kvmhid.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package kvmhid
  2. import (
  3. "fmt"
  4. "log"
  5. "time"
  6. "github.com/tarm/serial"
  7. )
  8. func NewHIDController(config *Config) *Controller {
  9. // Initialize the HID state with default values
  10. defaultHidState := HIDState{
  11. Modkey: 0x00,
  12. KeyboardButtons: [6]uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  13. Leds: 0x00,
  14. MouseButtons: 0x00, // No mouse buttons pressed
  15. MouseX: 0,
  16. MouseY: 0,
  17. }
  18. return &Controller{
  19. Config: config,
  20. serialRunning: false,
  21. hidState: defaultHidState,
  22. writeQueue: make(chan []byte, 32),
  23. incomingDataQueue: make(chan []byte, 1024),
  24. readCloseChan: make(chan bool),
  25. }
  26. }
  27. // Connect opens the serial port and starts reading from it
  28. func (c *Controller) Connect() error {
  29. // Open the serial port
  30. config := &serial.Config{
  31. Name: c.Config.PortName,
  32. Baud: c.Config.BaudRate,
  33. Size: 8,
  34. Parity: serial.ParityNone,
  35. ReadTimeout: time.Millisecond * 500,
  36. }
  37. port, err := serial.OpenPort(config)
  38. if err != nil {
  39. return err
  40. }
  41. c.serialPort = port
  42. // Start reading from the serial port
  43. go func() {
  44. buf := make([]byte, 1024)
  45. for {
  46. select {
  47. case <-c.readCloseChan:
  48. return
  49. default:
  50. n, err := port.Read(buf)
  51. if err != nil {
  52. continue
  53. }
  54. if n > 0 {
  55. c.incomingDataQueue <- buf[:n]
  56. }
  57. }
  58. }
  59. }()
  60. //Create a loop to write to the serial port
  61. c.serialRunning = true
  62. go func() {
  63. for {
  64. data := <-c.writeQueue
  65. _, err := port.Write(data)
  66. if err != nil {
  67. log.Println(err.Error())
  68. return
  69. }
  70. }
  71. }()
  72. //Send over an opr queue reset signal
  73. err = c.Send([]byte{0xFF})
  74. if err != nil {
  75. return err
  76. }
  77. return nil
  78. }
  79. func (c *Controller) Send(data []byte) error {
  80. if !c.serialRunning {
  81. return fmt.Errorf("serial port is not running")
  82. }
  83. select {
  84. case c.writeQueue <- data:
  85. return nil
  86. case <-time.After(30 * time.Millisecond):
  87. return fmt.Errorf("timeout waiting to send data")
  88. }
  89. }
  90. func (c *Controller) ClearReadQueue() {
  91. // Clear the incoming data queue
  92. for len(c.incomingDataQueue) > 0 {
  93. <-c.incomingDataQueue
  94. }
  95. }
  96. func (c *Controller) WaitForReply(cmdByte byte) ([]byte, error) {
  97. // Wait for a reply from the device
  98. succReplyByte := cmdByte | 0x80
  99. errorReplyByte := cmdByte | 0xC0
  100. timeout := make(chan bool, 1)
  101. go func() {
  102. // Timeout after 500ms
  103. time.Sleep(500 * time.Millisecond)
  104. timeout <- true
  105. }()
  106. var reply []byte
  107. for {
  108. select {
  109. case data := <-c.incomingDataQueue:
  110. reply = append(reply, data...)
  111. // Check if we have received enough bytes for a complete packet
  112. if len(reply) >= 7 {
  113. // Validate header
  114. if reply[0] == 0x57 && reply[1] == 0xAB {
  115. // Extract fields
  116. //address := reply[2]
  117. replyByte := reply[3]
  118. dataLength := reply[4]
  119. expectedLength := 5 + int(dataLength) + 1 // Header + address + replyByte + dataLength + data + checksum
  120. // Check if the full packet is received
  121. if len(reply) >= expectedLength {
  122. data := reply[5 : 5+dataLength]
  123. checksum := reply[5+dataLength]
  124. // Calculate checksum
  125. sum := byte(0)
  126. for _, b := range reply[:5+dataLength] {
  127. sum += b
  128. }
  129. // Validate checksum
  130. if sum == checksum {
  131. // Check reply byte for success or error
  132. switch replyByte {
  133. case succReplyByte:
  134. return data, nil
  135. case errorReplyByte:
  136. fmt.Print("Reply: ")
  137. for _, b := range reply {
  138. fmt.Printf("0x%02X ", b)
  139. }
  140. return nil, fmt.Errorf("device returned error reply")
  141. }
  142. } else {
  143. return nil, fmt.Errorf("checksum validation failed")
  144. }
  145. }
  146. } else {
  147. // Invalid header, discard data
  148. reply = nil
  149. }
  150. }
  151. case <-timeout:
  152. return nil, fmt.Errorf("timeout waiting for reply")
  153. }
  154. }
  155. }
  156. func (c *Controller) Close() {
  157. c.serialRunning = false
  158. c.readCloseChan <- true
  159. if c.serialPort != nil {
  160. done := make(chan struct{})
  161. go func() {
  162. c.serialPort.Close()
  163. close(done)
  164. }()
  165. select {
  166. case <-done:
  167. // Closed successfully
  168. case <-time.After(3 * time.Second):
  169. log.Println("serial port close timeout")
  170. }
  171. }
  172. }