1use std::{error::Error, ops::BitOr, str::FromStr};
2
3use crate::gpio_bits;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub(crate) struct ColorBits {
7 pub(crate) r1: u32,
8 pub(crate) g1: u32,
9 pub(crate) b1: u32,
10 pub(crate) r2: u32,
11 pub(crate) g2: u32,
12 pub(crate) b2: u32,
13}
14
15impl ColorBits {
16 pub const fn unused() -> Self {
17 Self {
18 r1: 0,
19 g1: 0,
20 b1: 0,
21 r2: 0,
22 g2: 0,
23 b2: 0,
24 }
25 }
26
27 pub(crate) fn used_bits(&self) -> u32 {
28 self.r1 | self.r2 | self.g1 | self.g2 | self.b1 | self.b2
29 }
30
31 fn red_bits(&self) -> u32 {
32 self.r1 | self.r2
33 }
34
35 fn green_bits(&self) -> u32 {
36 self.g1 | self.g2
37 }
38
39 fn blue_bits(&self) -> u32 {
40 self.b1 | self.b2
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub(crate) struct Panels {
46 pub(crate) color_bits: [ColorBits; 6],
47}
48
49impl Panels {
50 pub(crate) fn used_bits(&self) -> u32 {
51 self.red_bits() | self.green_bits() | self.blue_bits()
52 }
53
54 pub(crate) fn red_bits(&self) -> u32 {
55 self.color_bits
56 .iter()
57 .map(ColorBits::red_bits)
58 .fold(0, BitOr::bitor)
59 }
60
61 pub(crate) fn green_bits(&self) -> u32 {
62 self.color_bits
63 .iter()
64 .map(ColorBits::green_bits)
65 .fold(0, BitOr::bitor)
66 }
67
68 pub(crate) fn blue_bits(&self) -> u32 {
69 self.color_bits
70 .iter()
71 .map(ColorBits::blue_bits)
72 .fold(0, BitOr::bitor)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub struct HardwareMapping {
78 pub(crate) output_enable: u32,
79 pub(crate) clock: u32,
80 pub(crate) strobe: u32,
81
82 pub(crate) a: u32,
83 pub(crate) b: u32,
84 pub(crate) c: u32,
85 pub(crate) d: u32,
86 pub(crate) e: u32,
87
88 pub(crate) panels: Panels,
89}
90
91impl FromStr for HardwareMapping {
92 type Err = Box<dyn Error>;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 match s {
96 "AdafruitHat" => Ok(Self::adafruit_hat()),
97 "AdafruitHatPwm" => Ok(Self::adafruit_hat_pwm()),
98 "Regular" => Ok(Self::regular()),
99 "RegularPi1" => Ok(Self::regular_pi1()),
100 "Classic" => Ok(Self::classic()),
101 "ClassicPi1" => Ok(Self::classic_pi1()),
102 _ => Err(format!("'{s}' is not a valid GPIO mapping.").into()),
103 }
104 }
105}
106
107impl HardwareMapping {
108 pub(crate) fn used_bits(&self) -> u32 {
109 self.output_enable | self.clock | self.strobe | self.panels.used_bits()
110 }
111
112 pub(crate) fn get_color_clock_mask(&self, parallel: usize) -> u32 {
114 let mut color_clk_mask: u32 = 0;
115 (0..6).for_each(|panel| {
116 if parallel > panel {
117 color_clk_mask |= &self.panels.color_bits[panel].used_bits();
118 }
119 });
120 color_clk_mask |= self.clock;
121 color_clk_mask
122 }
123
124 pub(crate) fn max_parallel_chains(&self) -> usize {
125 self.panels
126 .color_bits
127 .iter()
128 .filter(|p| p.used_bits() > 0)
129 .count()
130 }
131}
132
133impl HardwareMapping {
134 #[must_use]
136 pub const fn regular() -> Self {
137 Self {
138 output_enable: gpio_bits!(18),
139 clock: gpio_bits!(17),
140 strobe: gpio_bits!(4),
141
142 a: gpio_bits!(22),
143 b: gpio_bits!(23),
144 c: gpio_bits!(24),
145 d: gpio_bits!(25),
146 e: gpio_bits!(15), panels: Panels {
149 color_bits: [
150 ColorBits {
152 r1: gpio_bits!(11), g1: gpio_bits!(27), b1: gpio_bits!(7), r2: gpio_bits!(8), g2: gpio_bits!(9), b2: gpio_bits!(10), },
159 ColorBits {
162 r1: gpio_bits!(12),
163 g1: gpio_bits!(5),
164 b1: gpio_bits!(6),
165 r2: gpio_bits!(19),
166 g2: gpio_bits!(13),
167 b2: gpio_bits!(20),
168 },
169 ColorBits {
171 r1: gpio_bits!(14), g1: gpio_bits!(2), b1: gpio_bits!(3), r2: gpio_bits!(26),
175 g2: gpio_bits!(16),
176 b2: gpio_bits!(21),
177 },
178 ColorBits::unused(),
179 ColorBits::unused(),
180 ColorBits::unused(),
181 ],
182 },
183 }
184 }
185
186 #[must_use]
188 pub const fn adafruit_hat() -> Self {
189 Self {
190 output_enable: gpio_bits!(4),
191 clock: gpio_bits!(17),
192 strobe: gpio_bits!(21),
193
194 a: gpio_bits!(22),
195 b: gpio_bits!(26),
196 c: gpio_bits!(27),
197 d: gpio_bits!(20),
198 e: gpio_bits!(24), panels: Panels {
201 color_bits: [
202 ColorBits {
203 r1: gpio_bits!(5),
204 g1: gpio_bits!(13),
205 b1: gpio_bits!(6),
206 r2: gpio_bits!(12),
207 g2: gpio_bits!(16),
208 b2: gpio_bits!(23),
209 },
210 ColorBits::unused(),
211 ColorBits::unused(),
212 ColorBits::unused(),
213 ColorBits::unused(),
214 ColorBits::unused(),
215 ],
216 },
217 }
218 }
219
220 #[must_use]
222 pub const fn adafruit_hat_pwm() -> Self {
223 Self {
224 output_enable: gpio_bits!(18),
225 ..Self::adafruit_hat()
226 }
227 }
228
229 #[must_use]
232 pub const fn regular_pi1() -> Self {
233 Self {
234 output_enable: gpio_bits!(18),
235 clock: gpio_bits!(17),
236 strobe: gpio_bits!(4),
237
238 a: gpio_bits!(22),
239 b: gpio_bits!(23),
240 c: gpio_bits!(24),
241 d: gpio_bits!(25),
242 e: gpio_bits!(15), panels: Panels {
246 color_bits: [
247 ColorBits {
248 r1: gpio_bits!(15, 27),
251 g1: gpio_bits!(21),
252 b1: gpio_bits!(7), r2: gpio_bits!(8), g2: gpio_bits!(9), b2: gpio_bits!(10), },
257 ColorBits::unused(),
259 ColorBits::unused(),
260 ColorBits::unused(),
261 ColorBits::unused(),
262 ColorBits::unused(),
263 ],
264 },
265 }
266 }
267
268 #[must_use]
271 pub const fn classic() -> Self {
272 Self {
273 output_enable: gpio_bits!(27), clock: gpio_bits!(11),
275 strobe: gpio_bits!(4),
276
277 a: gpio_bits!(7),
278 b: gpio_bits!(8),
279 c: gpio_bits!(9),
280 d: gpio_bits!(10),
281 e: 0,
282
283 panels: Panels {
284 color_bits: [
285 ColorBits {
286 r1: gpio_bits!(17),
287 g1: gpio_bits!(18),
288 b1: gpio_bits!(22),
289 r2: gpio_bits!(23),
290 g2: gpio_bits!(24),
291 b2: gpio_bits!(25),
292 },
293 ColorBits {
294 r1: gpio_bits!(12),
295 g1: gpio_bits!(5),
296 b1: gpio_bits!(6),
297 r2: gpio_bits!(19),
298 g2: gpio_bits!(13),
299 b2: gpio_bits!(20),
300 },
301 ColorBits {
302 r1: gpio_bits!(14), g1: gpio_bits!(2), b1: gpio_bits!(3), r2: gpio_bits!(15),
306 g2: gpio_bits!(26),
307 b2: gpio_bits!(21),
308 },
309 ColorBits::unused(),
310 ColorBits::unused(),
311 ColorBits::unused(),
312 ],
313 },
314 }
315 }
316
317 #[must_use]
319 pub const fn classic_pi1() -> Self {
320 Self {
321 output_enable: gpio_bits!(0, 2),
324 clock: gpio_bits!(1, 3),
325 strobe: gpio_bits!(4),
326
327 a: gpio_bits!(7),
328 b: gpio_bits!(8),
329 c: gpio_bits!(9),
330 d: gpio_bits!(10),
331 e: 0,
332
333 panels: Panels {
334 color_bits: [
335 ColorBits {
336 r1: gpio_bits!(17),
337 g1: gpio_bits!(18),
338 b1: gpio_bits!(22),
339 r2: gpio_bits!(23),
340 g2: gpio_bits!(24),
341 b2: gpio_bits!(25),
342 },
343 ColorBits::unused(),
344 ColorBits::unused(),
345 ColorBits::unused(),
346 ColorBits::unused(),
347 ColorBits::unused(),
348 ],
349 },
350 }
351 }
352}