main.go 3.2 KB

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