1use std::time::Duration;
54use crate::fb::{RTrig, FTrig, Ton};
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62#[repr(u8)]
63pub enum Animation {
64 Off = 0,
65 Steady = 1,
66 Flash = 2,
67 TwoColorFlash = 3,
68 TwoColorShift = 4,
69 EndsSteady = 5,
70 EndsFlash = 6,
71 Scroll = 7,
72 CenterScroll = 8,
73 Bounce = 9,
74 CenterBounce = 10,
75 IntensitySweep = 11,
77 TwoColorSweep = 12,
78 Spectrum = 13,
80 SingleEndSteady = 14,
81 SingleEndFlash = 15,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86#[repr(u8)]
87pub enum Color {
88 Green = 0,
89 Red = 1,
90 Orange = 2,
91 Amber = 3,
92 Yellow = 4,
93 LimeGreen = 5,
94 SpringGreen = 6,
95 Cyan = 7,
96 SkyBlue = 8,
97 Blue = 9,
98 Violet = 10,
99 Magenta = 11,
100 Rose = 12,
101 DaylightWhite = 13,
102 Custom1 = 14,
103 Custom2 = 15,
104 IncandescentWhite = 16,
105 WarmWhite = 17,
106 FluorescentWhite = 18,
107 NeutralWhite = 19,
108 CoolWhite = 20,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113#[repr(u8)]
114pub enum ColorIntensity {
115 High = 0,
116 Low = 1,
117 Medium = 2,
118 Off = 3,
119 Custom = 4,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124#[repr(u8)]
125pub enum Direction {
126 Up = 0,
127 Down = 1,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132#[repr(u8)]
133pub enum PulsePattern {
134 Normal = 0,
135 Strobe = 1,
136 ThreePulse = 2,
137 Sos = 3,
138 Random = 4,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143#[repr(u8)]
144pub enum ScrollStyle {
145 Solid = 0,
146 Tail = 1,
147 Ripple = 2,
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152#[repr(u8)]
153pub enum Speed {
154 Medium = 0,
155 Fast = 1,
156 Slow = 2,
157 CustomFlashRate = 3,
158}
159
160#[derive(Debug, Clone)]
171pub struct Wls15RunMode {
172 pub animation: u8,
174 pub color1: u8,
176 pub color1_intensity: u8,
178 pub color2: u8,
180 pub color2_intensity: u8,
182 pub speed: u8,
184 pub pulse_pattern: u8,
186 pub scroll_bounce_style: u8,
188 pub percent_width_color1: u8,
190 pub direction: u8,
192}
193
194impl Wls15RunMode {
195 pub fn new() -> Self {
197 Self {
198 animation: 0,
199 color1: 0,
200 color1_intensity: 0,
201 color2: 0,
202 color2_intensity: 0,
203 speed: 0,
204 pulse_pattern: 0,
205 scroll_bounce_style: 0,
206 percent_width_color1: 0,
207 direction: 0,
208 }
209 }
210
211 pub fn off(&mut self) {
213 self.animation = Animation::Off as u8;
214 }
215
216 pub fn alert(&mut self, color: Color, intensity: ColorIntensity, speed: Speed) {
221 self.color1 = color as u8;
222 self.speed = speed as u8;
223 self.color1_intensity = intensity as u8;
224 self.color2_intensity = ColorIntensity::Off as u8;
225 self.percent_width_color1 = 0;
226 self.animation = Animation::CenterScroll as u8;
227 }
228
229 pub fn knight_rider(&mut self, color: Color) {
234 self.color2 = Color::WarmWhite as u8;
235 self.scroll_bounce_style = ScrollStyle::Tail as u8;
236 self.color2_intensity = ColorIntensity::Off as u8;
237 self.percent_width_color1 = 40;
238 self.color1 = color as u8;
239 self.color1_intensity = ColorIntensity::High as u8;
240 self.speed = Speed::Medium as u8;
241 self.animation = Animation::Bounce as u8;
242 }
243
244 pub fn pulse(&mut self, color: Color, intensity: ColorIntensity, speed: Speed) {
248 self.color1 = color as u8;
249 self.speed = speed as u8;
250 self.color1_intensity = intensity as u8;
251 self.color2_intensity = ColorIntensity::Off as u8;
252 self.percent_width_color1 = 0;
253 self.animation = Animation::TwoColorSweep as u8;
254 }
255
256 pub fn spectrum(&mut self, speed: Speed) {
260 self.animation = Animation::Spectrum as u8;
261 self.speed = speed as u8;
262 self.percent_width_color1 = 0;
263 }
264
265 pub fn steady(&mut self, color: Color, intensity: ColorIntensity) {
267 self.color1 = color as u8;
268 self.color1_intensity = intensity as u8;
269 self.animation = Animation::Steady as u8;
270 }
271
272 pub fn flash(&mut self, color: Color, intensity: ColorIntensity, speed: Speed) {
274 self.color1 = color as u8;
275 self.color1_intensity = intensity as u8;
276 self.speed = speed as u8;
277 self.animation = Animation::Flash as u8;
278 }
279
280 pub fn apply(&self, view: &mut crate::banner::wls15_view::Wls15RunModeView<'_>) {
286 *view.animation = self.animation;
287 *view.color1 = self.color1;
288 *view.color1_intensity = self.color1_intensity;
289 *view.speed = self.speed;
290 *view.pulse_pattern = self.pulse_pattern;
291 *view.color2 = self.color2;
292 *view.color2_intensity = self.color2_intensity;
293 *view.scroll_bounce_style = self.scroll_bounce_style;
294 *view.percent_width_color1 = self.percent_width_color1;
295 *view.direction = self.direction;
296 }
297}
298
299impl Default for Wls15RunMode {
300 fn default() -> Self {
301 Self::new()
302 }
303}
304
305#[derive(Debug, Clone)]
323pub struct Wls15Digital {
324 pub q1: bool,
326 pub q2: bool,
328
329 req_q1: bool,
330 req_q2: bool,
331 enable_blink: bool,
332 blink_time: Duration,
333 blink_timer: Ton,
334 blink_bit: bool,
335 rt_blink: RTrig,
336 ft_blink: FTrig,
337}
338
339impl Wls15Digital {
340 pub fn new() -> Self {
342 Self {
343 q1: false,
344 q2: false,
345 req_q1: false,
346 req_q2: false,
347 enable_blink: false,
348 blink_time: Duration::from_secs(1),
349 blink_timer: Ton::new(),
350 blink_bit: false,
351 rt_blink: RTrig::new(),
352 ft_blink: FTrig::new(),
353 }
354 }
355
356 pub fn off(&mut self) {
358 self.req_q1 = false;
359 self.req_q2 = false;
360 }
361
362 pub fn red(&mut self) {
364 self.req_q1 = true;
365 self.req_q2 = false;
366 }
367
368 pub fn green(&mut self) {
370 self.req_q1 = false;
371 self.req_q2 = true;
372 }
373
374 pub fn blue(&mut self) {
376 self.req_q1 = true;
377 self.req_q2 = true;
378 }
379
380 pub fn blink_on(&mut self, interval: Duration) {
382 self.enable_blink = true;
383 self.blink_time = interval;
384 }
385
386 pub fn blink_off(&mut self) {
388 self.enable_blink = false;
389 }
390
391 pub fn call(&mut self) {
397 if self.blink_timer.call(true, self.blink_time) {
399 self.blink_bit = !self.blink_bit;
400 self.blink_timer.reset();
401 }
402
403 let rising = self.rt_blink.call(self.blink_bit);
404 let falling = self.ft_blink.call(self.blink_bit);
405
406 if self.enable_blink {
407 if rising {
408 self.q1 = self.req_q1;
409 self.q2 = self.req_q2;
410 }
411 if falling {
412 self.q1 = false;
413 self.q2 = false;
414 }
415 } else {
416 self.q1 = self.req_q1;
417 self.q2 = self.req_q2;
418 }
419 }
420}
421
422impl Default for Wls15Digital {
423 fn default() -> Self {
424 Self::new()
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 fn test_run_mode_off() {
434 let mut light = Wls15RunMode::new();
435 light.steady(Color::Red, ColorIntensity::High);
436 assert_eq!(light.animation, Animation::Steady as u8);
437 light.off();
438 assert_eq!(light.animation, Animation::Off as u8);
439 }
440
441 #[test]
442 fn test_run_mode_alert() {
443 let mut light = Wls15RunMode::new();
444 light.alert(Color::Red, ColorIntensity::High, Speed::Medium);
445 assert_eq!(light.animation, Animation::CenterScroll as u8);
446 assert_eq!(light.color1, Color::Red as u8);
447 assert_eq!(light.color1_intensity, ColorIntensity::High as u8);
448 assert_eq!(light.color2_intensity, ColorIntensity::Off as u8);
449 }
450
451 #[test]
452 fn test_run_mode_knight_rider() {
453 let mut light = Wls15RunMode::new();
454 light.knight_rider(Color::Red);
455 assert_eq!(light.animation, Animation::Bounce as u8);
456 assert_eq!(light.scroll_bounce_style, ScrollStyle::Tail as u8);
457 assert_eq!(light.color1, Color::Red as u8);
458 assert_eq!(light.percent_width_color1, 40);
459 }
460
461 #[test]
462 fn test_run_mode_pulse() {
463 let mut light = Wls15RunMode::new();
464 light.pulse(Color::Green, ColorIntensity::High, Speed::Slow);
465 assert_eq!(light.animation, Animation::TwoColorSweep as u8);
466 assert_eq!(light.color1, Color::Green as u8);
467 assert_eq!(light.speed, Speed::Slow as u8);
468 }
469
470 #[test]
471 fn test_run_mode_spectrum() {
472 let mut light = Wls15RunMode::new();
473 light.spectrum(Speed::Fast);
474 assert_eq!(light.animation, Animation::Spectrum as u8);
475 assert_eq!(light.speed, Speed::Fast as u8);
476 }
477
478 #[test]
479 fn test_digital_colors() {
480 let mut light = Wls15Digital::new();
481
482 light.red();
483 light.call();
484 assert_eq!((light.q1, light.q2), (true, false));
485
486 light.green();
487 light.call();
488 assert_eq!((light.q1, light.q2), (false, true));
489
490 light.blue();
491 light.call();
492 assert_eq!((light.q1, light.q2), (true, true));
493
494 light.off();
495 light.call();
496 assert_eq!((light.q1, light.q2), (false, false));
497 }
498
499 #[test]
500 fn test_digital_blink_off_tracks_color() {
501 let mut light = Wls15Digital::new();
502 light.red();
503 light.blink_off();
504 light.call();
505 assert_eq!((light.q1, light.q2), (true, false));
506 }
507
508 #[test]
509 fn test_enum_values() {
510 assert_eq!(Animation::Off as u8, 0);
511 assert_eq!(Animation::Spectrum as u8, 13);
512 assert_eq!(Color::Green as u8, 0);
513 assert_eq!(Color::Red as u8, 1);
514 assert_eq!(Color::CoolWhite as u8, 20);
515 assert_eq!(ColorIntensity::High as u8, 0);
516 assert_eq!(ColorIntensity::Off as u8, 3);
517 assert_eq!(Direction::Up as u8, 0);
518 assert_eq!(Direction::Down as u8, 1);
519 assert_eq!(PulsePattern::Sos as u8, 3);
520 assert_eq!(ScrollStyle::Tail as u8, 1);
521 assert_eq!(Speed::Fast as u8, 1);
522 }
523}