1#![cfg_attr(
2 feature = "doc-images",
3 doc = ::embed_doc_image::embed_image!(
4 "led_strip_simple",
5 "docs/assets/led_strip_simple.png"
6 ),
7 doc = ::embed_doc_image::embed_image!(
8 "led_strip_gpio0",
9 "docs/assets/led_strip_gpio0.png"
10 ),
11 doc = ::embed_doc_image::embed_image!(
12 "led_strip_gogo",
13 "docs/assets/led2d2.png"
14 ),
15 doc = ::embed_doc_image::embed_image!(
16 "led_strip_animated",
17 "docs/assets/led_strip_animated.png"
18 )
19)]
20#[doc(inline)]
146pub use smart_leds::RGB8;
147
148#[doc(inline)]
159pub use smart_leds::colors;
160
161#[doc(inline)]
173pub use embedded_graphics::pixelcolor::Rgb888;
174
175pub trait ToRgb8 {
194 #[must_use]
198 fn to_rgb8(self) -> RGB8;
199}
200
201impl ToRgb8 for RGB8 {
202 #[inline(always)]
203 fn to_rgb8(self) -> RGB8 {
204 self
205 }
206}
207
208impl ToRgb8 for Rgb888 {
209 #[inline(always)]
210 fn to_rgb8(self) -> RGB8 {
211 RGB8::new(self.r(), self.g(), self.b())
212 }
213}
214
215pub trait ToRgb888 {
234 #[must_use]
238 fn to_rgb888(self) -> Rgb888;
239}
240
241impl ToRgb888 for RGB8 {
242 #[inline(always)]
243 fn to_rgb888(self) -> Rgb888 {
244 Rgb888::new(self.r, self.g, self.b)
245 }
246}
247
248impl ToRgb888 for Rgb888 {
249 #[inline(always)]
250 fn to_rgb888(self) -> Rgb888 {
251 self
252 }
253}
254
255#[cfg(not(feature = "host"))]
256use core::borrow::Borrow;
257use core::ops::{Deref, DerefMut};
258use embedded_graphics::prelude::RgbColor;
259
260#[derive(Clone, Copy, Debug, Eq, PartialEq)]
274pub enum Gamma {
275 Linear,
277 Srgb,
281 SmartLeds,
283}
284
285impl Default for Gamma {
286 fn default() -> Self {
287 Self::Srgb
288 }
289}
290
291#[doc(hidden)]
293pub const GAMMA_DEFAULT: Gamma = Gamma::Srgb;
295
296pub(crate) const GAMMA_SRGB_TABLE: [u8; 256] = [
299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
300 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11,
301 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23,
302 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39,
303 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
304 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 87, 88,
305 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 116,
306 117, 119, 120, 121, 123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 141, 143, 145,
307 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166, 168, 170, 172, 173, 175, 177,
308 179, 181, 182, 184, 186, 188, 190, 192, 194, 196, 197, 199, 201, 203, 205, 207, 209, 211, 213,
309 215, 217, 219, 221, 223, 225, 227, 229, 231, 234, 236, 238, 240, 242, 244, 246, 248, 251, 253,
310 255,
311];
312
313pub(crate) const GAMMA_SMARTLEDS_TABLE: [u8; 256] = [
316 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
317 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
318 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14,
319 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27,
320 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46,
321 47, 48, 49, 50, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 70, 72,
322 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, 90, 92, 93, 95, 96, 98, 99, 101, 102, 104,
323 105, 107, 109, 110, 112, 114, 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137,
324 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
325 177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218, 220,
326 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255,
327];
328
329const LINEAR_TABLE: [u8; 256] = [
331 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
332 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
333 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
334 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
335 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
336 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
337 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
338 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
339 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
340 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
341 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
342 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
343 250, 251, 252, 253, 254, 255,
344];
345
346#[doc(hidden)] #[must_use]
355pub const fn generate_combo_table(gamma: Gamma, max_brightness: u8) -> [u8; 256] {
356 let gamma_table = match gamma {
357 Gamma::Linear => &LINEAR_TABLE,
358 Gamma::Srgb => &GAMMA_SRGB_TABLE,
359 Gamma::SmartLeds => &GAMMA_SMARTLEDS_TABLE,
360 };
361 let mut result = [0u8; 256];
362 let mut index = 0;
363 while index < 256 {
364 let gamma_corrected = gamma_table[index];
365 let scaled = ((gamma_corrected as u16 * max_brightness as u16) / 255) as u8;
367 result[index] = scaled;
368 index += 1;
369 }
370 result
371}
372
373#[cfg(not(feature = "host"))]
374use core::cell::RefCell;
375#[cfg(not(feature = "host"))]
376use embassy_futures::select::{Either, select};
377#[cfg(not(feature = "host"))]
378use embassy_rp::pio::{Common, Instance};
379#[cfg(not(feature = "host"))]
380use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program};
381#[cfg(not(feature = "host"))]
382use embassy_sync::blocking_mutex::Mutex;
383#[cfg(not(feature = "host"))]
384use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
385#[cfg(not(feature = "host"))]
386#[cfg(not(feature = "host"))]
387use embassy_sync::once_lock::OnceLock;
388#[cfg(not(feature = "host"))]
389use embassy_sync::signal::Signal;
390#[cfg(not(feature = "host"))]
391use embassy_time::{Duration, Timer};
392#[cfg(not(feature = "host"))]
393use heapless::Vec;
394
395#[cfg(not(feature = "host"))]
396use crate::Result;
397
398pub mod led_strip_generated;
403
404#[derive(Clone, Copy, Debug)]
410pub struct Frame1d<const N: usize>(pub [RGB8; N]);
411
412impl<const N: usize> Frame1d<N> {
413 pub const LEN: usize = N;
415
416 #[must_use]
420 pub const fn new() -> Self {
421 Self([RGB8::new(0, 0, 0); N])
422 }
423
424 #[must_use]
428 pub const fn filled(color: RGB8) -> Self {
429 Self([color; N])
430 }
431}
432
433impl<const N: usize> Deref for Frame1d<N> {
434 type Target = [RGB8; N];
435
436 fn deref(&self) -> &Self::Target {
437 &self.0
438 }
439}
440
441impl<const N: usize> DerefMut for Frame1d<N> {
442 fn deref_mut(&mut self) -> &mut Self::Target {
443 &mut self.0
444 }
445}
446
447impl<const N: usize> From<[RGB8; N]> for Frame1d<N> {
448 fn from(array: [RGB8; N]) -> Self {
449 Self(array)
450 }
451}
452
453impl<const N: usize> From<Frame1d<N>> for [RGB8; N] {
454 fn from(frame: Frame1d<N>) -> Self {
455 frame.0
456 }
457}
458
459impl<const N: usize> Default for Frame1d<N> {
460 fn default() -> Self {
461 Self::new()
462 }
463}
464
465#[cfg(not(feature = "host"))]
474#[doc(hidden)] pub trait LedStripPio: crate::pio_irqs::PioIrqMap {}
476
477#[cfg(not(feature = "host"))]
478impl<PioResource: crate::pio_irqs::PioIrqMap> LedStripPio for PioResource {}
479#[cfg(not(feature = "host"))]
483#[doc(hidden)] pub struct PioBusStateMachine<PIO: Instance + 'static, const SM: usize> {
485 pio_bus: &'static PioBus<'static, PIO>,
486 state_machine: embassy_rp::pio::StateMachine<'static, PIO, SM>,
487}
488
489#[cfg(not(feature = "host"))]
490impl<PIO: Instance + 'static, const SM: usize> PioBusStateMachine<PIO, SM> {
491 #[doc(hidden)]
492 pub fn new(
493 pio_bus: &'static PioBus<'static, PIO>,
494 state_machine: embassy_rp::pio::StateMachine<'static, PIO, SM>,
495 ) -> Self {
496 Self {
497 pio_bus,
498 state_machine,
499 }
500 }
501
502 #[doc(hidden)]
503 pub fn pio_bus(&self) -> &'static PioBus<'static, PIO> {
504 self.pio_bus
505 }
506
507 #[doc(hidden)]
508 pub fn into_parts(
509 self,
510 ) -> (
511 &'static PioBus<'static, PIO>,
512 embassy_rp::pio::StateMachine<'static, PIO, SM>,
513 ) {
514 (self.pio_bus, self.state_machine)
515 }
516}
517
518#[cfg(not(feature = "host"))]
520#[doc(hidden)] pub struct PioBus<'d, PIO: Instance> {
522 common: Mutex<CriticalSectionRawMutex, RefCell<Common<'d, PIO>>>,
523 ws2812_program: OnceLock<PioWs2812Program<'d, PIO>>,
524}
525
526#[cfg(not(feature = "host"))]
527impl<'d, PIO: Instance> PioBus<'d, PIO> {
528 pub fn new(common: Common<'d, PIO>) -> Self {
530 Self {
531 common: Mutex::new(RefCell::new(common)),
532 ws2812_program: OnceLock::new(),
533 }
534 }
535
536 pub fn get_program(&'static self) -> &'static PioWs2812Program<'d, PIO> {
538 self.ws2812_program.get_or_init(|| {
539 self.common.lock(|common_cell: &RefCell<Common<'d, PIO>>| {
540 let mut common = common_cell.borrow_mut();
541 PioWs2812Program::new(&mut *common)
542 })
543 })
544 }
545
546 pub fn with_common<F, R>(&self, f: F) -> R
548 where
549 F: FnOnce(&mut Common<'d, PIO>) -> R,
550 {
551 self.common.lock(|common_cell: &RefCell<Common<'d, PIO>>| {
552 let mut common = common_cell.borrow_mut();
553 f(&mut *common)
554 })
555 }
556}
557
558#[cfg(not(feature = "host"))]
563#[cfg(not(feature = "host"))]
564#[doc(hidden)] pub type LedStripCommandSignal<const N: usize, const MAX_FRAMES: usize> =
566 Signal<CriticalSectionRawMutex, Command<N, MAX_FRAMES>>;
567
568#[cfg(not(feature = "host"))]
569#[cfg(not(feature = "host"))]
570#[doc(hidden)]
571#[derive(Clone)]
573pub enum Command<const N: usize, const MAX_FRAMES: usize> {
574 DisplayStatic(Frame1d<N>),
575 Animate(Vec<(Frame1d<N>, Duration), MAX_FRAMES>),
576}
577
578#[cfg(not(feature = "host"))]
580#[doc(hidden)] pub struct LedStripStatic<const N: usize, const MAX_FRAMES: usize> {
582 command_signal: LedStripCommandSignal<N, MAX_FRAMES>,
583}
584
585#[cfg(not(feature = "host"))]
586impl<const N: usize, const MAX_FRAMES: usize> LedStripStatic<N, MAX_FRAMES> {
587 #[must_use]
589 #[doc(hidden)]
590 pub const fn new_static() -> Self {
591 Self {
592 command_signal: Signal::new(),
593 }
594 }
595
596 #[doc(hidden)]
597 pub fn command_signal(&'static self) -> &'static LedStripCommandSignal<N, MAX_FRAMES> {
598 &self.command_signal
599 }
600}
601
602#[cfg(not(feature = "host"))]
604#[doc(hidden)]
605pub struct LedStrip<const N: usize, const MAX_FRAMES: usize> {
610 command_signal: &'static LedStripCommandSignal<N, MAX_FRAMES>,
611}
612
613#[cfg(not(feature = "host"))]
614impl<const N: usize, const MAX_FRAMES: usize> LedStrip<N, MAX_FRAMES> {
615 #[must_use]
617 #[doc(hidden)]
618 pub const fn new_static() -> LedStripStatic<N, MAX_FRAMES> {
619 LedStripStatic::new_static()
620 }
621
622 pub fn new(led_strip_static: &'static LedStripStatic<N, MAX_FRAMES>) -> Result<Self> {
624 Ok(Self {
625 command_signal: led_strip_static.command_signal(),
626 })
627 }
628
629 pub fn write_frame(&self, frame: Frame1d<N>) -> Result<()> {
634 self.command_signal.signal(Command::DisplayStatic(frame));
635 Ok(())
636 }
637
638 pub fn animate<I>(&self, frames: I) -> Result<()>
649 where
650 I: IntoIterator,
651 I::Item: Borrow<(Frame1d<N>, Duration)>,
652 {
653 if MAX_FRAMES == 0 {
654 return Err(crate::Error::AnimationDisabled(MAX_FRAMES));
655 }
656 let mut sequence: Vec<(Frame1d<N>, Duration), MAX_FRAMES> = Vec::new();
657 for frame in frames {
658 let (frame, duration) = *frame.borrow();
659 assert!(
660 duration.as_micros() > 0,
661 "animation frame duration must be positive"
662 );
663 sequence
664 .push((frame, duration))
665 .expect("animation sequence fits within MAX_FRAMES");
666 }
667 self.animate_frames(sequence)
668 }
669
670 pub(crate) fn animate_frames(
671 &self,
672 sequence: Vec<(Frame1d<N>, Duration), MAX_FRAMES>,
673 ) -> Result<()> {
674 if MAX_FRAMES == 0 {
675 return Err(crate::Error::AnimationDisabled(MAX_FRAMES));
676 }
677 assert!(
678 !sequence.is_empty(),
679 "animation requires at least one frame"
680 );
681 self.command_signal.signal(Command::Animate(sequence));
682 Ok(())
683 }
684}
685
686#[cfg(not(feature = "host"))]
687#[doc(hidden)] pub async fn led_strip_device_loop<
689 PIO,
690 const SM: usize,
691 const N: usize,
692 const MAX_FRAMES: usize,
693 ORDER,
694>(
695 mut driver: PioWs2812<'static, PIO, SM, N, ORDER>,
696 command_signal: &'static LedStripCommandSignal<N, MAX_FRAMES>,
697 combo_table: &'static [u8; 256],
698) -> !
699where
700 PIO: Instance,
701 ORDER: embassy_rp::pio_programs::ws2812::RgbColorOrder,
702{
703 loop {
704 let mut command = command_signal.wait().await;
705 command_signal.reset();
706
707 loop {
708 match command {
709 Command::DisplayStatic(mut frame) => {
710 apply_correction(&mut frame, combo_table);
711 driver.write(&frame).await;
712 break;
713 }
714 Command::Animate(frames) => {
715 command =
716 run_frame_animation(&mut driver, frames, command_signal, combo_table).await;
717 }
718 }
719 }
720 }
721}
722
723#[cfg(not(feature = "host"))]
724async fn run_frame_animation<PIO, const SM: usize, const N: usize, const MAX_FRAMES: usize, ORDER>(
725 driver: &mut PioWs2812<'static, PIO, SM, N, ORDER>,
726 mut frames: Vec<(Frame1d<N>, Duration), MAX_FRAMES>,
727 command_signal: &'static LedStripCommandSignal<N, MAX_FRAMES>,
728 combo_table: &'static [u8; 256],
729) -> Command<N, MAX_FRAMES>
730where
731 PIO: Instance,
732 ORDER: embassy_rp::pio_programs::ws2812::RgbColorOrder,
733{
734 frames
735 .iter_mut()
736 .for_each(|(frame, _)| apply_correction(frame, combo_table));
737
738 loop {
739 for (frame, duration) in &frames {
740 driver.write(frame).await;
741
742 match select(command_signal.wait(), Timer::after(*duration)).await {
743 Either::First(new_command) => {
744 command_signal.reset();
745 return new_command;
746 }
747 Either::Second(()) => continue,
748 }
749 }
750 }
751}
752
753#[cfg(not(feature = "host"))]
754fn apply_correction<const N: usize>(frame: &mut Frame1d<N>, combo_table: &[u8; 256]) {
755 frame.iter_mut().for_each(|pixel| {
756 pixel.r = combo_table[pixel.r as usize];
757 pixel.g = combo_table[pixel.g as usize];
758 pixel.b = combo_table[pixel.b as usize];
759 });
760}
761#[doc = include_str!("docs/current_limiting_and_gamma.md")]
967#[cfg_attr(
973 feature = "doc-images",
974 doc = ::embed_doc_image::embed_image!(
975 "led_strip_gpio0",
976 "docs/assets/led_strip_gpio0.png"
977 )
978)]
979#[cfg_attr(
980 feature = "doc-images",
981 doc = ::embed_doc_image::embed_image!(
982 "led_strip_simple",
983 "docs/assets/led_strip_simple.png"
984 )
985)]
986#[cfg_attr(
987 feature = "doc-images",
988 doc = ::embed_doc_image::embed_image!(
989 "led_strip_gogo",
990 "docs/assets/led2d2.png"
991 )
992)]
993#[cfg(not(feature = "host"))]
994#[doc(hidden)]
995#[macro_export]
996macro_rules! led_strips {
997 ($($tt:tt)*) => { $crate::__led_strips_impl! { $($tt)* } };
998}
999
1000#[cfg(not(feature = "host"))]
1002#[doc(hidden)]
1003#[macro_export]
1004macro_rules! __led_strips_impl {
1005 (@__expand
1007 frame_alias: $frame_alias:tt,
1008 pio: $pio:ident,
1009 vis: $vis:vis,
1010 group: $group:ident,
1011 strips: [
1012 $(
1013 $label:ident {
1014 sm: $sm_index:expr,
1015 dma: $dma:ident,
1016 pin: $pin:ident,
1017 len: $len:expr,
1018 max_current: $max_current:expr,
1019 gamma: $gamma:expr,
1020 max_frames: $max_frames:expr
1021 $(,
1022 led2d: {
1023 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1024 $(max_frames: $led2d_max_frames:expr,)?
1025 font: $led2d_font:expr $(,)?
1026 }
1027 )?
1028 }
1029 ),+ $(,)?
1030 ]
1031 ) => {
1032 paste::paste! {
1034 #[allow(non_upper_case_globals)]
1036 static [<$pio _BUS>]: ::static_cell::StaticCell<
1037 $crate::led_strip::PioBus<'static, ::embassy_rp::peripherals::$pio>
1038 > = ::static_cell::StaticCell::new();
1039
1040 #[allow(dead_code)]
1044 pub fn [<$pio:lower _split>](
1045 pio: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pio>,
1046 ) -> (
1047 $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, 0>,
1048 $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, 1>,
1049 $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, 2>,
1050 $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, 3>,
1051 ) {
1052 let ::embassy_rp::pio::Pio { common, sm0, sm1, sm2, sm3, .. } =
1053 ::embassy_rp::pio::Pio::new(
1054 pio,
1055 <::embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
1056 );
1057 let pio_bus = [<$pio _BUS>].init_with(|| {
1058 $crate::led_strip::PioBus::new(common)
1059 });
1060 (
1061 $crate::led_strip::PioBusStateMachine::new(pio_bus, sm0),
1062 $crate::led_strip::PioBusStateMachine::new(pio_bus, sm1),
1063 $crate::led_strip::PioBusStateMachine::new(pio_bus, sm2),
1064 $crate::led_strip::PioBusStateMachine::new(pio_bus, sm3),
1065 )
1066 }
1067
1068 $(
1070 $crate::__led_strips_impl!(
1071 @__define_strip
1072 vis: $vis,
1073 group: $group,
1074 pio: $pio,
1075 label: $label,
1076 sm: $sm_index,
1077 dma: $dma,
1078 pin: $pin,
1079 len: $len,
1080 max_current: $max_current,
1081 gamma: $gamma,
1082 max_frames: $max_frames
1083 $(,
1084 led2d: {
1085 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1086 $(max_frames: $led2d_max_frames,)?
1087 font: $led2d_font,
1088 }
1089 )?
1090 );
1091 )+
1092
1093 #[allow(missing_docs)]
1095 $vis struct $group;
1096
1097 #[allow(missing_docs)]
1098 impl $group {
1099 #[allow(clippy::too_many_arguments)]
1100 pub fn new(
1101 pio: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pio>>,
1102 $(
1103 [<$label:snake _pin>]: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>>,
1104 [<$label:snake _dma>]: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>>,
1105 )+
1106 spawner: ::embassy_executor::Spawner,
1107 ) -> $crate::Result<(
1108 $(
1109 $crate::__led_strips_impl!(
1110 @__strip_return_type
1111 $label
1112 $(,
1113 led2d: {
1114 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1115 font: $led2d_font,
1116 }
1117 )?
1118 ),
1119 )+
1120 )> {
1121 let pio_peri = pio.into();
1123 let ::embassy_rp::pio::Pio { common, sm0, sm1, sm2, sm3, .. } =
1124 ::embassy_rp::pio::Pio::new(
1125 pio_peri,
1126 <::embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
1127 );
1128 let pio_bus = [<$pio _BUS>].init_with(|| {
1129 $crate::led_strip::PioBus::new(common)
1130 });
1131
1132 #[allow(unused_variables)]
1134 let sm0_wrapped = $crate::led_strip::PioBusStateMachine::new(pio_bus, sm0);
1135 #[allow(unused_variables)]
1136 let sm1_wrapped = $crate::led_strip::PioBusStateMachine::new(pio_bus, sm1);
1137 #[allow(unused_variables)]
1138 let sm2_wrapped = $crate::led_strip::PioBusStateMachine::new(pio_bus, sm2);
1139 #[allow(unused_variables)]
1140 let sm3_wrapped = $crate::led_strip::PioBusStateMachine::new(pio_bus, sm3);
1141
1142 Ok((
1144 $(
1145 $crate::__led_strips_impl!(
1146 @__strip_return_value
1147 label: $label,
1148 state_machine: $crate::__led_strips_impl!(
1149 @__select_sm
1150 $sm_index,
1151 sm0_wrapped,
1152 sm1_wrapped,
1153 sm2_wrapped,
1154 sm3_wrapped
1155 ),
1156 pin: [<$label:snake _pin>],
1157 dma: [<$label:snake _dma>],
1158 spawner: spawner
1159 $(,
1160 led2d: {
1161 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1162 font: $led2d_font,
1163 }
1164 )?
1165 ),
1166 )+
1167 ))
1168 }
1169 }
1170 }
1171 };
1172
1173 (@__select_sm 0, $sm0:ident, $sm1:ident, $sm2:ident, $sm3:ident) => { $sm0 };
1175 (@__select_sm 1, $sm0:ident, $sm1:ident, $sm2:ident, $sm3:ident) => { $sm1 };
1176 (@__select_sm 2, $sm0:ident, $sm1:ident, $sm2:ident, $sm3:ident) => { $sm2 };
1177 (@__select_sm 3, $sm0:ident, $sm1:ident, $sm2:ident, $sm3:ident) => { $sm3 };
1178
1179 (@__define_strip
1180 vis: $vis:vis,
1181 group: $group:ident,
1182 pio: $pio:ident,
1183 label: $label:ident,
1184 sm: $sm_index:expr,
1185 dma: $dma:ident,
1186 pin: $pin:ident,
1187 len: $len:expr,
1188 max_current: $max_current:expr,
1189 gamma: $gamma:expr,
1190 max_frames: $max_frames:expr
1191 ) => {
1192 paste::paste! {
1193 #[doc = concat!(
1194 "LED strip wrapper generated by [`led_strips!`].\n\n",
1195 "Derefs to provide all LED control methods. ",
1196 "Created with [`", stringify!($group), "::new`]. ",
1197 "See the [led_strip module documentation](mod@crate::led_strip) for a similar example."
1198 )]
1199 $vis struct $label {
1200 strip: $crate::led_strip::LedStrip<{ $len }, { $max_frames }>,
1201 }
1202
1203 #[allow(missing_docs)]
1204 impl $label {
1205 pub const LEN: usize = $len;
1206 pub const MAX_FRAMES: usize = $max_frames;
1207
1208 const WORST_CASE_MA: u32 = ($len as u32) * 60;
1211 pub const MAX_BRIGHTNESS: u8 =
1212 $max_current.max_brightness(Self::WORST_CASE_MA);
1213
1214 const COMBO_TABLE: [u8; 256] = $crate::led_strip::generate_combo_table($gamma, Self::MAX_BRIGHTNESS);
1216
1217 pub(crate) const fn new_static() -> $crate::led_strip::LedStripStatic<{ $len }, { $max_frames }> {
1218 $crate::led_strip::LedStrip::new_static()
1219 }
1220
1221 pub fn new(
1222 state_machine: $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, $sm_index>,
1223 pin: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>>,
1224 dma: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>>,
1225 spawner: ::embassy_executor::Spawner,
1226 ) -> $crate::Result<&'static Self> {
1227 static STRIP_STATIC: $crate::led_strip::LedStripStatic<{ $len }, { $max_frames }> =
1228 $label::new_static();
1229 static STRIP_CELL: ::static_cell::StaticCell<$label> = ::static_cell::StaticCell::new();
1230 let pin = pin.into();
1231 let dma = dma.into();
1232
1233 let (bus, sm) = state_machine.into_parts();
1234 let token = [<$label:snake _device_task>](
1235 bus,
1236 sm,
1237 dma,
1238 pin,
1239 STRIP_STATIC.command_signal(),
1240 );
1241 spawner.spawn(token).map_err($crate::Error::TaskSpawn)?;
1242 let strip = $crate::led_strip::LedStrip::new(&STRIP_STATIC)?;
1243 let instance = STRIP_CELL.init(Self { strip });
1244 Ok(instance)
1245 }
1246 }
1247
1248 impl ::core::ops::Deref for $label {
1249 type Target = $crate::led_strip::LedStrip<{ $len }, { $max_frames }>;
1250
1251 fn deref(&self) -> &Self::Target {
1252 &self.strip
1253 }
1254 }
1255
1256 #[cfg(not(feature = "host"))]
1257 impl AsRef<$crate::led_strip::LedStrip<{ $len }, { $max_frames }>> for $label {
1258 fn as_ref(&self) -> &$crate::led_strip::LedStrip<{ $len }, { $max_frames }> {
1259 &self.strip
1260 }
1261 }
1262
1263 #[::embassy_executor::task]
1264 async fn [<$label:snake _device_task>](
1265 bus: &'static $crate::led_strip::PioBus<'static, ::embassy_rp::peripherals::$pio>,
1266 sm: ::embassy_rp::pio::StateMachine<'static, ::embassy_rp::peripherals::$pio, $sm_index>,
1267 dma: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>,
1268 pin: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>,
1269 command_signal: &'static $crate::led_strip::LedStripCommandSignal<{ $len }, { $max_frames }>,
1270 ) -> ! {
1271 let program = bus.get_program();
1272 let driver = bus.with_common(|common| {
1273 ::embassy_rp::pio_programs::ws2812::PioWs2812::<
1274 ::embassy_rp::peripherals::$pio,
1275 $sm_index,
1276 { $len },
1277 _
1278 >::new(common, sm, dma, pin, program)
1279 });
1280 $crate::led_strip::led_strip_device_loop::<
1281 ::embassy_rp::peripherals::$pio,
1282 $sm_index,
1283 { $len },
1284 { $max_frames },
1285 _
1286 >(driver, command_signal, &$label::COMBO_TABLE).await
1287 }
1288 }
1289 };
1290
1291 (@__define_strip
1292 vis: $vis:vis,
1293 group: $group:ident,
1294 pio: $pio:ident,
1295 label: $label:ident,
1296 sm: $sm_index:expr,
1297 dma: $dma:ident,
1298 pin: $pin:ident,
1299 len: $len:expr,
1300 max_current: $max_current:expr,
1301 gamma: $gamma:expr,
1302 max_frames: $max_frames:expr,
1303 led2d: {
1304 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1305 $(max_frames: $led2d_max_frames:expr,)?
1306 font: $led2d_font:expr $(,)?
1307 }
1308 ) => {
1309 paste::paste! {
1310 #[doc = concat!(
1311 "LED strip wrapper generated by [`led_strips!`].\n\n",
1312 "Derefs to provide all LED control methods. ",
1313 "Created with [`", stringify!($group), "::new`]. ",
1314 "See the [led_strip module documentation](mod@crate::led_strip) for a similar example."
1315 )]
1316 #[allow(missing_docs)]
1317 struct [<$label:camel LedStrip>] {
1318 strip: $crate::led_strip::LedStrip<{ $len }, { $max_frames }>,
1319 }
1320
1321 #[allow(missing_docs)]
1322 impl [<$label:camel LedStrip>] {
1323 pub const LEN: usize = $len;
1324 pub const MAX_FRAMES: usize = $max_frames;
1325
1326 const WORST_CASE_MA: u32 = ($len as u32) * 60;
1329 pub const MAX_BRIGHTNESS: u8 =
1330 $max_current.max_brightness(Self::WORST_CASE_MA);
1331
1332 const COMBO_TABLE: [u8; 256] = $crate::led_strip::generate_combo_table($gamma, Self::MAX_BRIGHTNESS);
1334
1335 pub(crate) const fn new_static() -> $crate::led_strip::LedStripStatic<{ $len }, { $max_frames }> {
1336 $crate::led_strip::LedStrip::new_static()
1337 }
1338
1339 pub fn new(
1340 state_machine: $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, $sm_index>,
1341 pin: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>>,
1342 dma: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>>,
1343 spawner: ::embassy_executor::Spawner,
1344 ) -> $crate::Result<&'static Self> {
1345 static STRIP_STATIC: $crate::led_strip::LedStripStatic<{ $len }, { $max_frames }> =
1346 [<$label:camel LedStrip>]::new_static();
1347 static STRIP_CELL: ::static_cell::StaticCell<[<$label:camel LedStrip>]> = ::static_cell::StaticCell::new();
1348 let pin = pin.into();
1349 let dma = dma.into();
1350
1351 let (bus, sm) = state_machine.into_parts();
1352 let token = [<$label:snake _led_strip _device_task>](
1353 bus,
1354 sm,
1355 dma,
1356 pin,
1357 STRIP_STATIC.command_signal(),
1358 );
1359 spawner.spawn(token).map_err($crate::Error::TaskSpawn)?;
1360 let strip = $crate::led_strip::LedStrip::new(&STRIP_STATIC)?;
1361 let instance = STRIP_CELL.init(Self { strip });
1362 Ok(instance)
1363 }
1364 }
1365
1366 impl ::core::ops::Deref for [<$label:camel LedStrip>] {
1367 type Target = $crate::led_strip::LedStrip<{ $len }, { $max_frames }>;
1368
1369 fn deref(&self) -> &Self::Target {
1370 &self.strip
1371 }
1372 }
1373
1374 #[cfg(not(feature = "host"))]
1375 impl AsRef<$crate::led_strip::LedStrip<{ $len }, { $max_frames }>> for [<$label:camel LedStrip>] {
1376 fn as_ref(&self) -> &$crate::led_strip::LedStrip<{ $len }, { $max_frames }> {
1377 &self.strip
1378 }
1379 }
1380
1381 #[::embassy_executor::task]
1382 async fn [<$label:snake _led_strip _device_task>](
1383 bus: &'static $crate::led_strip::PioBus<'static, ::embassy_rp::peripherals::$pio>,
1384 sm: ::embassy_rp::pio::StateMachine<'static, ::embassy_rp::peripherals::$pio, $sm_index>,
1385 dma: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>,
1386 pin: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>,
1387 command_signal: &'static $crate::led_strip::LedStripCommandSignal<{ $len }, { $max_frames }>,
1388 ) -> ! {
1389 let program = bus.get_program();
1390 let driver = bus.with_common(|common| {
1391 ::embassy_rp::pio_programs::ws2812::PioWs2812::<
1392 ::embassy_rp::peripherals::$pio,
1393 $sm_index,
1394 { $len },
1395 _
1396 >::new(common, sm, dma, pin, program)
1397 });
1398 $crate::led_strip::led_strip_device_loop::<
1399 ::embassy_rp::peripherals::$pio,
1400 $sm_index,
1401 { $len },
1402 { $max_frames },
1403 _
1404 >(driver, command_signal, &[<$label:camel LedStrip>]::COMBO_TABLE).await
1405 }
1406
1407 #[cfg(not(feature = "host"))]
1408 $crate::led2d::led2d_from_strip! {
1409 $vis $label,
1410 strip_type: [<$label:camel LedStrip>],
1411 width: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?.width(),
1412 height: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?.height(),
1413 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1414 font: $led2d_font,
1415 }
1416
1417 #[cfg(not(feature = "host"))]
1418 impl [<$label:camel LedStrip>] {
1419 pub fn new_led2d(
1420 state_machine: $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, $sm_index>,
1421 pin: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>>,
1422 dma: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>>,
1423 spawner: ::embassy_executor::Spawner,
1424 ) -> $crate::Result<$label> {
1425 let strip = Self::new(state_machine, pin, dma, spawner)?;
1426 $label::from_strip(strip)
1427 }
1428 }
1429 }
1430 };
1431
1432 (@__strip_return_type $label:ident) => {
1433 &'static $label
1434 };
1435 (@__strip_return_type $label:ident, led2d: { $($led2d_fields:tt)* }) => {
1436 $label
1437 };
1438
1439
1440 (@__strip_return_value
1441 label: $label:ident,
1442 state_machine: $state_machine:expr,
1443 pin: $pin:ident,
1444 dma: $dma:ident,
1445 spawner: $spawner:ident
1446 ) => {
1447 $label::new($state_machine, $pin, $dma, $spawner)?
1448 };
1449 (@__strip_return_value
1450 label: $label:ident,
1451 state_machine: $state_machine:expr,
1452 pin: $pin:ident,
1453 dma: $dma:ident,
1454 spawner: $spawner:ident,
1455 led2d: {
1456 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1457 $(max_frames: $led2d_max_frames:expr,)?
1458 font: $led2d_font:expr $(,)?
1459 }
1460 ) => {
1461 paste::paste! {{
1462 let [<$label:snake _led_strip>] =
1463 [<$label:camel LedStrip>]::new($state_machine, $pin, $dma, $spawner)?;
1464 $label::from_strip([<$label:snake _led_strip>])?
1465 }}
1466 };
1467
1468 (@__with_frame_alias
1470 frame_alias: $frame_alias:tt,
1471 pio: $pio:ident,
1472 vis: $vis:vis,
1473 $group:ident {
1474 $( $label:ident: { $($fields:tt)* } ),+ $(,)?
1475 }
1476 ) => {
1477 $crate::__led_strips_impl! {
1478 @__with_defaults
1479 frame_alias: $frame_alias,
1480 pio: $pio,
1481 vis: $vis,
1482 group: $group,
1483 sm_counter: 0,
1484 strips_out: [],
1485 strips_in: [ $( $label: { $($fields)* } ),+ ]
1486 }
1487 };
1488
1489 (
1491 pio: $pio:ident,
1492 $vis:vis $group:ident {
1493 $( $label:ident: { $($fields:tt)* } ),+ $(,)?
1494 }
1495 ) => {
1496 $crate::__led_strips_impl! {
1497 @__with_defaults
1498 frame_alias: __WITH_FRAME_ALIAS__,
1499 pio: $pio,
1500 vis: $vis,
1501 group: $group,
1502 sm_counter: 0,
1503 strips_out: [],
1504 strips_in: [ $( $label: { $($fields)* } ),+ ]
1505 }
1506 };
1507
1508 (
1514 $vis:vis $group:ident {
1515 $( $label:ident: { $($fields:tt)* } ),+ $(,)?
1516 }
1517 ) => {
1518 $crate::__led_strips_impl! {
1519 @__with_defaults
1520 frame_alias: __WITH_FRAME_ALIAS__,
1521 pio: PIO0,
1522 vis: $vis,
1523 group: $group,
1524 sm_counter: 0,
1525 strips_out: [],
1526 strips_in: [ $( $label: { $($fields)* } ),+ ]
1527 }
1528 };
1529
1530 (@__with_defaults
1534 frame_alias: $frame_alias:tt,
1535 pio: $pio:ident,
1536 vis: $vis:vis,
1537 group: $group:ident,
1538 sm_counter: $sm:tt,
1539 strips_out: [ $($out:tt)* ],
1540 strips_in: [ $label:ident: { $($fields:tt)* } $(, $($rest:tt)* )? ]
1541 ) => {
1542 $crate::__led_strips_impl! {
1543 @__fill_strip_defaults
1544 frame_alias: $frame_alias,
1545 pio: $pio,
1546 vis: $vis,
1547 sm_counter: $sm,
1548 strips_out: [ $($out)* ],
1549 strips_remaining: [ $($($rest)*)? ],
1550 label: $label,
1551 group: $group,
1552 pin: __MISSING_PIN__,
1553 dma: __DEFAULT_DMA__,
1554 len: __MISSING_LEN__,
1555 max_current: __MISSING_MAX_CURRENT__,
1556 gamma: $crate::led_strip::GAMMA_DEFAULT,
1557 max_frames: $crate::led_strip::MAX_FRAMES_DEFAULT,
1558 led2d: __NONE__,
1559 fields: [ $($fields)* ]
1560 }
1561 };
1562
1563 (@__with_defaults
1565 frame_alias: $frame_alias:tt,
1566 pio: $pio:ident,
1567 vis: $vis:vis,
1568 group: $group:ident,
1569 sm_counter: $sm:tt,
1570 strips_out: [ $($out:tt)* ],
1571 strips_in: []
1572 ) => {
1573 $crate::__led_strips_impl! {
1574 @__resolve_default_dma
1575 frame_alias: $frame_alias,
1576 pio: $pio,
1577 vis: $vis,
1578 group: $group,
1579 strips_out: [],
1580 strips_in: [ $($out)* ]
1581 }
1582 };
1583
1584 (@__resolve_default_dma
1586 frame_alias: $frame_alias:tt,
1587 pio: $pio:ident,
1588 vis: $vis:vis,
1589 group: $group:ident,
1590 strips_out: [ $($out:tt)* ],
1591 strips_in: []
1592 ) => {
1593 $crate::__led_strips_impl! {
1594 @__expand
1595 frame_alias: $frame_alias,
1596 pio: $pio,
1597 vis: $vis,
1598 group: $group,
1599 strips: [ $($out)* ]
1600 }
1601 };
1602
1603 (@__resolve_default_dma
1604 frame_alias: $frame_alias:tt,
1605 pio: $pio:ident,
1606 vis: $vis:vis,
1607 group: $group:ident,
1608 strips_out: [ $($out:tt)* ],
1609 strips_in: [
1610 $label:ident {
1611 sm: 0,
1612 dma: __DEFAULT_DMA__,
1613 pin: $pin:ident,
1614 len: $len:expr,
1615 max_current: $max_current:expr,
1616 gamma: $gamma:expr,
1617 max_frames: $max_frames:expr
1618 $(,
1619 led2d: {
1620 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1621 $(max_frames: $led2d_max_frames:expr,)?
1622 font: $led2d_font:expr $(,)?
1623 }
1624 )?
1625 }
1626 $(, $($rest:tt)* )?
1627 ]
1628 ) => {
1629 $crate::__led_strips_impl! {
1630 @__resolve_default_dma
1631 frame_alias: $frame_alias,
1632 pio: $pio,
1633 vis: $vis,
1634 group: $group,
1635 strips_out: [
1636 $($out)*
1637 $label {
1638 sm: 0,
1639 dma: DMA_CH0,
1640 pin: $pin,
1641 len: $len,
1642 max_current: $max_current,
1643 gamma: $gamma,
1644 max_frames: $max_frames
1645 $(,
1646 led2d: {
1647 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1648 font: $led2d_font,
1649 }
1650 )?
1651 },
1652 ],
1653 strips_in: [ $($($rest)*)? ]
1654 }
1655 };
1656
1657 (@__resolve_default_dma
1659 frame_alias: $frame_alias:tt,
1660 pio: $pio:ident,
1661 vis: $vis:vis,
1662 group: $group:ident,
1663 strips_out: [ $($out:tt)* ],
1664 strips_in: [
1665 $label:ident {
1666 sm: 0,
1667 dma: __DEFAULT_DMA__,
1668 pin: $pin:ident,
1669 len: $len:expr,
1670 max_current: $max_current:expr,
1671 gamma: $gamma:expr,
1672 max_frames: $max_frames:expr
1673 ,
1674 led2d: {
1675 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1676 font: $led2d_font:expr $(,)?
1677 }
1678 }
1679 $(, $($rest:tt)* )?
1680 ]
1681 ) => {
1682 $crate::__led_strips_impl! {
1683 @__resolve_default_dma
1684 frame_alias: $frame_alias,
1685 pio: $pio,
1686 vis: $vis,
1687 group: $group,
1688 strips_out: [
1689 $($out)*
1690 $label {
1691 sm: 0,
1692 dma: DMA_CH0,
1693 pin: $pin,
1694 len: $len,
1695 max_current: $max_current,
1696 gamma: $gamma,
1697 max_frames: $max_frames
1698 ,
1699 led2d: {
1700 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1701 max_frames: $max_frames,
1702 font: $led2d_font,
1703 }
1704 },
1705 ],
1706 strips_in: [ $($($rest)*)? ]
1707 }
1708 };
1709
1710 (@__resolve_default_dma
1712 frame_alias: $frame_alias:tt,
1713 pio: $pio:ident,
1714 vis: $vis:vis,
1715 group: $group:ident,
1716 strips_out: [ $($out:tt)* ],
1717 strips_in: [
1718 $label:ident {
1719 sm: 1,
1720 dma: __DEFAULT_DMA__,
1721 pin: $pin:ident,
1722 len: $len:expr,
1723 max_current: $max_current:expr,
1724 gamma: $gamma:expr,
1725 max_frames: $max_frames:expr
1726 ,
1727 led2d: {
1728 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1729 font: $led2d_font:expr $(,)?
1730 }
1731 }
1732 $(, $($rest:tt)* )?
1733 ]
1734 ) => {
1735 $crate::__led_strips_impl! {
1736 @__resolve_default_dma
1737 frame_alias: $frame_alias,
1738 pio: $pio,
1739 vis: $vis,
1740 group: $group,
1741 strips_out: [
1742 $($out)*
1743 $label {
1744 sm: 1,
1745 dma: DMA_CH1,
1746 pin: $pin,
1747 len: $len,
1748 max_current: $max_current,
1749 gamma: $gamma,
1750 max_frames: $max_frames
1751 ,
1752 led2d: {
1753 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1754 max_frames: $max_frames,
1755 font: $led2d_font,
1756 }
1757 },
1758 ],
1759 strips_in: [ $($($rest)*)? ]
1760 }
1761 };
1762
1763 (@__resolve_default_dma
1765 frame_alias: $frame_alias:tt,
1766 pio: $pio:ident,
1767 vis: $vis:vis,
1768 group: $group:ident,
1769 strips_out: [ $($out:tt)* ],
1770 strips_in: [
1771 $label:ident {
1772 sm: 1,
1773 dma: __DEFAULT_DMA__,
1774 pin: $pin:ident,
1775 len: $len:expr,
1776 max_current: $max_current:expr,
1777 gamma: $gamma:expr,
1778 max_frames: $max_frames:expr
1779 $(,
1780 led2d: {
1781 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1782 $(max_frames: $led2d_max_frames:expr,)?
1783 font: $led2d_font:expr $(,)?
1784 }
1785 )?
1786 }
1787 $(, $($rest:tt)* )?
1788 ]
1789 ) => {
1790 $crate::__led_strips_impl! {
1791 @__resolve_default_dma
1792 frame_alias: $frame_alias,
1793 pio: $pio,
1794 vis: $vis,
1795 group: $group,
1796 strips_out: [
1797 $($out)*
1798 $label {
1799 sm: 1,
1800 dma: DMA_CH1,
1801 pin: $pin,
1802 len: $len,
1803 max_current: $max_current,
1804 gamma: $gamma,
1805 max_frames: $max_frames
1806 $(,
1807 led2d: {
1808 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1809 font: $led2d_font,
1810 }
1811 )?
1812 },
1813 ],
1814 strips_in: [ $($($rest)*)? ]
1815 }
1816 };
1817
1818 (@__resolve_default_dma
1820 frame_alias: $frame_alias:tt,
1821 pio: $pio:ident,
1822 vis: $vis:vis,
1823 group: $group:ident,
1824 strips_out: [ $($out:tt)* ],
1825 strips_in: [
1826 $label:ident {
1827 sm: 2,
1828 dma: __DEFAULT_DMA__,
1829 pin: $pin:ident,
1830 len: $len:expr,
1831 max_current: $max_current:expr,
1832 gamma: $gamma:expr,
1833 max_frames: $max_frames:expr
1834 ,
1835 led2d: {
1836 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1837 font: $led2d_font:expr $(,)?
1838 }
1839 }
1840 $(, $($rest:tt)* )?
1841 ]
1842 ) => {
1843 $crate::__led_strips_impl! {
1844 @__resolve_default_dma
1845 frame_alias: $frame_alias,
1846 pio: $pio,
1847 vis: $vis,
1848 group: $group,
1849 strips_out: [
1850 $($out)*
1851 $label {
1852 sm: 2,
1853 dma: DMA_CH2,
1854 pin: $pin,
1855 len: $len,
1856 max_current: $max_current,
1857 gamma: $gamma,
1858 max_frames: $max_frames
1859 ,
1860 led2d: {
1861 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1862 max_frames: $max_frames,
1863 font: $led2d_font,
1864 }
1865 },
1866 ],
1867 strips_in: [ $($($rest)*)? ]
1868 }
1869 };
1870
1871 (@__resolve_default_dma
1873 frame_alias: $frame_alias:tt,
1874 pio: $pio:ident,
1875 vis: $vis:vis,
1876 group: $group:ident,
1877 strips_out: [ $($out:tt)* ],
1878 strips_in: [
1879 $label:ident {
1880 sm: 3,
1881 dma: __DEFAULT_DMA__,
1882 pin: $pin:ident,
1883 len: $len:expr,
1884 max_current: $max_current:expr,
1885 gamma: $gamma:expr,
1886 max_frames: $max_frames:expr
1887 ,
1888 led2d: {
1889 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1890 font: $led2d_font:expr $(,)?
1891 }
1892 }
1893 $(, $($rest:tt)* )?
1894 ]
1895 ) => {
1896 $crate::__led_strips_impl! {
1897 @__resolve_default_dma
1898 frame_alias: $frame_alias,
1899 pio: $pio,
1900 vis: $vis,
1901 group: $group,
1902 strips_out: [
1903 $($out)*
1904 $label {
1905 sm: 3,
1906 dma: DMA_CH3,
1907 pin: $pin,
1908 len: $len,
1909 max_current: $max_current,
1910 gamma: $gamma,
1911 max_frames: $max_frames
1912 ,
1913 led2d: {
1914 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1915 max_frames: $max_frames,
1916 font: $led2d_font,
1917 }
1918 },
1919 ],
1920 strips_in: [ $($($rest)*)? ]
1921 }
1922 };
1923
1924 (@__resolve_default_dma
1925 frame_alias: $frame_alias:tt,
1926 pio: $pio:ident,
1927 vis: $vis:vis,
1928 group: $group:ident,
1929 strips_out: [ $($out:tt)* ],
1930 strips_in: [
1931 $label:ident {
1932 sm: 2,
1933 dma: __DEFAULT_DMA__,
1934 pin: $pin:ident,
1935 len: $len:expr,
1936 max_current: $max_current:expr,
1937 gamma: $gamma:expr,
1938 max_frames: $max_frames:expr
1939 $(,
1940 led2d: {
1941 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1942 $(max_frames: $led2d_max_frames:expr,)?
1943 font: $led2d_font:expr $(,)?
1944 }
1945 )?
1946 }
1947 $(, $($rest:tt)* )?
1948 ]
1949 ) => {
1950 $crate::__led_strips_impl! {
1951 @__resolve_default_dma
1952 frame_alias: $frame_alias,
1953 pio: $pio,
1954 vis: $vis,
1955 group: $group,
1956 strips_out: [
1957 $($out)*
1958 $label {
1959 sm: 2,
1960 dma: DMA_CH2,
1961 pin: $pin,
1962 len: $len,
1963 max_current: $max_current,
1964 gamma: $gamma,
1965 max_frames: $max_frames
1966 $(,
1967 led2d: {
1968 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
1969 font: $led2d_font,
1970 }
1971 )?
1972 },
1973 ],
1974 strips_in: [ $($($rest)*)? ]
1975 }
1976 };
1977
1978 (@__resolve_default_dma
1979 frame_alias: $frame_alias:tt,
1980 pio: $pio:ident,
1981 vis: $vis:vis,
1982 group: $group:ident,
1983 strips_out: [ $($out:tt)* ],
1984 strips_in: [
1985 $label:ident {
1986 sm: 3,
1987 dma: __DEFAULT_DMA__,
1988 pin: $pin:ident,
1989 len: $len:expr,
1990 max_current: $max_current:expr,
1991 gamma: $gamma:expr,
1992 max_frames: $max_frames:expr
1993 $(,
1994 led2d: {
1995 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
1996 $(max_frames: $led2d_max_frames:expr,)?
1997 font: $led2d_font:expr $(,)?
1998 }
1999 )?
2000 }
2001 $(, $($rest:tt)* )?
2002 ]
2003 ) => {
2004 $crate::__led_strips_impl! {
2005 @__resolve_default_dma
2006 frame_alias: $frame_alias,
2007 pio: $pio,
2008 vis: $vis,
2009 group: $group,
2010 strips_out: [
2011 $($out)*
2012 $label {
2013 sm: 3,
2014 dma: DMA_CH3,
2015 pin: $pin,
2016 len: $len,
2017 max_current: $max_current,
2018 gamma: $gamma,
2019 max_frames: $max_frames
2020 $(,
2021 led2d: {
2022 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
2023 font: $led2d_font,
2024 }
2025 )?
2026 },
2027 ],
2028 strips_in: [ $($($rest)*)? ]
2029 }
2030 };
2031
2032 (@__resolve_default_dma
2033 frame_alias: $frame_alias:tt,
2034 pio: $pio:ident,
2035 vis: $vis:vis,
2036 group: $group:ident,
2037 strips_out: [ $($out:tt)* ],
2038 strips_in: [
2039 $label:ident {
2040 sm: $sm_index:expr,
2041 dma: $dma:ident,
2042 pin: $pin:ident,
2043 len: $len:expr,
2044 max_current: $max_current:expr,
2045 gamma: $gamma:expr,
2046 max_frames: $max_frames:expr
2047 $(,
2048 led2d: {
2049 led_layout: $led2d_led_layout:ident $( ( $($led2d_led_layout_args:tt)* ) )?,
2050 $(max_frames: $led2d_max_frames:expr,)?
2051 font: $led2d_font:expr $(,)?
2052 }
2053 )?
2054 }
2055 $(, $($rest:tt)* )?
2056 ]
2057 ) => {
2058 $crate::__led_strips_impl! {
2059 @__resolve_default_dma
2060 frame_alias: $frame_alias,
2061 pio: $pio,
2062 vis: $vis,
2063 group: $group,
2064 strips_out: [
2065 $($out)*
2066 $label {
2067 sm: $sm_index,
2068 dma: $dma,
2069 pin: $pin,
2070 len: $len,
2071 max_current: $max_current,
2072 gamma: $gamma,
2073 max_frames: $max_frames
2074 $(,
2075 led2d: {
2076 led_layout: $led2d_led_layout $( ( $($led2d_led_layout_args)* ) )?,
2077 font: $led2d_font,
2078 }
2079 )?
2080 },
2081 ],
2082 strips_in: [ $($($rest)*)? ]
2083 }
2084 };
2085
2086
2087 (@__fill_strip_defaults
2089 frame_alias: $frame_alias:tt,
2090 pio: $pio:ident,
2091 vis: $vis:vis,
2092 sm_counter: $sm:tt,
2093 strips_out: [ $($out:tt)* ],
2094 strips_remaining: [ $($remaining:tt)* ],
2095 label: $label:ident,
2096 group: $group:ident,
2097 pin: $pin:tt,
2098 dma: $dma:ident,
2099 len: $len:tt,
2100 max_current: $max_current:expr,
2101 gamma: $gamma:expr,
2102 max_frames: $max_frames:expr,
2103 led2d: $led2d:tt,
2104 fields: [ pin: $new_pin:ident $(, $($rest:tt)* )? ]
2105 ) => {
2106 $crate::__led_strips_impl! {
2107 @__fill_strip_defaults
2108 frame_alias: $frame_alias,
2109 pio: $pio,
2110 vis: $vis,
2111 sm_counter: $sm,
2112 strips_out: [ $($out)* ],
2113 strips_remaining: [ $($remaining)* ],
2114 label: $label,
2115 group: $group,
2116 pin: $new_pin,
2117 dma: $dma,
2118 len: $len,
2119 max_current: $max_current,
2120 gamma: $gamma,
2121 max_frames: $max_frames,
2122 led2d: $led2d,
2123 fields: [ $($($rest)*)? ]
2124 }
2125 };
2126
2127 (@__fill_strip_defaults
2128 frame_alias: $frame_alias:tt,
2129 pio: $pio:ident,
2130 vis: $vis:vis,
2131 sm_counter: $sm:tt,
2132 strips_out: [ $($out:tt)* ],
2133 strips_remaining: [ $($remaining:tt)* ],
2134 label: $label:ident,
2135 group: $group:ident,
2136 pin: $pin:tt,
2137 dma: $dma:ident,
2138 len: $len:tt,
2139 max_current: $max_current:expr,
2140 gamma: $gamma:expr,
2141 max_frames: $max_frames:expr,
2142 led2d: $led2d:tt,
2143 fields: [ dma: $new_dma:ident $(, $($rest:tt)* )? ]
2144 ) => {
2145 $crate::__led_strips_impl! {
2146 @__fill_strip_defaults
2147 frame_alias: $frame_alias,
2148 pio: $pio,
2149 vis: $vis,
2150 sm_counter: $sm,
2151 strips_out: [ $($out)* ],
2152 strips_remaining: [ $($remaining)* ],
2153 label: $label,
2154 group: $group,
2155 pin: $pin,
2156 dma: $new_dma,
2157 len: $len,
2158 max_current: $max_current,
2159 gamma: $gamma,
2160 max_frames: $max_frames,
2161 led2d: $led2d,
2162 fields: [ $($($rest)*)? ]
2163 }
2164 };
2165
2166 (@__fill_strip_defaults
2167 frame_alias: $frame_alias:tt,
2168 pio: $pio:ident,
2169 vis: $vis:vis,
2170 sm_counter: $sm:tt,
2171 strips_out: [ $($out:tt)* ],
2172 strips_remaining: [ $($remaining:tt)* ],
2173 label: $label:ident,
2174 group: $group:ident,
2175 pin: $pin:tt,
2176 dma: $dma:ident,
2177 len: $len:tt,
2178 max_current: $max_current:expr,
2179 gamma: $gamma:expr,
2180 max_frames: $max_frames:expr,
2181 led2d: $led2d:tt,
2182 fields: [ len: $new_len:expr $(, $($rest:tt)* )? ]
2183 ) => {
2184 $crate::__led_strips_impl! {
2185 @__fill_strip_defaults
2186 frame_alias: $frame_alias,
2187 pio: $pio,
2188 vis: $vis,
2189 sm_counter: $sm,
2190 strips_out: [ $($out)* ],
2191 strips_remaining: [ $($remaining)* ],
2192 label: $label,
2193 group: $group,
2194 pin: $pin,
2195 dma: $dma,
2196 len: $new_len,
2197 max_current: $max_current,
2198 gamma: $gamma,
2199 max_frames: $max_frames,
2200 led2d: $led2d,
2201 fields: [ $($($rest)*)? ]
2202 }
2203 };
2204
2205 (@__fill_strip_defaults
2206 frame_alias: $frame_alias:tt,
2207 pio: $pio:ident,
2208 vis: $vis:vis,
2209 sm_counter: $sm:tt,
2210 strips_out: [ $($out:tt)* ],
2211 strips_remaining: [ $($remaining:tt)* ],
2212 label: $label:ident,
2213 group: $group:ident,
2214 pin: $pin:tt,
2215 dma: $dma:ident,
2216 len: $len:tt,
2217 max_current: $max_current:expr,
2218 gamma: $gamma:expr,
2219 max_frames: $max_frames:expr,
2220 led2d: $led2d:tt,
2221 fields: [ max_current: $new_max_current:expr $(, $($rest:tt)* )? ]
2222 ) => {
2223 $crate::__led_strips_impl! {
2224 @__fill_strip_defaults
2225 frame_alias: $frame_alias,
2226 pio: $pio,
2227 vis: $vis,
2228 sm_counter: $sm,
2229 strips_out: [ $($out)* ],
2230 strips_remaining: [ $($remaining)* ],
2231 label: $label,
2232 group: $group,
2233 pin: $pin,
2234 dma: $dma,
2235 len: $len,
2236 max_current: $new_max_current,
2237 gamma: $gamma,
2238 max_frames: $max_frames,
2239 led2d: $led2d,
2240 fields: [ $($($rest)*)? ]
2241 }
2242 };
2243
2244 (@__fill_strip_defaults
2245 frame_alias: $frame_alias:tt,
2246 pio: $pio:ident,
2247 vis: $vis:vis,
2248 sm_counter: $sm:tt,
2249 strips_out: [ $($out:tt)* ],
2250 strips_remaining: [ $($remaining:tt)* ],
2251 label: $label:ident,
2252 group: $group:ident,
2253 pin: $pin:tt,
2254 dma: $dma:ident,
2255 len: $len:tt,
2256 max_current: $max_current:expr,
2257 gamma: $gamma:expr,
2258 max_frames: $max_frames:expr,
2259 led2d: $led2d:tt,
2260 fields: [ gamma: $new_gamma:expr $(, $($rest:tt)* )? ]
2261 ) => {
2262 $crate::__led_strips_impl! {
2263 @__fill_strip_defaults
2264 frame_alias: $frame_alias,
2265 pio: $pio,
2266 vis: $vis,
2267 sm_counter: $sm,
2268 strips_out: [ $($out)* ],
2269 strips_remaining: [ $($remaining)* ],
2270 label: $label,
2271 group: $group,
2272 pin: $pin,
2273 dma: $dma,
2274 len: $len,
2275 max_current: $max_current,
2276 gamma: $new_gamma,
2277 max_frames: $max_frames,
2278 led2d: $led2d,
2279 fields: [ $($($rest)*)? ]
2280 }
2281 };
2282
2283 (@__fill_strip_defaults
2284 frame_alias: $frame_alias:tt,
2285 pio: $pio:ident,
2286 vis: $vis:vis,
2287 sm_counter: $sm:tt,
2288 strips_out: [ $($out:tt)* ],
2289 strips_remaining: [ $($remaining:tt)* ],
2290 label: $label:ident,
2291 group: $group:ident,
2292 pin: $pin:tt,
2293 dma: $dma:ident,
2294 len: $len:tt,
2295 max_current: $max_current:expr,
2296 gamma: $gamma:expr,
2297 max_frames: $max_frames:expr,
2298 led2d: $led2d:tt,
2299 fields: [ max_frames: $new_max_frames:expr $(, $($rest:tt)* )? ]
2300 ) => {
2301 $crate::__led_strips_impl! {
2302 @__fill_strip_defaults
2303 frame_alias: $frame_alias,
2304 pio: $pio,
2305 vis: $vis,
2306 sm_counter: $sm,
2307 strips_out: [ $($out)* ],
2308 strips_remaining: [ $($remaining)* ],
2309 label: $label,
2310 group: $group,
2311 pin: $pin,
2312 dma: $dma,
2313 len: $len,
2314 max_current: $max_current,
2315 gamma: $gamma,
2316 max_frames: $new_max_frames,
2317 led2d: $led2d,
2318 fields: [ $($($rest)*)? ]
2319 }
2320 };
2321
2322 (@__fill_strip_defaults
2323 frame_alias: $frame_alias:tt,
2324 pio: $pio:ident,
2325 vis: $vis:vis,
2326 sm_counter: $sm:tt,
2327 strips_out: [ $($out:tt)* ],
2328 strips_remaining: [ $($remaining:tt)* ],
2329 label: $label:ident,
2330 group: $group:ident,
2331 pin: $pin:tt,
2332 dma: $dma:ident,
2333 len: $len:tt,
2334 max_current: $max_current:expr,
2335 gamma: $gamma:expr,
2336 max_frames: $max_frames:expr,
2337 led2d: __NONE__,
2338 fields: [ led2d: { $($led2d_fields:tt)* } $(, $($rest:tt)* )? ]
2339 ) => {
2340 $crate::__led_strips_impl! {
2341 @__fill_strip_defaults
2342 frame_alias: $frame_alias,
2343 pio: $pio,
2344 vis: $vis,
2345 sm_counter: $sm,
2346 strips_out: [ $($out)* ],
2347 strips_remaining: [ $($remaining)* ],
2348 label: $label,
2349 group: $group,
2350 pin: $pin,
2351 dma: $dma,
2352 len: $len,
2353 max_current: $max_current,
2354 gamma: $gamma,
2355 max_frames: $max_frames,
2356 led2d: __HAS_LED2D__ { $($led2d_fields)* },
2357 fields: [ $($($rest)*)? ]
2358 }
2359 };
2360
2361 (@__fill_strip_defaults
2364 frame_alias: $frame_alias:tt,
2365 pio: $pio:ident,
2366 vis: $vis:vis,
2367 sm_counter: 0,
2368 strips_out: [ $($out:tt)* ],
2369 strips_remaining: [ $($remaining:tt)* ],
2370 label: $label:ident,
2371 group: $group:ident,
2372 pin: $pin:ident,
2373 dma: __DEFAULT_DMA__,
2374 len: $len:expr,
2375 max_current: $max_current:expr,
2376 gamma: $gamma:expr,
2377 max_frames: $max_frames:expr,
2378 led2d: $led2d:tt,
2379 fields: []
2380 ) => {
2381 $crate::__led_strips_impl! {
2382 @__fill_strip_defaults
2383 frame_alias: $frame_alias,
2384 pio: $pio,
2385 vis: $vis,
2386 sm_counter: 0,
2387 strips_out: [ $($out)* ],
2388 strips_remaining: [ $($remaining)* ],
2389 label: $label,
2390 group: $group,
2391 pin: $pin,
2392 dma: DMA_CH0,
2393 len: $len,
2394 max_current: $max_current,
2395 gamma: $gamma,
2396 max_frames: $max_frames,
2397 led2d: $led2d,
2398 fields: []
2399 }
2400 };
2401 (@__fill_strip_defaults
2402 frame_alias: $frame_alias:tt,
2403 pio: $pio:ident,
2404 vis: $vis:vis,
2405 sm_counter: 1,
2406 strips_out: [ $($out:tt)* ],
2407 strips_remaining: [ $($remaining:tt)* ],
2408 label: $label:ident,
2409 group: $group:ident,
2410 pin: $pin:ident,
2411 dma: __DEFAULT_DMA__,
2412 len: $len:expr,
2413 max_current: $max_current:expr,
2414 gamma: $gamma:expr,
2415 max_frames: $max_frames:expr,
2416 led2d: $led2d:tt,
2417 fields: []
2418 ) => {
2419 $crate::__led_strips_impl! {
2420 @__fill_strip_defaults
2421 frame_alias: $frame_alias,
2422 pio: $pio,
2423 vis: $vis,
2424 sm_counter: 1,
2425 strips_out: [ $($out)* ],
2426 strips_remaining: [ $($remaining)* ],
2427 label: $label,
2428 group: $group,
2429 pin: $pin,
2430 dma: DMA_CH1,
2431 len: $len,
2432 max_current: $max_current,
2433 gamma: $gamma,
2434 max_frames: $max_frames,
2435 led2d: $led2d,
2436 fields: []
2437 }
2438 };
2439 (@__fill_strip_defaults
2440 frame_alias: $frame_alias:tt,
2441 pio: $pio:ident,
2442 vis: $vis:vis,
2443 sm_counter: 2,
2444 strips_out: [ $($out:tt)* ],
2445 strips_remaining: [ $($remaining:tt)* ],
2446 label: $label:ident,
2447 group: $group:ident,
2448 pin: $pin:ident,
2449 dma: __DEFAULT_DMA__,
2450 len: $len:expr,
2451 max_current: $max_current:expr,
2452 gamma: $gamma:expr,
2453 max_frames: $max_frames:expr,
2454 led2d: $led2d:tt,
2455 fields: []
2456 ) => {
2457 $crate::__led_strips_impl! {
2458 @__fill_strip_defaults
2459 frame_alias: $frame_alias,
2460 pio: $pio,
2461 vis: $vis,
2462 sm_counter: 2,
2463 strips_out: [ $($out)* ],
2464 strips_remaining: [ $($remaining)* ],
2465 label: $label,
2466 group: $group,
2467 pin: $pin,
2468 dma: DMA_CH2,
2469 len: $len,
2470 max_current: $max_current,
2471 gamma: $gamma,
2472 max_frames: $max_frames,
2473 led2d: $led2d,
2474 fields: []
2475 }
2476 };
2477 (@__fill_strip_defaults
2478 frame_alias: $frame_alias:tt,
2479 pio: $pio:ident,
2480 vis: $vis:vis,
2481 sm_counter: 3,
2482 strips_out: [ $($out:tt)* ],
2483 strips_remaining: [ $($remaining:tt)* ],
2484 label: $label:ident,
2485 group: $group:ident,
2486 pin: $pin:ident,
2487 dma: __DEFAULT_DMA__,
2488 len: $len:expr,
2489 max_current: $max_current:expr,
2490 gamma: $gamma:expr,
2491 max_frames: $max_frames:expr,
2492 led2d: $led2d:tt,
2493 fields: []
2494 ) => {
2495 $crate::__led_strips_impl! {
2496 @__fill_strip_defaults
2497 frame_alias: $frame_alias,
2498 pio: $pio,
2499 vis: $vis,
2500 sm_counter: 3,
2501 strips_out: [ $($out)* ],
2502 strips_remaining: [ $($remaining)* ],
2503 label: $label,
2504 group: $group,
2505 pin: $pin,
2506 dma: DMA_CH3,
2507 len: $len,
2508 max_current: $max_current,
2509 gamma: $gamma,
2510 max_frames: $max_frames,
2511 led2d: $led2d,
2512 fields: []
2513 }
2514 };
2515
2516 (@__fill_strip_defaults
2518 frame_alias: $frame_alias:tt,
2519 pio: $pio:ident,
2520 vis: $vis:vis,
2521 sm_counter: $sm:tt,
2522 strips_out: [ $($out:tt)* ],
2523 strips_remaining: [ $($remaining:tt)* ],
2524 label: $label:ident,
2525 group: $group:ident,
2526 pin: $pin:ident,
2527 dma: $dma:ident,
2528 len: $len:expr,
2529 max_current: __MISSING_MAX_CURRENT__,
2530 gamma: $gamma:expr,
2531 max_frames: $max_frames:expr,
2532 led2d: __NONE__,
2533 fields: []
2534 ) => {
2535 compile_error!("led_strips!: max_current is required for every strip");
2536 };
2537
2538 (@__fill_strip_defaults
2539 frame_alias: $frame_alias:tt,
2540 pio: $pio:ident,
2541 vis: $vis:vis,
2542 sm_counter: $sm:tt,
2543 strips_out: [ $($out:tt)* ],
2544 strips_remaining: [ $($remaining:tt)* ],
2545 label: $label:ident,
2546 group: $group:ident,
2547 pin: $pin:ident,
2548 dma: $dma:ident,
2549 len: $len:expr,
2550 max_current: __MISSING_MAX_CURRENT__,
2551 gamma: $gamma:expr,
2552 max_frames: $max_frames:expr,
2553 led2d: __HAS_LED2D__ { $($led2d_fields:tt)* },
2554 fields: []
2555 ) => {
2556 compile_error!("led_strips!: max_current is required for every strip");
2557 };
2558
2559 (@__fill_strip_defaults
2560 frame_alias: $frame_alias:tt,
2561 pio: $pio:ident,
2562 vis: $vis:vis,
2563 sm_counter: $sm:tt,
2564 strips_out: [ $($out:tt)* ],
2565 strips_remaining: [ $($remaining:tt)* ],
2566 label: $label:ident,
2567 group: $group:ident,
2568 pin: $pin:ident,
2569 dma: $dma:ident,
2570 len: $len:expr,
2571 max_current: $max_current:expr,
2572 gamma: $gamma:expr,
2573 max_frames: $max_frames:expr,
2574 led2d: __NONE__,
2575 fields: []
2576 ) => {
2577 $crate::__led_strips_impl! {
2578 @__inc_counter
2579 frame_alias: $frame_alias,
2580 pio: $pio,
2581 vis: $vis,
2582 group: $group,
2583 sm: $sm,
2584 strips_out: [
2585 $($out)*
2586 $label {
2587 sm: $sm,
2588 dma: $dma,
2589 pin: $pin,
2590 len: $len,
2591 max_current: $max_current,
2592 gamma: $gamma,
2593 max_frames: $max_frames
2594 },
2595 ],
2596 strips_in: [ $($remaining)* ]
2597 }
2598 };
2599
2600 (@__fill_strip_defaults
2601 frame_alias: $frame_alias:tt,
2602 pio: $pio:ident,
2603 vis: $vis:vis,
2604 sm_counter: $sm:tt,
2605 strips_out: [ $($out:tt)* ],
2606 strips_remaining: [ $($remaining:tt)* ],
2607 label: $label:ident,
2608 group: $group:ident,
2609 pin: $pin:ident,
2610 dma: $dma:ident,
2611 len: $len:expr,
2612 max_current: $max_current:expr,
2613 gamma: $gamma:expr,
2614 max_frames: $max_frames:expr,
2615 led2d: __HAS_LED2D__ { $($led2d_fields:tt)* },
2616 fields: []
2617 ) => {
2618 $crate::__led_strips_impl! {
2619 @__inc_counter
2620 frame_alias: $frame_alias,
2621 pio: $pio,
2622 vis: $vis,
2623 group: $group,
2624 sm: $sm,
2625 strips_out: [
2626 $($out)*
2627 $label {
2628 sm: $sm,
2629 dma: $dma,
2630 pin: $pin,
2631 len: $len,
2632 max_current: $max_current,
2633 gamma: $gamma,
2634 max_frames: $max_frames,
2635 led2d: { $($led2d_fields)* }
2636 },
2637 ],
2638 strips_in: [ $($remaining)* ]
2639 }
2640 };
2641 (@__inc_counter frame_alias: $frame_alias:tt, pio: $pio:ident, vis: $vis:vis, group: $group:ident, sm: 0, strips_out: [$($out:tt)*], strips_in: [$($in:tt)*]) => {
2643 $crate::__led_strips_impl! { @__with_defaults frame_alias: $frame_alias, pio: $pio, vis: $vis, group: $group, sm_counter: 1, strips_out: [$($out)*], strips_in: [$($in)*] }
2644 };
2645 (@__inc_counter frame_alias: $frame_alias:tt, pio: $pio:ident, vis: $vis:vis, group: $group:ident, sm: 1, strips_out: [$($out:tt)*], strips_in: [$($in:tt)*]) => {
2646 $crate::__led_strips_impl! { @__with_defaults frame_alias: $frame_alias, pio: $pio, vis: $vis, group: $group, sm_counter: 2, strips_out: [$($out)*], strips_in: [$($in)*] }
2647 };
2648 (@__inc_counter frame_alias: $frame_alias:tt, pio: $pio:ident, vis: $vis:vis, group: $group:ident, sm: 2, strips_out: [$($out:tt)*], strips_in: [$($in:tt)*]) => {
2649 $crate::__led_strips_impl! { @__with_defaults frame_alias: $frame_alias, pio: $pio, vis: $vis, group: $group, sm_counter: 3, strips_out: [$($out)*], strips_in: [$($in)*] }
2650 };
2651 (@__inc_counter frame_alias: $frame_alias:tt, pio: $pio:ident, vis: $vis:vis, group: $group:ident, sm: 3, strips_out: [$($out:tt)*], strips_in: [$($in:tt)*]) => {
2652 $crate::__led_strips_impl! { @__with_defaults frame_alias: $frame_alias, pio: $pio, vis: $vis, group: $group, sm_counter: 4, strips_out: [$($out)*], strips_in: [$($in)*] }
2653 };
2654}
2655
2656#[doc = include_str!("docs/current_limiting_and_gamma.md")]
2693#[cfg(not(feature = "host"))]
2700#[doc(hidden)]
2701#[macro_export]
2702macro_rules! led_strip {
2703 ($($tt:tt)*) => { $crate::__led_strip_impl! { $($tt)* } };
2704}
2705
2706#[cfg(not(feature = "host"))]
2708#[doc(hidden)]
2709#[macro_export]
2710macro_rules! __led_strip_impl {
2711 (
2713 $name:ident {
2714 $($fields:tt)*
2715 }
2716 ) => {
2717 $crate::__led_strip_impl! {
2718 @__fill_defaults
2719 vis: pub(self),
2720 pio: PIO0,
2721 name: $name,
2722 pin: _UNSET_,
2723 dma: DMA_CH0,
2724 len: _UNSET_,
2725 max_current: _UNSET_,
2726 gamma: $crate::led_strip::GAMMA_DEFAULT,
2727 max_frames: $crate::led_strip::MAX_FRAMES_DEFAULT,
2728 fields: [ $($fields)* ]
2729 }
2730 };
2731
2732 (
2734 $vis:vis $name:ident {
2735 $($fields:tt)*
2736 }
2737 ) => {
2738 $crate::__led_strip_impl! {
2739 @__fill_defaults
2740 vis: $vis,
2741 pio: PIO0,
2742 name: $name,
2743 pin: _UNSET_,
2744 dma: DMA_CH0,
2745 len: _UNSET_,
2746 max_current: _UNSET_,
2747 gamma: $crate::led_strip::GAMMA_DEFAULT,
2748 max_frames: $crate::led_strip::MAX_FRAMES_DEFAULT,
2749 fields: [ $($fields)* ]
2750 }
2751 };
2752
2753 (@__fill_defaults
2755 vis: $vis:vis,
2756 pio: $pio:ident,
2757 name: $name:ident,
2758 pin: $pin:tt,
2759 dma: $dma:ident,
2760 len: $len:tt,
2761 max_current: $max_current:tt,
2762 gamma: $gamma:expr,
2763 max_frames: $max_frames:expr,
2764 fields: [ pio: $new_pio:ident $(, $($rest:tt)* )? ]
2765 ) => {
2766 $crate::__led_strip_impl! {
2767 @__fill_defaults
2768 vis: $vis,
2769 pio: $new_pio,
2770 name: $name,
2771 pin: $pin,
2772 dma: $dma,
2773 len: $len,
2774 max_current: $max_current,
2775 gamma: $gamma,
2776 max_frames: $max_frames,
2777 fields: [ $($($rest)*)? ]
2778 }
2779 };
2780
2781 (@__fill_defaults
2783 vis: $vis:vis,
2784 pio: $pio:ident,
2785 name: $name:ident,
2786 pin: $pin:tt,
2787 dma: $dma:ident,
2788 len: $len:tt,
2789 max_current: $max_current:tt,
2790 gamma: $gamma:expr,
2791 max_frames: $max_frames:expr,
2792 fields: [ pin: $new_pin:ident $(, $($rest:tt)* )? ]
2793 ) => {
2794 $crate::__led_strip_impl! {
2795 @__fill_defaults
2796 vis: $vis,
2797 pio: $pio,
2798 name: $name,
2799 pin: $new_pin,
2800 dma: $dma,
2801 len: $len,
2802 max_current: $max_current,
2803 gamma: $gamma,
2804 max_frames: $max_frames,
2805 fields: [ $($($rest)*)? ]
2806 }
2807 };
2808
2809 (@__fill_defaults
2811 vis: $vis:vis,
2812 pio: $pio:ident,
2813 name: $name:ident,
2814 pin: $pin:tt,
2815 dma: $dma:ident,
2816 len: $len:tt,
2817 max_current: $max_current:tt,
2818 gamma: $gamma:expr,
2819 max_frames: $max_frames:expr,
2820 fields: [ dma: $new_dma:ident $(, $($rest:tt)* )? ]
2821 ) => {
2822 $crate::__led_strip_impl! {
2823 @__fill_defaults
2824 vis: $vis,
2825 pio: $pio,
2826 name: $name,
2827 pin: $pin,
2828 dma: $new_dma,
2829 len: $len,
2830 max_current: $max_current,
2831 gamma: $gamma,
2832 max_frames: $max_frames,
2833 fields: [ $($($rest)*)? ]
2834 }
2835 };
2836
2837 (@__fill_defaults
2839 vis: $vis:vis,
2840 pio: $pio:ident,
2841 name: $name:ident,
2842 pin: $pin:tt,
2843 dma: $dma:ident,
2844 len: $len:tt,
2845 max_current: $max_current:tt,
2846 gamma: $gamma:expr,
2847 max_frames: $max_frames:expr,
2848 fields: [ len: { $new_len:expr } $(, $($rest:tt)* )? ]
2849 ) => {
2850 $crate::__led_strip_impl! {
2851 @__fill_defaults
2852 vis: $vis,
2853 pio: $pio,
2854 name: $name,
2855 pin: $pin,
2856 dma: $dma,
2857 len: { $new_len },
2858 max_current: $max_current,
2859 gamma: $gamma,
2860 max_frames: $max_frames,
2861 fields: [ $($($rest)*)? ]
2862 }
2863 };
2864
2865 (@__fill_defaults
2867 vis: $vis:vis,
2868 pio: $pio:ident,
2869 name: $name:ident,
2870 pin: $pin:tt,
2871 dma: $dma:ident,
2872 len: $len:tt,
2873 max_current: $max_current:tt,
2874 gamma: $gamma:expr,
2875 max_frames: $max_frames:expr,
2876 fields: [ len: $new_len:expr $(, $($rest:tt)* )? ]
2877 ) => {
2878 $crate::__led_strip_impl! {
2879 @__fill_defaults
2880 vis: $vis,
2881 pio: $pio,
2882 name: $name,
2883 pin: $pin,
2884 dma: $dma,
2885 len: $new_len,
2886 max_current: $max_current,
2887 gamma: $gamma,
2888 max_frames: $max_frames,
2889 fields: [ $($($rest)*)? ]
2890 }
2891 };
2892
2893 (@__fill_defaults
2895 vis: $vis:vis,
2896 pio: $pio:ident,
2897 name: $name:ident,
2898 pin: $pin:tt,
2899 dma: $dma:ident,
2900 len: $len:tt,
2901 max_current: $max_current:tt,
2902 gamma: $gamma:expr,
2903 max_frames: $max_frames:expr,
2904 fields: [ max_current: $new_max_current:expr $(, $($rest:tt)* )? ]
2905 ) => {
2906 $crate::__led_strip_impl! {
2907 @__fill_defaults
2908 vis: $vis,
2909 pio: $pio,
2910 name: $name,
2911 pin: $pin,
2912 dma: $dma,
2913 len: $len,
2914 max_current: $new_max_current,
2915 gamma: $gamma,
2916 max_frames: $max_frames,
2917 fields: [ $($($rest)*)? ]
2918 }
2919 };
2920
2921 (@__fill_defaults
2923 vis: $vis:vis,
2924 pio: $pio:ident,
2925 name: $name:ident,
2926 pin: $pin:tt,
2927 dma: $dma:ident,
2928 len: $len:tt,
2929 max_current: $max_current:tt,
2930 gamma: $gamma:expr,
2931 max_frames: $max_frames:expr,
2932 fields: [ gamma: $new_gamma:expr $(, $($rest:tt)* )? ]
2933 ) => {
2934 $crate::__led_strip_impl! {
2935 @__fill_defaults
2936 vis: $vis,
2937 pio: $pio,
2938 name: $name,
2939 pin: $pin,
2940 dma: $dma,
2941 len: $len,
2942 max_current: $max_current,
2943 gamma: $new_gamma,
2944 max_frames: $max_frames,
2945 fields: [ $($($rest)*)? ]
2946 }
2947 };
2948
2949 (@__fill_defaults
2951 vis: $vis:vis,
2952 pio: $pio:ident,
2953 name: $name:ident,
2954 pin: $pin:tt,
2955 dma: $dma:ident,
2956 len: $len:tt,
2957 max_current: $max_current:tt,
2958 gamma: $gamma:expr,
2959 max_frames: $max_frames:expr,
2960 fields: [ max_frames: $new_max_frames:expr $(, $($rest:tt)* )? ]
2961 ) => {
2962 $crate::__led_strip_impl! {
2963 @__fill_defaults
2964 vis: $vis,
2965 pio: $pio,
2966 name: $name,
2967 pin: $pin,
2968 dma: $dma,
2969 len: $len,
2970 max_current: $max_current,
2971 gamma: $gamma,
2972 max_frames: $new_max_frames,
2973 fields: [ $($($rest)*)? ]
2974 }
2975 };
2976
2977 (@__fill_defaults
2979 vis: $vis:vis,
2980 pio: $pio:ident,
2981 name: $name:ident,
2982 pin: $pin:ident,
2983 dma: $dma:ident,
2984 len: $len:expr,
2985 max_current: _UNSET_,
2986 gamma: $gamma:expr,
2987 max_frames: $max_frames:expr,
2988 fields: []
2989 ) => {
2990 $crate::__led_strip_impl! {
2991 @__fill_defaults
2992 vis: $vis,
2993 pio: $pio,
2994 name: $name,
2995 pin: $pin,
2996 dma: $dma,
2997 len: $len,
2998 max_current: $crate::led_strip::MAX_CURRENT_DEFAULT,
2999 gamma: $gamma,
3000 max_frames: $max_frames,
3001 fields: []
3002 }
3003 };
3004
3005 (@__fill_defaults
3007 vis: $vis:vis,
3008 pio: $pio:ident,
3009 name: $name:ident,
3010 pin: $pin:ident,
3011 dma: $dma:ident,
3012 len: $len:expr,
3013 max_current: $max_current:expr,
3014 gamma: $gamma:expr,
3015 max_frames: $max_frames:expr,
3016 fields: []
3017 ) => {
3018 ::paste::paste! {
3019 #[allow(non_upper_case_globals)]
3021 static [<$name:snake _ $pio _BUS>]: ::static_cell::StaticCell<
3022 $crate::led_strip::PioBus<'static, ::embassy_rp::peripherals::$pio>
3023 > = ::static_cell::StaticCell::new();
3024
3025 #[allow(dead_code)]
3029 fn [<$name:snake _split_sm0>](
3030 pio: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pio>,
3031 ) -> $crate::led_strip::PioBusStateMachine<::embassy_rp::peripherals::$pio, 0> {
3032 let ::embassy_rp::pio::Pio { common, sm0, .. } =
3033 ::embassy_rp::pio::Pio::new(
3034 pio,
3035 <::embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
3036 );
3037 let pio_bus = [<$name:snake _ $pio _BUS>].init_with(|| {
3038 $crate::led_strip::PioBus::new(common)
3039 });
3040 $crate::led_strip::PioBusStateMachine::new(pio_bus, sm0)
3041 }
3042
3043 #[doc = concat!(
3044 "LED strip generated by [`led_strip!`] or [`led_strips!`](crate::led_strips!).\n\n",
3045 "See the [led_strip module documentation](mod@crate::led_strip) for usage and examples."
3046 )]
3047 $vis struct $name {
3048 strip: $crate::led_strip::LedStrip<{ $len }, { $max_frames }>,
3049 }
3050
3051 impl $name {
3052 pub const LEN: usize = $len;
3054 pub const MAX_FRAMES: usize = $max_frames;
3056
3057 const WORST_CASE_MA: u32 = ($len as u32) * 60;
3059 pub const MAX_BRIGHTNESS: u8 =
3062 $max_current.max_brightness(Self::WORST_CASE_MA);
3063
3064 const COMBO_TABLE: [u8; 256] = $crate::led_strip::generate_combo_table($gamma, Self::MAX_BRIGHTNESS);
3066
3067 pub fn new(
3086 pin: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>>,
3087 pio: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pio>,
3088 dma: impl Into<::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>>,
3089 spawner: ::embassy_executor::Spawner,
3090 ) -> $crate::Result<&'static Self> {
3091 static STRIP_STATIC: $crate::led_strip::LedStripStatic<{ $len }, { $max_frames }> =
3092 $crate::led_strip::LedStrip::new_static();
3093 static STRIP_CELL: ::static_cell::StaticCell<$name> = ::static_cell::StaticCell::new();
3094
3095 let pin = pin.into();
3096 let dma = dma.into();
3097
3098 let sm0 = [<$name:snake _split_sm0>](pio);
3099 let (bus, sm) = sm0.into_parts();
3100
3101 let token = [<$name:snake _device_task>](
3102 bus,
3103 sm,
3104 dma,
3105 pin,
3106 STRIP_STATIC.command_signal(),
3107 );
3108 spawner.spawn(token).map_err($crate::Error::TaskSpawn)?;
3109
3110 let strip = $crate::led_strip::LedStrip::new(&STRIP_STATIC)?;
3111 let instance = STRIP_CELL.init($name { strip });
3112 Ok(instance)
3113 }
3114 }
3115
3116 impl ::core::ops::Deref for $name {
3117 type Target = $crate::led_strip::LedStrip<{ $len }, { $max_frames }>;
3118
3119 fn deref(&self) -> &Self::Target {
3120 &self.strip
3121 }
3122 }
3123
3124 #[cfg(not(feature = "host"))]
3125 impl AsRef<$crate::led_strip::LedStrip<{ $len }, { $max_frames }>> for $name {
3126 fn as_ref(&self) -> &$crate::led_strip::LedStrip<{ $len }, { $max_frames }> {
3127 &self.strip
3128 }
3129 }
3130
3131 #[::embassy_executor::task]
3132 async fn [<$name:snake _device_task>](
3133 bus: &'static $crate::led_strip::PioBus<'static, ::embassy_rp::peripherals::$pio>,
3134 sm: ::embassy_rp::pio::StateMachine<'static, ::embassy_rp::peripherals::$pio, 0>,
3135 dma: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$dma>,
3136 pin: ::embassy_rp::Peri<'static, ::embassy_rp::peripherals::$pin>,
3137 command_signal: &'static $crate::led_strip::LedStripCommandSignal<{ $len }, { $max_frames }>,
3138 ) -> ! {
3139 let program = bus.get_program();
3140 let driver = bus.with_common(|common| {
3141 ::embassy_rp::pio_programs::ws2812::PioWs2812::<
3142 ::embassy_rp::peripherals::$pio,
3143 0,
3144 { $len },
3145 _
3146 >::new(common, sm, dma, pin, program)
3147 });
3148 $crate::led_strip::led_strip_device_loop
3149 ::<
3150 ::embassy_rp::peripherals::$pio,
3151 0,
3152 { $len },
3153 { $max_frames },
3154 _
3155 >(driver, command_signal, &$name::COMBO_TABLE).await
3156 }
3157 }
3158 };
3159}
3160
3161#[doc(hidden)]
3165#[cfg(not(feature = "host"))]
3166#[macro_export]
3167macro_rules! pio_split {
3168 ($p:ident . PIO0) => {
3169 pio0_split($p.PIO0)
3170 };
3171 ($p:ident . PIO1) => {
3172 pio1_split($p.PIO1)
3173 };
3174 ($p:ident . PIO2) => {
3175 pio2_split($p.PIO2)
3176 };
3177}
3178
3179#[cfg(not(feature = "host"))]
3180pub use pio_split;
3181
3182#[cfg(not(feature = "host"))]
3183#[doc(inline)]
3184pub use led_strip;
3185#[cfg(not(feature = "host"))]
3186#[doc(inline)]
3187pub use led_strips;
3188
3189#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3194pub enum Current {
3195 Milliamps(u16),
3205 Unlimited,
3211}
3212
3213impl Default for Current {
3214 fn default() -> Self {
3215 Self::Milliamps(250)
3216 }
3217}
3218
3219#[doc(hidden)]
3221pub const MAX_CURRENT_DEFAULT: Current = Current::Milliamps(250);
3223
3224#[doc(hidden)]
3226pub const MAX_FRAMES_DEFAULT: usize = 16;
3228
3229impl Current {
3230 #[doc(hidden)] #[must_use]
3235 pub const fn max_brightness(self, worst_case_ma: u32) -> u8 {
3236 assert!(worst_case_ma > 0, "worst_case_ma must be positive");
3237 match self {
3238 Self::Milliamps(ma) => {
3239 let scale = (ma as u32 * 255) / worst_case_ma;
3240 if scale > 255 { 255 } else { scale as u8 }
3241 }
3242 Self::Unlimited => 255,
3243 }
3244 }
3245}