Skip to main content

display_driver/panel/
initseq.rs

1use embedded_hal_async::delay::DelayNs;
2
3use crate::DisplayBus;
4
5/// A step in the initialization sequence.
6#[derive(Clone, Copy)]
7pub enum InitStep<'a> {
8    /// Single byte command.
9    SingleCommand(u8),
10    /// Command with parameters.
11    CommandWithParams(u8, &'a [u8]),
12    /// Delay in milliseconds.
13    DelayMs(u8),
14    /// No Operation. Useful for placeholders or conditional logic.
15    Nop,
16    /// Nested sequence.
17    /// 
18    /// NOTE: Only supports one level of nesting (cannot nest a Nested inside a Nested)
19    /// to avoid recursion issues in async no_std environments.
20    Nested(&'a [InitStep<'a>]),
21}
22
23impl InitStep<'static> {
24    pub const fn maybe_cmd(cmd: Option<u8>) -> Self {
25        match cmd {
26            Some(cmd) => Self::SingleCommand(cmd),
27            None => Self::Nop,
28        }
29    }
30
31    pub const fn cmd_if(cond: bool, cmd: u8) -> Self {
32        Self::SingleCommand(if cond { cmd } else { 0 })
33    }
34
35    pub const fn cmd_if_with<const N: usize>(
36        cond: bool,
37        cmd: u8,
38        params: &'static [u8; N],
39    ) -> Self {
40        Self::CommandWithParams(if cond { cmd } else { 0 }, params)
41    }
42
43    pub const fn maybe_cmd_with<const N: usize>(cmd: u8, params: Option<&'static [u8; N]>) -> Self {
44        match params {
45            Some(p) => Self::CommandWithParams(cmd, p),
46            None => Self::Nop,
47        }
48    }
49
50    pub const fn select_cmd(cond: bool, cmd_true: u8, cmd_false: u8) -> Self {
51        Self::SingleCommand(if cond { cmd_true } else { cmd_false })
52    }
53}
54
55/// Helper to execute initialization steps.
56pub struct SequencedInit<'a, D: DelayNs, B: DisplayBus, I: Iterator<Item = InitStep<'a>>> {
57    steps: I,
58    delay: &'a mut D,
59    display_bus: &'a mut B,
60}
61
62impl<'a, D: DelayNs, B: DisplayBus, I: Iterator<Item = InitStep<'a>>> SequencedInit<'a, D, B, I> {
63    /// Creates a new SequencedInit instance.
64    pub fn new(steps: I, delay: &'a mut D, display_bus: &'a mut B) -> Self {
65        Self {
66            steps,
67            delay,
68            display_bus,
69        }
70    }
71
72    /// Helper function to execute a single atomic step.
73    /// Does not handle recursion; ignores Nested variants if passed directly.
74    async fn exec_atomic_step(&mut self, step: InitStep<'a>) -> Result<(), B::Error> {
75        match step {
76            InitStep::SingleCommand(cmd) => self.display_bus.write_cmd(&[cmd]).await,
77            InitStep::CommandWithParams(cmd, data) => {
78                self.display_bus.write_cmd_with_params(&[cmd], data).await
79            }
80            InitStep::DelayMs(ms) => {
81                self.delay.delay_ms(ms as u32).await;
82                Ok(())
83            }
84            InitStep::Nop => Ok(()),
85            InitStep::Nested(_) => {
86                panic!("We only support 1 level in InitStep.");
87            }
88        }
89    }
90
91    /// Executes the initialization sequence.
92    pub async fn sequenced_init(&mut self) -> Result<(), B::Error> {
93        while let Some(step) = self.steps.next() {
94            match step {
95                // If the step is a Nested sequence, unroll it here (1 level deep)
96                InitStep::Nested(sub_steps) => {
97                    for sub_step in sub_steps.iter() {
98                        // We use *sub_step because we derived Copy
99                        self.exec_atomic_step(*sub_step).await?;
100                    }
101                }
102                // Otherwise, execute the step directly
103                _ => self.exec_atomic_step(step).await?,
104            }
105        }
106
107        Ok(())
108    }
109}
110
111/// Convenience function to run an initialization sequence.
112pub async fn sequenced_init<'a, D: DelayNs, B: DisplayBus, I: Iterator<Item = InitStep<'a>>>(
113    steps: I,
114    delay: &'a mut D,
115    display_bus: &'a mut B,
116) -> Result<(), B::Error> {
117    SequencedInit::new(steps, delay, display_bus)
118        .sequenced_init()
119        .await
120}