main.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package main
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "log"
  6. "os"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/chzyer/readline"
  11. "github.com/zserge/hid"
  12. )
  13. func shell(device hid.Device, inputReportSize int) {
  14. if err := device.Open(); err != nil {
  15. log.Println("Open error: ", err)
  16. return
  17. }
  18. defer device.Close()
  19. if report, err := device.HIDReport(); err != nil {
  20. log.Println("HID report error:", err)
  21. return
  22. } else {
  23. log.Println("HID report", hex.EncodeToString(report))
  24. }
  25. go func() {
  26. for {
  27. if buf, err := device.Read(inputReportSize, 1*time.Second); err == nil {
  28. log.Println("Input report: ", hex.EncodeToString(buf))
  29. }
  30. }
  31. }()
  32. commands := map[string]func([]byte){
  33. "output": func(b []byte) {
  34. if len(b) == 0 {
  35. log.Println("Invalid input: output report data expected")
  36. } else if n, err := device.Write(b, 1*time.Second); err != nil {
  37. log.Println("Output report write failed:", err)
  38. } else {
  39. log.Printf("Output report: written %d bytes\n", n)
  40. }
  41. },
  42. "set-feature": func(b []byte) {
  43. if len(b) == 0 {
  44. log.Println("Invalid input: feature report data expected")
  45. } else if err := device.SetReport(0, b); err != nil {
  46. log.Println("Feature report write failed:", err)
  47. } else {
  48. log.Printf("Feature report: " + hex.EncodeToString(b) + "\n")
  49. }
  50. },
  51. "get-feature": func(b []byte) {
  52. if b, err := device.GetReport(0); err != nil {
  53. log.Println("Feature report read failed:", err)
  54. } else {
  55. log.Println("Feature report: " + hex.EncodeToString(b) + "\n")
  56. }
  57. },
  58. }
  59. var completer = readline.NewPrefixCompleter(
  60. readline.PcItem("output"),
  61. readline.PcItem("set-feature"),
  62. readline.PcItem("get-feature"),
  63. )
  64. rl, err := readline.NewEx(&readline.Config{
  65. Prompt: "> ",
  66. AutoComplete: completer,
  67. })
  68. if err != nil {
  69. panic(err)
  70. }
  71. defer rl.Close()
  72. log.SetOutput(rl.Stderr())
  73. out:
  74. for {
  75. line, err := rl.Readline()
  76. if err != nil {
  77. break
  78. }
  79. line = strings.ToLower(line)
  80. for cmd, f := range commands {
  81. if strings.HasPrefix(line, cmd) {
  82. line = strings.TrimSpace(line[len(cmd):])
  83. raw := []byte{}
  84. if len(line) > 0 {
  85. raw = make([]byte, len(line)/2, len(line)/2)
  86. if _, err := hex.Decode(raw, []byte(line)); err != nil {
  87. log.Println("Invalid input:", err)
  88. log.Println(">>", hex.EncodeToString(raw))
  89. continue out
  90. }
  91. }
  92. f(raw)
  93. continue out
  94. }
  95. }
  96. }
  97. }
  98. func main() {
  99. if len(os.Args) == 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
  100. fmt.Println("USAGE:")
  101. fmt.Printf(" %s list USB HID devices\n", os.Args[0])
  102. fmt.Printf(" %s <id> [size] open USB HID device shell for the given input report size\n", os.Args[0])
  103. fmt.Printf(" %s -h|--help show this help\n", os.Args[0])
  104. fmt.Println()
  105. return
  106. }
  107. // Without arguments - enumerate all HID devices
  108. if len(os.Args) == 1 {
  109. found := false
  110. hid.UsbWalk(func(device hid.Device) {
  111. info := device.Info()
  112. fmt.Printf("%04x:%04x:%04x\n", info.Vendor, info.Product, info.Revision)
  113. found = true
  114. })
  115. if !found {
  116. fmt.Println("No USB HID devices found\n")
  117. }
  118. return
  119. }
  120. inputReportSize := 1
  121. if len(os.Args) > 2 {
  122. if n, err := strconv.Atoi(os.Args[2]); err == nil {
  123. inputReportSize = n
  124. } else {
  125. log.Fatal(err)
  126. }
  127. }
  128. hid.UsbWalk(func(device hid.Device) {
  129. info := device.Info()
  130. id := fmt.Sprintf("%04x:%04x:%04x", info.Vendor, info.Product, info.Revision)
  131. if id != os.Args[1] {
  132. return
  133. }
  134. shell(device, inputReportSize)
  135. })
  136. }