main.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package main
  2. import (
  3. "encoding/binary"
  4. "encoding/hex"
  5. "fmt"
  6. "log"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/chzyer/readline"
  11. "github.com/zserge/hid"
  12. )
  13. //output: 550301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037c3
  14. //input : 550301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037c3
  15. var cur_cmd string
  16. var cmdList map[string][]byte
  17. var tmrCmdTimeout *time.Timer = nil
  18. var chnMain chan string
  19. func init() {
  20. cmdList = map[string][]byte{
  21. "read": []byte{0x55, 0x03, 0x01, 0x00},
  22. "config": []byte{0x55, 0x01, 0x07, 0x00},
  23. "config2": []byte{0x55, 0x01, 0x09, 0x00},
  24. "query": []byte{0x55, 0x01, 0x02, 0x00}, //QUERY NAME
  25. "dump": []byte{0x55, 0x01, 0x0b, 0x00},
  26. "clean": []byte{0x55, 0x01, 0x05, 0x00},
  27. }
  28. }
  29. func sendcmd(device hid.Device, strcmd string) error {
  30. log.Println("send cmd : ", strcmd)
  31. cmd := cmdList[strcmd]
  32. cmdbuf := make([]byte, 64)
  33. copy(cmdbuf[0:4], cmd[0:4])
  34. crc := CheckSum(cmdbuf[0:62])
  35. cmdbuf[63] = byte(crc >> 8)
  36. cmdbuf[62] = byte(crc)
  37. log.Println("output:", hex.EncodeToString(cmdbuf))
  38. cur_cmd = strcmd
  39. if _, err := device.Write(cmdbuf, 1*time.Second); err != nil {
  40. log.Println("Output report write failed:", err)
  41. return err
  42. }
  43. return nil
  44. }
  45. func resetCmdTimer() {
  46. if tmrCmdTimeout != nil {
  47. tmrCmdTimeout.Stop()
  48. tmrCmdTimeout.Reset(3 * time.Second)
  49. }
  50. }
  51. func shell(device hid.Device) {
  52. if err := device.Open(); err != nil {
  53. log.Println("Open error: ", err)
  54. return
  55. }
  56. defer device.Close()
  57. if report, err := device.HIDReport(); err != nil {
  58. log.Println("HID report error:", err)
  59. return
  60. } else {
  61. log.Println("HID report", hex.EncodeToString(report))
  62. }
  63. chnMain = make(chan string, 20)
  64. tmrCmdTimeout = time.NewTimer(time.Second)
  65. defer tmrCmdTimeout.Stop()
  66. num_total := 0
  67. num_read := 0
  68. go func() {
  69. for {
  70. if buf, err := device.Read(-1, 1*time.Second); err == nil {
  71. log.Println("Input report: ", hex.EncodeToString(buf))
  72. resetCmdTimer()
  73. switch cur_cmd {
  74. case "read":
  75. FmtPrintBinary(buf)
  76. temp := binary.BigEndian.Uint16(buf[23:25])
  77. humidity := binary.BigEndian.Uint16(buf[25:27])
  78. log.Printf("%d, %d\n", temp, humidity)
  79. chnMain <- cur_cmd
  80. case "query": // aa3b020000861c5553422d5448000000555342e6b8a9e6b9bfe5baa6e8aeb0e5bd95e4bbaa000000000000000000000000000000000000000000000000006223
  81. num_total = int(buf[6])
  82. log.Println(num_total)
  83. chnMain <- cur_cmd
  84. case "dump":
  85. if buf[2] == 2 {
  86. num_total = int(buf[6])
  87. log.Println(num_total)
  88. // aa 3a 03 07 6150d959 00f3 02c4; 6150d97700f302c16150d99500f302be6150d9b300f302be6150d9d100f202bd6150d9ef00f302c46150da0d00f202c200001f77
  89. } else if buf[2] == 3 { //aa 3a 03 07; 61509ee4 00f9 02aa; 61509f2000fa02aa61509f5c00fa02aa61509f9800fa02ab61509fd400f902ab6150a01000f902aa6150a04c00f802ac00002ee6
  90. items := int(buf[3])
  91. for i := 0; i < items; i++ {
  92. pos := i*8 + 4
  93. ts := binary.BigEndian.Uint32(buf[pos:pos+4]) - 8*3600
  94. temp := binary.BigEndian.Uint16(buf[pos+4 : pos+6])
  95. humidity := binary.BigEndian.Uint16(buf[pos+6 : pos+8])
  96. if ts > 1632760878 {
  97. ReportTelemty(ts, temp, humidity)
  98. }
  99. num_read++
  100. }
  101. if items < 7 {
  102. log.Printf("Total recived :%d\n", num_read)
  103. chnMain <- cur_cmd
  104. }
  105. }
  106. default:
  107. log.Println(cur_cmd + " skipped")
  108. chnMain <- cur_cmd
  109. }
  110. }
  111. }
  112. }()
  113. var completer = readline.NewPrefixCompleter(
  114. readline.PcItem("output"),
  115. readline.PcItem("set-feature"),
  116. readline.PcItem("get-feature"),
  117. )
  118. rl, err := readline.NewEx(&readline.Config{
  119. Prompt: "> ",
  120. AutoComplete: completer,
  121. })
  122. if err != nil {
  123. panic(err)
  124. }
  125. defer rl.Close()
  126. log.SetOutput(rl.Stderr())
  127. //sendcmd(device, "read")
  128. cmds := []string{
  129. "read",
  130. "config",
  131. "config2",
  132. "query",
  133. "dump",
  134. }
  135. timeout := 0
  136. for _, k := range cmds {
  137. sendcmd(device, k)
  138. tmrCmdTimeout.Stop()
  139. tmrCmdTimeout.Reset(3 * time.Second)
  140. select {
  141. case msg := <-chnMain:
  142. log.Println("Send command [", k, "<>", msg, "] done!")
  143. case <-tmrCmdTimeout.C:
  144. log.Println("Send command [", k, "] timeout!")
  145. timeout = 1
  146. }
  147. if timeout != 0 {
  148. break
  149. }
  150. }
  151. time.Sleep(1 * time.Second)
  152. log.Printf("\nConfirm to clean all record data in device? [Yes/no]:")
  153. if timeout == 0 && num_read > 0 && num_read == num_total {
  154. line, err := rl.Readline()
  155. if err == nil {
  156. line = strings.ToLower(line)
  157. switch line {
  158. case "yes", "y":
  159. sendcmd(device, "clean")
  160. tmrCmdTimeout.Stop()
  161. tmrCmdTimeout.Reset(3 * time.Second)
  162. select {
  163. case <-chnMain:
  164. case <-tmrCmdTimeout.C:
  165. log.Println("Send command [clean] timeout!")
  166. }
  167. default:
  168. log.Println("Skip clean device")
  169. }
  170. }
  171. }
  172. }
  173. func main() {
  174. if len(os.Args) == 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
  175. fmt.Println("USAGE:")
  176. fmt.Printf(" %s list USB HID devices\n", os.Args[0])
  177. fmt.Printf(" %s <id> open USB HID device shell for the given input report size\n", os.Args[0])
  178. fmt.Printf(" %s -h|--help show this help\n", os.Args[0])
  179. fmt.Println()
  180. return
  181. }
  182. // Without arguments - enumerate all HID devices
  183. if len(os.Args) == 1 {
  184. found := false
  185. hid.UsbWalk(func(device hid.Device) {
  186. info := device.Info()
  187. fmt.Printf("%04x:%04x:%04x:%02x\n", info.Vendor, info.Product, info.Revision, info.Interface)
  188. found = true
  189. })
  190. if !found {
  191. fmt.Println("No USB HID devices found\n")
  192. }
  193. return
  194. }
  195. hid.UsbWalk(func(device hid.Device) {
  196. info := device.Info()
  197. id := fmt.Sprintf("%04x:%04x:%04x:%02x", info.Vendor, info.Product, info.Revision, info.Interface)
  198. if id != os.Args[1] {
  199. return
  200. }
  201. StartMqttServer()
  202. shell(device)
  203. StopMqttServer()
  204. })
  205. }