main.go 6.2 KB

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