package tunergenius import ( "bufio" "fmt" "net" "strings" "time" . "git.rouggy.com/rouggy/ShackMaster/internal/devices" ) type Client struct { host string port int conn net.Conn } type Status struct { Operate bool `json:"operate"` // true = OPERATE, false = STANDBY Bypass bool `json:"bypass"` // Bypass mode ActiveAntenna int `json:"active_antenna"` // 0=ANT1, 1=ANT2, 2=ANT3 TuningStatus string `json:"tuning_status"` FrequencyA float64 `json:"frequency_a"` FrequencyB float64 `json:"frequency_b"` C1 int `json:"c1"` L int `json:"l"` C2 int `json:"c2"` SWR float64 `json:"swr"` Power float64 `json:"power"` Temperature float64 `json:"temperature"` Connected bool `json:"connected"` } func New(host string, port int) *Client { return &Client{ host: host, port: port, } } func (c *Client) Connect() error { conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", c.host, c.port), 5*time.Second) if err != nil { return fmt.Errorf("failed to connect: %w", err) } c.conn = conn return nil } func (c *Client) Close() error { if c.conn != nil { return c.conn.Close() } return nil } func (c *Client) sendCommand(cmd string) (string, error) { if c.conn == nil { if err := c.Connect(); err != nil { return "", err } } // Get next command ID from global counter cmdID := GetGlobalCommandID().GetNextID() // Format command with ID: C| fullCmd := fmt.Sprintf("C%d|%s\n", cmdID, cmd) // Send command _, err := c.conn.Write([]byte(fullCmd)) if err != nil { c.conn = nil return "", fmt.Errorf("failed to send command: %w", err) } // Read response reader := bufio.NewReader(c.conn) response, err := reader.ReadString('\n') if err != nil { c.conn = nil return "", fmt.Errorf("failed to read response: %w", err) } return strings.TrimSpace(response), nil } func (c *Client) GetStatus() (*Status, error) { resp, err := c.sendCommand("status") if err != nil { return nil, err } // Parse the response - format will depend on actual device response // This is a placeholder that should be updated based on real response format status := &Status{ Connected: true, } // TODO: Parse actual status response from device // The response format needs to be determined from real device testing // For now, we just check if we got a response _ = resp // Temporary: will be used when we parse the actual response format return status, nil } func (c *Client) SetOperate(operate bool) error { var state int if operate { state = 1 } cmd := fmt.Sprintf("operate set=%d", state) resp, err := c.sendCommand(cmd) if err != nil { return err } // Check if command was successful if resp == "" { return fmt.Errorf("empty response from device") } return nil } func (c *Client) SetBypass(bypass bool) error { var state int if bypass { state = 1 } cmd := fmt.Sprintf("bypass set=%d", state) resp, err := c.sendCommand(cmd) if err != nil { return err } // Check if command was successful if resp == "" { return fmt.Errorf("empty response from device") } return nil } func (c *Client) ActivateAntenna(antenna int) error { if antenna < 0 || antenna > 2 { return fmt.Errorf("antenna must be 0 (ANT1), 1 (ANT2), or 2 (ANT3)") } cmd := fmt.Sprintf("activate ant=%d", antenna) resp, err := c.sendCommand(cmd) if err != nil { return err } // Check if command was successful if resp == "" { return fmt.Errorf("empty response from device") } return nil } func (c *Client) AutoTune() error { resp, err := c.sendCommand("autotune") if err != nil { return err } // Check if command was successful if resp == "" { return fmt.Errorf("empty response from device") } return nil } // TuneRelay adjusts tuning parameters manually // relay: 0=C1, 1=L, 2=C2 // move: -1 to decrease, 1 to increase func (c *Client) TuneRelay(relay int, move int) error { if relay < 0 || relay > 2 { return fmt.Errorf("relay must be 0 (C1), 1 (L), or 2 (C2)") } if move != -1 && move != 1 { return fmt.Errorf("move must be -1 or 1") } cmd := fmt.Sprintf("tune relay=%d move=%d", relay, move) resp, err := c.sendCommand(cmd) if err != nil { return err } // Check if command was successful if resp == "" { return fmt.Errorf("empty response from device") } return nil }