1#![no_std]
2
3pub mod effect;
4pub(crate) mod effects;
5pub mod prelude;
6pub mod segment;
7pub mod utils;
8
9use heapless::Vec;
10use smart_leds_trait::RGB8;
11
12use crate::effect::Effect;
13use crate::segment::{Segment, SegmentOptions};
14
15const MAX_SEGMENTS: usize = 10;
16
17pub struct StripFx<const N: usize> {
24 pixels: [RGB8; N],
25 segments: Vec<Segment, MAX_SEGMENTS>,
26 brightness: u8,
27 running: bool,
28 triggered: bool,
29}
30
31impl<const N: usize> StripFx<N> {
32 pub fn new(brightness: u8) -> Self {
35 let mut fx = Self {
36 pixels: [RGB8 { r: 0, g: 0, b: 0 }; N],
37 segments: Vec::new(),
38 brightness,
39 running: true,
40 triggered: false,
41 };
42 let _ = fx.segments.push(Segment::new(0, N - 1, Effect::Static));
43 fx
44 }
45
46 pub fn start(&mut self) {
48 self.running = true;
49 }
50
51 pub fn stop(&mut self) {
53 self.running = false;
54 self.clear();
55 }
56
57 pub fn pause(&mut self) {
59 self.running = false;
60 }
61
62 pub fn resume(&mut self) {
64 self.running = true;
65 }
66
67 pub fn trigger(&mut self) {
70 self.triggered = true;
71 }
72
73 pub fn is_running(&self) -> bool {
74 self.running
75 }
76
77 pub fn is_triggered(&self) -> bool {
78 self.triggered
79 }
80
81 pub fn clear(&mut self) {
83 for p in self.pixels.iter_mut() {
84 *p = RGB8 { r: 0, g: 0, b: 0 };
85 }
86 }
87
88 pub fn service(&mut self, now_ms: u64) -> bool {
93 if !self.running && !self.triggered {
94 return false;
95 }
96 let force = self.triggered;
97 self.triggered = false;
98
99 let mut updated = false;
100 for i in 0..self.segments.len() {
101 let elapsed = now_ms.wrapping_sub(self.segments[i].last_update);
102 if force || elapsed >= self.segments[i].config.speed as u64 {
103 let start = self.segments[i].start;
104 let stop = self.segments[i].stop;
105 let effect = self.segments[i].effect;
106 let config = self.segments[i].config;
107 let mut state = self.segments[i].state;
108
109 let end = (stop + 1).min(N);
110 effect.render(&mut self.pixels[start..end], &mut state, &config);
111
112 self.segments[i].state = state;
113 self.segments[i].last_update = now_ms;
114 updated = true;
115 }
116 }
117 updated
118 }
119
120 pub fn iter(&self) -> impl Iterator<Item = RGB8> + '_ {
123 let brightness = self.brightness;
124 self.pixels.iter().map(move |c| RGB8 {
125 r: (c.r as u16 * brightness as u16 / 255) as u8,
126 g: (c.g as u16 * brightness as u16 / 255) as u8,
127 b: (c.b as u16 * brightness as u16 / 255) as u8,
128 })
129 }
130
131 pub fn set_brightness(&mut self, brightness: u8) {
132 self.brightness = brightness;
133 }
134
135 pub fn get_brightness(&self) -> u8 {
136 self.brightness
137 }
138
139 pub fn increase_brightness(&mut self, amount: u8) {
140 self.brightness = self.brightness.saturating_add(amount);
141 }
142
143 pub fn decrease_brightness(&mut self, amount: u8) {
144 self.brightness = self.brightness.saturating_sub(amount);
145 }
146
147 pub fn intensity_sum(&self) -> u32 {
150 self.iter()
151 .map(|c| c.r as u32 + c.g as u32 + c.b as u32)
152 .sum()
153 }
154
155 pub fn add_segment(&mut self, segment: Segment) -> Result<(), Segment> {
157 self.segments.push(segment).map_err(|s| s)
158 }
159
160 pub fn set_segment(&mut self, idx: usize, segment: Segment) -> bool {
164 if let Some(slot) = self.segments.get_mut(idx) {
165 *slot = segment;
166 true
167 } else if idx == self.segments.len() {
168 self.segments.push(segment).is_ok()
169 } else {
170 false
171 }
172 }
173
174 pub fn reset_segments(&mut self) {
176 self.segments.clear();
177 let _ = self.segments.push(Segment::new(0, N - 1, Effect::Static));
178 }
179
180 pub fn reset_segment(&mut self, idx: usize) {
182 if let Some(seg) = self.segments.get_mut(idx) {
183 seg.state = Default::default();
184 seg.last_update = 0;
185 }
186 }
187
188 pub fn segment_count(&self) -> usize {
189 self.segments.len()
190 }
191
192 pub fn get_segment(&self, idx: usize) -> Option<&Segment> {
193 self.segments.get(idx)
194 }
195
196 pub fn get_segment_mut(&mut self, idx: usize) -> Option<&mut Segment> {
197 self.segments.get_mut(idx)
198 }
199
200 pub fn set_effect(&mut self, idx: usize, effect: Effect) {
202 if let Some(seg) = self.segments.get_mut(idx) {
203 seg.effect = effect;
204 seg.state = Default::default();
205 }
206 }
207
208 pub fn get_effect(&self, idx: usize) -> Option<Effect> {
209 self.segments.get(idx).map(|s| s.effect)
210 }
211
212 pub fn set_speed(&mut self, idx: usize, speed: u16) {
213 if let Some(seg) = self.segments.get_mut(idx) {
214 seg.config.speed = speed;
215 }
216 }
217
218 pub fn get_speed(&self, idx: usize) -> Option<u16> {
219 self.segments.get(idx).map(|s| s.config.speed)
220 }
221
222 pub fn faster(&mut self, idx: usize, amount: u16) {
224 if let Some(seg) = self.segments.get_mut(idx) {
225 seg.config.speed = seg.config.speed.saturating_sub(amount);
226 }
227 }
228
229 pub fn slower(&mut self, idx: usize, amount: u16) {
231 if let Some(seg) = self.segments.get_mut(idx) {
232 seg.config.speed = seg.config.speed.saturating_add(amount);
233 }
234 }
235
236 pub fn set_color(&mut self, idx: usize, color: RGB8) {
238 if let Some(seg) = self.segments.get_mut(idx) {
239 seg.config.colors[0] = color;
240 }
241 }
242
243 pub fn get_color(&self, idx: usize) -> Option<RGB8> {
244 self.segments.get(idx).map(|s| s.config.colors[0])
245 }
246
247 pub fn set_colors(&mut self, idx: usize, colors: [RGB8; 3]) {
249 if let Some(seg) = self.segments.get_mut(idx) {
250 seg.config.colors = colors;
251 }
252 }
253
254 pub fn get_colors(&self, idx: usize) -> Option<[RGB8; 3]> {
255 self.segments.get(idx).map(|s| s.config.colors)
256 }
257
258 pub fn set_options(&mut self, idx: usize, options: SegmentOptions) {
259 if let Some(seg) = self.segments.get_mut(idx) {
260 seg.options = options;
261 }
262 }
263
264 pub fn get_options(&self, idx: usize) -> Option<SegmentOptions> {
265 self.segments.get(idx).map(|s| s.options)
266 }
267
268 pub fn set_random_seed(&mut self, seed: u32) {
270 for seg in self.segments.iter_mut() {
271 seg.state.aux = seed;
272 }
273 }
274
275 pub fn mode_count() -> usize {
277 Effect::count()
278 }
279
280 pub fn mode_name(effect: Effect) -> &'static str {
282 effect.name()
283 }
284}