channel.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package via
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. // Channel is a VIA lighting channel. The values are QMK's id_qmk_*_channel
  7. // constants from quantum/via.h.
  8. type Channel uint8
  9. const (
  10. ChannelBacklight Channel = 1
  11. ChannelRgblight Channel = 2
  12. ChannelRgbMatrix Channel = 3
  13. ChannelAudio Channel = 4
  14. ChannelLedMatrix Channel = 5
  15. )
  16. // AssignedChannelMax is the highest channel QMK currently assigns. The probe
  17. // asks beyond it on purpose, see probeChannelMax.
  18. const AssignedChannelMax = ChannelLedMatrix
  19. // probeChannelMax is the highest channel the probe asks about. The QMK enum
  20. // stops at 5; the extra reads cost one round trip each and let a future QMK
  21. // that claims a higher channel be found without a code change.
  22. const probeChannelMax = 15
  23. // probeValueID is the brightness value ID. It is one byte and valid on every
  24. // lighting subsystem, so one request per channel finds any kind of channel.
  25. const probeValueID = 0x01
  26. // Subsystem returns the QMK name of the channel's lighting subsystem. The name
  27. // follows from the channel number, so no board file stores it and it is always
  28. // available for a channel the keyboard has.
  29. func (c Channel) Subsystem() string {
  30. switch c {
  31. case ChannelBacklight:
  32. return "backlight"
  33. case ChannelRgblight:
  34. return "rgblight"
  35. case ChannelRgbMatrix:
  36. return "rgb_matrix"
  37. case ChannelAudio:
  38. return "audio"
  39. case ChannelLedMatrix:
  40. return "led_matrix"
  41. default:
  42. return ""
  43. }
  44. }
  45. // DetectChannels asks the keyboard which lighting channels it has, in ascending
  46. // order.
  47. //
  48. // The 0xFF answer is the discriminator, not the payload: QMK rejects a channel
  49. // it does not compile in with id_unhandled, whereas an unknown value ID on a
  50. // known channel is mirrored back with a zero payload. A read that fails for any
  51. // other reason aborts the probe, because a channel list missing entries is
  52. // indistinguishable from a complete one and would silently under-report.
  53. func (p *Protocol) DetectChannels() ([]Channel, error) {
  54. var present []Channel
  55. for c := Channel(1); c <= probeChannelMax; c++ {
  56. if _, err := p.GetValue(c, probeValueID); err != nil {
  57. if errors.Is(err, errUnhandled) {
  58. continue
  59. }
  60. return nil, fmt.Errorf("probe channel %d: %w", c, err)
  61. }
  62. present = append(present, c)
  63. }
  64. return present, nil
  65. }