channel.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  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. // LightingChannels lists the QMK lighting channels in channel order, which is
  30. // the order the tool reports them in.
  31. var LightingChannels = []Channel{ChannelBacklight, ChannelRgblight, ChannelRgbMatrix, ChannelAudio, ChannelLedMatrix}
  32. func (c Channel) Subsystem() string {
  33. switch c {
  34. case ChannelBacklight:
  35. return "backlight"
  36. case ChannelRgblight:
  37. return "rgblight"
  38. case ChannelRgbMatrix:
  39. return "rgb_matrix"
  40. case ChannelAudio:
  41. return "audio"
  42. case ChannelLedMatrix:
  43. return "led_matrix"
  44. default:
  45. return ""
  46. }
  47. }
  48. // DetectChannels asks the keyboard which lighting channels it has, in ascending
  49. // order.
  50. //
  51. // The 0xFF answer is the discriminator, not the payload: QMK rejects a channel
  52. // it does not compile in with id_unhandled, whereas an unknown value ID on a
  53. // known channel is mirrored back with a zero payload. A read that fails for any
  54. // other reason aborts the probe, because a channel list missing entries is
  55. // indistinguishable from a complete one and would silently under-report.
  56. func (p *Protocol) DetectChannels() ([]Channel, error) {
  57. var present []Channel
  58. for c := Channel(1); c <= probeChannelMax; c++ {
  59. if _, err := p.GetValue(c, probeValueID); err != nil {
  60. if errors.Is(err, errUnhandled) {
  61. continue
  62. }
  63. return nil, fmt.Errorf("probe channel %d: %w", c, err)
  64. }
  65. present = append(present, c)
  66. }
  67. return present, nil
  68. }