package remdeshid import ( "fmt" "log" "time" "github.com/tarm/serial" ) func NewHIDController(config *Config) *Controller { // Initialize the HID state with default values defaultHidState := HIDState{ Modkey: 0x00, KeyboardButtons: [6]uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, Leds: 0x00, MouseButtons: 0x00, // No mouse buttons pressed MouseX: 0, MouseY: 0, } return &Controller{ Config: config, serialRunning: false, hidState: defaultHidState, writeQueue: make(chan []byte, 32), incomgDataQueue: make(chan []byte, 1024), } } // Connect opens the serial port and starts reading from it func (c *Controller) Connect() error { // Open the serial port config := &serial.Config{ Name: c.Config.PortName, Baud: c.Config.BaudRate, Size: 8, Parity: serial.ParityNone, } port, err := serial.OpenPort(config) if err != nil { return err } c.serialPort = port //Start reading from the serial port go func() { buf := make([]byte, 1024) for { n, err := port.Read(buf) if err != nil { log.Println(err.Error()) return } if n > 0 { c.incomgDataQueue <- buf[:n] //fmt.Print("Received bytes: ") //for i := 0; i < n; i++ { // fmt.Printf("0x%02X ", buf[i]) //} fmt.Println() } } }() //Create a loop to write to the serial port c.serialRunning = true go func() { for { data := <-c.writeQueue _, err := port.Write(data) if err != nil { log.Println(err.Error()) return } } }() //Send over an opr queue reset signal err = c.Send([]byte{0xFF}) if err != nil { return err } return nil } func (c *Controller) Send(data []byte) error { if !c.serialRunning { return fmt.Errorf("serial port is not running") } select { case c.writeQueue <- data: return nil case <-time.After(30 * time.Millisecond): return fmt.Errorf("timeout waiting to send data") } } func (c *Controller) ClearReadQueue() { // Clear the incoming data queue for len(c.incomgDataQueue) > 0 { <-c.incomgDataQueue } } func (c *Controller) WaitForReply(cmdByte byte) ([]byte, error) { // Wait for a reply from the device succReplyByte := cmdByte | 0x80 errorReplyByte := cmdByte | 0xC0 timeout := make(chan bool, 1) go func() { // Timeout after 500ms time.Sleep(500 * time.Millisecond) timeout <- true }() var reply []byte for { select { case data := <-c.incomgDataQueue: reply = append(reply, data...) // Check if we have received enough bytes for a complete packet if len(reply) >= 7 { // Validate header if reply[0] == 0x57 && reply[1] == 0xAB { // Extract fields //address := reply[2] replyByte := reply[3] dataLength := reply[4] expectedLength := 5 + int(dataLength) + 1 // Header + address + replyByte + dataLength + data + checksum // Check if the full packet is received if len(reply) >= expectedLength { data := reply[5 : 5+dataLength] checksum := reply[5+dataLength] // Calculate checksum sum := byte(0) for _, b := range reply[:5+dataLength] { sum += b } // Validate checksum if sum == checksum { // Check reply byte for success or error switch replyByte { case succReplyByte: return data, nil case errorReplyByte: return nil, fmt.Errorf("device returned error reply") } } else { return nil, fmt.Errorf("checksum validation failed") } } } else { // Invalid header, discard data reply = nil } } case <-timeout: return nil, fmt.Errorf("timeout waiting for reply") } } } func (c *Controller) Close() { if c.serialPort != nil { c.serialPort.Close() } }