update
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// Package pst sends commands to PstRotator over its UDP listener.
|
||||
//
|
||||
// PstRotator (Codrut Buda YO3DMU) exposes a simple text/XML protocol on
|
||||
// a configurable UDP port (default 12000 on localhost). Each command is a
|
||||
// single fire-and-forget datagram — no handshake, no response. This keeps
|
||||
// us connectionless and means a misconfigured port silently no-ops rather
|
||||
// than hanging the UI. Run the matching "Test" action to confirm the link.
|
||||
package pst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client is a stateless UDP sender. Safe to construct cheaply per call —
|
||||
// the underlying socket only lives for the length of one Write.
|
||||
type Client struct {
|
||||
Host string // hostname or IP of the PstRotator host (usually "127.0.0.1")
|
||||
Port int // UDP port (PstRotator default = 12000)
|
||||
}
|
||||
|
||||
// New returns a Client with sane defaults applied for empty fields.
|
||||
func New(host string, port int) *Client {
|
||||
if host == "" {
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
if port <= 0 || port > 65535 {
|
||||
port = 12000
|
||||
}
|
||||
return &Client{Host: host, Port: port}
|
||||
}
|
||||
|
||||
// GoTo points the antenna at azimuth (0-359°). If hasElevation is true
|
||||
// and el >= 0 the elevation field is included too (VHF/satellite setups);
|
||||
// otherwise PstRotator just turns in azimuth.
|
||||
func (c *Client) GoTo(az int, hasElevation bool, el int) error {
|
||||
az = ((az % 360) + 360) % 360 // normalise to [0,360)
|
||||
if hasElevation && el >= 0 && el <= 180 {
|
||||
return c.send(fmt.Sprintf("<PST><AZIMUTH>%d</AZIMUTH><ELEVATION>%d</ELEVATION></PST>", az, el))
|
||||
}
|
||||
return c.send(fmt.Sprintf("<PST><AZIMUTH>%d</AZIMUTH></PST>", az))
|
||||
}
|
||||
|
||||
// Stop interrupts any in-progress rotation.
|
||||
func (c *Client) Stop() error {
|
||||
return c.send("<PST><STOP>1</STOP></PST>")
|
||||
}
|
||||
|
||||
// Park sends the rotator to its parked position (configured inside
|
||||
// PstRotator itself — we just trigger it).
|
||||
func (c *Client) Park() error {
|
||||
return c.send("<PST><PARK>1</PARK></PST>")
|
||||
}
|
||||
|
||||
func (c *Client) send(payload string) error {
|
||||
addr := fmt.Sprintf("%s:%d", c.Host, c.Port)
|
||||
conn, err := net.DialTimeout("udp", addr, 2*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dial PstRotator at %s: %w", addr, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
_ = conn.SetWriteDeadline(time.Now().Add(2 * time.Second))
|
||||
if _, err := conn.Write([]byte(payload)); err != nil {
|
||||
return fmt.Errorf("send to PstRotator: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user