impact80.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package rgb
  2. import "fmt"
  3. type Zone string
  4. const (
  5. ZoneLogo Zone = "logo"
  6. ZoneBacklight Zone = "backlight"
  7. ZoneSide Zone = "side"
  8. )
  9. type EffectTarget struct {
  10. Zone Zone
  11. ID uint8
  12. }
  13. var impact80BacklightEffects = [...]string{
  14. "none",
  15. "solid_color",
  16. "alphas_mods",
  17. "gradient_up_down",
  18. "gradient_left_right",
  19. "breathing",
  20. "band_sat",
  21. "band_val",
  22. "band_pinwheel_sat",
  23. "band_pinwheel_val",
  24. "band_spiral_sat",
  25. "band_spiral_val",
  26. "cycle_all",
  27. "cycle_left_right",
  28. "cycle_up_down",
  29. "cycle_out_in",
  30. "cycle_out_in_dual",
  31. "rainbow_moving_chevron",
  32. "cycle_pinwheel",
  33. "cycle_spiral",
  34. "dual_beacon",
  35. "rainbow_beacon",
  36. "rainbow_pinwheels",
  37. "flower_blooming",
  38. "raindrops",
  39. "jellybean_raindrops",
  40. "hue_breathing",
  41. "hue_pendulum",
  42. "hue_wave",
  43. "pixel_flow",
  44. "digital_rain",
  45. "solid_reactive",
  46. "solid_reactive_wide",
  47. "solid_reactive_multiwide",
  48. "solid_reactive_cross",
  49. "solid_reactive_multicross",
  50. "solid_reactive_nexus",
  51. "solid_reactive_multinexus",
  52. "splash",
  53. "multisplash",
  54. "solid_splash",
  55. "solid_multisplash",
  56. "starlight",
  57. "starlight_dual_hue",
  58. "starlight_dual_sat",
  59. "riverflow",
  60. }
  61. var impact80LogoEffects = [...]string{
  62. "none",
  63. "wave",
  64. "fixed_wave",
  65. "spectrum",
  66. "breathing",
  67. "light",
  68. "shutdown",
  69. }
  70. var impact80SideEffects = [...]string{
  71. "none",
  72. "wave",
  73. "fixed_wave",
  74. "spectrum",
  75. "breathing",
  76. "light",
  77. "shutdown",
  78. }
  79. var impact80EffectAliases = map[Zone]map[string]string{
  80. ZoneLogo: {
  81. "off": "none",
  82. "breathe": "breathing",
  83. "rainbow": "spectrum",
  84. "rainbow_wave": "wave",
  85. "solid": "light",
  86. },
  87. ZoneBacklight: {
  88. "off": "none",
  89. "breathe": "breathing",
  90. "rainbow": "rainbow_moving_chevron",
  91. "solid": "solid_color",
  92. },
  93. ZoneSide: {
  94. "off": "none",
  95. "breathe": "breathing",
  96. "rainbow": "spectrum",
  97. "rainbow_wave": "wave",
  98. "solid": "light",
  99. },
  100. }
  101. func AllZones() []Zone {
  102. return []Zone{ZoneLogo, ZoneBacklight, ZoneSide}
  103. }
  104. func ParseZone(value string) (Zone, error) {
  105. zone := Zone(value)
  106. switch zone {
  107. case ZoneLogo, ZoneBacklight, ZoneSide:
  108. return zone, nil
  109. default:
  110. return "", fmt.Errorf("unknown zone: %s", value)
  111. }
  112. }
  113. func (z Zone) Channel() uint8 {
  114. switch z {
  115. case ZoneLogo:
  116. return 2
  117. case ZoneBacklight:
  118. return 3
  119. case ZoneSide:
  120. return 4
  121. default:
  122. return 0
  123. }
  124. }
  125. func EffectName(zone Zone, id uint8) string {
  126. names := impact80EffectNames(zone)
  127. if int(id) >= len(names) {
  128. return "unknown"
  129. }
  130. return names[id]
  131. }
  132. func DefaultEffect(zone Zone) uint8 {
  133. switch zone {
  134. case ZoneLogo, ZoneSide:
  135. return 4
  136. case ZoneBacklight:
  137. return 5
  138. default:
  139. return 0
  140. }
  141. }
  142. func ResolveEffect(name string, zones []Zone) ([]EffectTarget, []Zone, error) {
  143. for _, zone := range zones {
  144. if impact80EffectNames(zone) == nil {
  145. return nil, nil, fmt.Errorf("unknown zone: %s", zone)
  146. }
  147. }
  148. known := false
  149. for _, zone := range AllZones() {
  150. if _, ok := resolveEffectID(zone, name); ok {
  151. known = true
  152. break
  153. }
  154. }
  155. if !known {
  156. return nil, nil, fmt.Errorf("unknown effect: %s", name)
  157. }
  158. explicit := len(zones) == 1
  159. var targets []EffectTarget
  160. var skipped []Zone
  161. for _, zone := range zones {
  162. id, ok := resolveEffectID(zone, name)
  163. if !ok {
  164. if explicit {
  165. return nil, nil, fmt.Errorf("effect %s is not supported on zone %s", name, zone)
  166. }
  167. skipped = append(skipped, zone)
  168. continue
  169. }
  170. targets = append(targets, EffectTarget{Zone: zone, ID: id})
  171. }
  172. return targets, skipped, nil
  173. }
  174. func impact80EffectNames(zone Zone) []string {
  175. switch zone {
  176. case ZoneLogo:
  177. return impact80LogoEffects[:]
  178. case ZoneBacklight:
  179. return impact80BacklightEffects[:]
  180. case ZoneSide:
  181. return impact80SideEffects[:]
  182. default:
  183. return nil
  184. }
  185. }
  186. func resolveEffectID(zone Zone, name string) (uint8, bool) {
  187. for id, effectName := range impact80EffectNames(zone) {
  188. if effectName == name {
  189. return uint8(id), true
  190. }
  191. }
  192. if canonical, ok := impact80EffectAliases[zone][name]; ok {
  193. return resolveEffectID(zone, canonical)
  194. }
  195. return 0, false
  196. }
  197. func Impact80EffectName(value uint8) string {
  198. return EffectName(ZoneLogo, value)
  199. }
  200. func ParseImpact80Effect(name string) (uint8, error) {
  201. targets, _, err := ResolveEffect(name, []Zone{ZoneLogo})
  202. if err != nil {
  203. return 0, err
  204. }
  205. return targets[0].ID, nil
  206. }