il0373/
command.rs

1use crate::interface::DisplayInterface;
2
3/// Display Resolution
4#[derive(Clone, Copy)]
5pub enum DisplayResolution {
6    R96x230,
7    R96x252,
8    R128x296,
9    R160x296,
10}
11
12/// Data Polarity
13#[derive(Clone, Copy)]
14pub enum DataPolarity {
15    BWOnly,
16    RedOnly,
17    Both,
18}
19
20/// Data Interval
21#[derive(Clone, Copy)]
22pub enum DataInterval {
23    V2,
24    V3,
25    V4,
26    V5,
27    V6,
28    V7,
29    V8,
30    V9,
31    V10,
32    V11,
33    V12,
34    V13,
35    V14,
36    V15,
37    V16,
38    V17,
39}
40
41/// A command that can be issued to the controller.
42#[derive(Clone, Copy)]
43pub enum Command {
44    /// Set the panel (PSR), overwritten by ResolutionSetting (TRES)
45    PanelSetting(DisplayResolution),
46    /// Gate scanning sequence and direction (PWR)
47    PowerSetting(u8, u8, u8),
48    /// Power OFF (POF)
49    PowerOff,
50    /// Power OFF Sequence
51    /// Power ON (PON)
52    PowerOn,
53    /// Power ON Measure
54    /// Booster Soft Start (BTST)
55    BoosterSoftStart(u8, u8, u8),
56    /// Deep Sleep
57    DeepSleep,
58    /// Data Start Transmission 1 (DTM1)
59    /// Data Stop (DSP)
60    DataStop,
61    /// Display Refresh (DRF)
62    DisplayRefresh,
63    /// Data Start Transmission 2 (DTM2)
64    /// VCOM LUT (LUTC)
65    /// W2W LUT (LUTWW)
66    /// B2W LUT (LUTBW/LUTR)
67    /// B2B LUT (LUTBB/LUTB)
68    /// PLL Control (PLL)
69    PLLControl(u8),
70    /// Temperature Sensor Calibration
71    /// Temperature Sensor Enable
72    /// Temperature Sensor Write
73    /// Temperature Sensor Read
74    /// VCOM and Data Interval Setting (CDI)
75    VCOMDataIntervalSetting(u8, DataPolarity, DataInterval),
76    /// Low Power Detection
77    /// TCON Setting
78    /// ResolutionSetting (TRES). Has higher priority than (PSR)
79    ResolutionSetting(u8, u16),
80    /// Revision
81    /// Get Status
82    /// Auto Measure VCOM
83    /// VCOM Value
84    /// VCM DC Setting (VDCS)
85    VCMDCSetting(u8),
86    // Partial Window
87    // Partial In
88    // Partial Out
89    // Program Mode
90    // Active Program
91    // Read OTP Data
92    // Cascade Setting
93    // Force Temperature
94}
95
96/// Enumerates commands that can be sent to the controller that accept a slice argument buffer. This
97/// is separated from `Command` so that the lifetime parameter of the argument buffer slice does
98/// not pervade code which never invokes these two commands.
99pub enum BufCommand<'buf> {
100    /// Write to black/white RAM
101    /// 1 = White
102    /// 0 = Black
103    WriteBlackData(&'buf [u8]),
104    /// Write to red RAM
105    /// 1 = Red
106    /// 0 = Use contents of black/white RAM
107    WriteRedData(&'buf [u8]),
108}
109
110/// Populates data buffer (array) and returns a pair (tuple) with command and
111/// appropriately sized slice into populated buffer.
112/// E.g.
113///
114/// let mut buf = [0u8; 5];
115/// let (command, data) = pack!(buf, 0x3C, [0x12, 0x34]);
116macro_rules! pack {
117    ($buf:ident, $cmd:expr,[]) => {
118        ($cmd, &$buf[..0])
119    };
120    ($buf:ident, $cmd:expr,[$arg0:expr]) => {{
121        $buf[0] = $arg0;
122        ($cmd, &$buf[..1])
123    }};
124    ($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr]) => {{
125        $buf[0] = $arg0;
126        $buf[1] = $arg1;
127        ($cmd, &$buf[..2])
128    }};
129    ($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr, $arg2:expr]) => {{
130        $buf[0] = $arg0;
131        $buf[1] = $arg1;
132        $buf[2] = $arg2;
133        ($cmd, &$buf[..3])
134    }};
135    ($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr]) => {{
136        $buf[0] = $arg0;
137        $buf[1] = $arg1;
138        $buf[2] = $arg2;
139        $buf[3] = $arg3;
140        ($cmd, &$buf[..4])
141    }};
142    ($buf:ident, $cmd:expr,[$arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr]) => {{
143        $buf[0] = $arg0;
144        $buf[1] = $arg1;
145        $buf[2] = $arg2;
146        $buf[3] = $arg3;
147        $buf[4] = $arg4;
148        ($cmd, &$buf[..5])
149    }};
150}
151
152impl Command {
153    /// Execute the command, transmitting any associated data as well.
154    pub fn execute<I: DisplayInterface>(&self, interface: &mut I) -> Result<(), I::Error> {
155        use self::Command::*;
156
157        let mut buf = [0u8; 5];
158        let (command, data) = match *self {
159            PanelSetting(resolution) => {
160                let res = match resolution {
161                    self::DisplayResolution::R96x230 => 0b0000_0000,
162                    self::DisplayResolution::R96x252 => 0b0100_0000,
163                    self::DisplayResolution::R128x296 => 0b1000_0000,
164                    self::DisplayResolution::R160x296 => 0b1100_0000,
165                };
166                pack!(buf, 0x0, [res | 0b001111])
167            }
168            PowerSetting(vdh, vdl, vdhr) => {
169                debug_assert!(vdh < 64);
170                debug_assert!(vdl < 64);
171                debug_assert!(vdhr < 64);
172                pack!(buf, 0x1, [0x3, 0x0, vdh, vdl, vdhr])
173            }
174            PowerOff => {
175                pack!(buf, 0x3, [])
176            }
177            PowerOn => {
178                pack!(buf, 0x4, [])
179            }
180            BoosterSoftStart(phase_a, phase_b, phase_c) => {
181                pack!(buf, 0x6, [phase_a, phase_b, phase_c])
182            }
183            DeepSleep => {
184                pack!(buf, 0x8, [0xa5])
185            }
186            DataStop => {
187                pack!(buf, 0x11, [])
188            }
189            DisplayRefresh => {
190                pack!(buf, 0x12, [])
191            }
192            PLLControl(clock) => {
193                pack!(buf, 0x30, [clock])
194            }
195            VCOMDataIntervalSetting(border_data, data_polarity, interval) => {
196                debug_assert!(border_data < 4);
197                let vbd = border_data << 6;
198                let ddx = match data_polarity {
199                    DataPolarity::BWOnly => 0b01_0000,
200                    DataPolarity::RedOnly => 0b10_0000,
201                    DataPolarity::Both => 0b11_0000,
202                };
203                let cdi = match interval {
204                    DataInterval::V2 => 0b1111,
205                    DataInterval::V3 => 0b1110,
206                    DataInterval::V4 => 0b1101,
207                    DataInterval::V5 => 0b1100,
208                    DataInterval::V6 => 0b1011,
209                    DataInterval::V7 => 0b1010,
210                    DataInterval::V8 => 0b1001,
211                    DataInterval::V9 => 0b1000,
212                    DataInterval::V10 => 0b0111,
213                    DataInterval::V11 => 0b0110,
214                    DataInterval::V12 => 0b0101,
215                    DataInterval::V13 => 0b0100,
216                    DataInterval::V14 => 0b0011,
217                    DataInterval::V15 => 0b0010,
218                    DataInterval::V16 => 0b0001,
219                    DataInterval::V17 => 0b0000,
220                };
221                pack!(buf, 0x50, [vbd | ddx | cdi])
222            }
223            ResolutionSetting(horiz, vertical) => {
224                let vres_hi = ((vertical & 0x100) >> 8) as u8;
225                let vres_lo = (vertical & 0xFF) as u8;
226                pack!(buf, 0x61, [horiz, vres_hi, vres_lo])
227            }
228            VCMDCSetting(vcom_dc) => {
229                debug_assert!(vcom_dc <= 0b11_1010);
230                pack!(buf, 0x82, [vcom_dc])
231            }
232        };
233
234        interface.send_command(command)?;
235        if data.is_empty() {
236            Ok(())
237        } else {
238            interface.send_data(data)
239        }
240    }
241}
242
243impl<'buf> BufCommand<'buf> {
244    /// Execute the command, transmitting the associated buffer as well.
245    pub fn execute<I: DisplayInterface>(&self, interface: &mut I) -> Result<(), I::Error> {
246        use self::BufCommand::*;
247
248        let (command, data) = match self {
249            WriteBlackData(buffer) => (0x10, buffer),
250            WriteRedData(buffer) => (0x13, buffer),
251        };
252
253        interface.send_command(command)?;
254        if data.is_empty() {
255            Ok(())
256        } else {
257            interface.send_data(data)
258        }
259    }
260}
261
262#[cfg(test)]
263mod tests {
264    use super::*;
265
266    struct MockInterface {
267        data: [u8; 256],
268        offset: usize,
269    }
270
271    impl MockInterface {
272        fn new() -> Self {
273            MockInterface {
274                data: [0; 256],
275                offset: 0,
276            }
277        }
278
279        fn write(&mut self, byte: u8) {
280            self.data[self.offset] = byte;
281            self.offset += 1;
282        }
283
284        fn data(&self) -> &[u8] {
285            &self.data[0..self.offset]
286        }
287    }
288
289    impl DisplayInterface for MockInterface {
290        type Error = ();
291
292        fn send_command(&mut self, command: u8) -> Result<(), Self::Error> {
293            self.write(command);
294            Ok(())
295        }
296
297        fn send_data(&mut self, data: &[u8]) -> Result<(), Self::Error> {
298            for byte in data {
299                self.write(*byte)
300            }
301            Ok(())
302        }
303
304        fn reset<D: hal::blocking::delay::DelayMs<u8>>(&mut self, _delay: &mut D) {
305            self.data = [0; 256];
306            self.offset = 0;
307        }
308
309        fn busy_wait(&self) {
310            // nop
311        }
312
313        fn epd_update_data(
314            &mut self,
315            _layer: u8,
316            _nbytes: u16,
317            _buf: &[u8],
318        ) -> Result<(), Self::Error> {
319            Ok(())
320        }
321
322        #[cfg(feature = "sram")]
323        fn sram_read(&mut self, _address: u16, _data: &mut [u8]) -> Result<(), Self::Error> {
324            Ok(())
325        }
326
327        #[cfg(feature = "sram")]
328        fn sram_write(&mut self, _address: u16, _data: &[u8]) -> Result<(), Self::Error> {
329            Ok(())
330        }
331
332        #[cfg(feature = "sram")]
333        fn sram_clear(&mut self, _address: u16, _nbytes: u16, _val: u8) -> Result<(), Self::Error> {
334            Ok(())
335        }
336
337        #[cfg(feature = "sram")]
338        fn sram_epd_update_data(
339            &mut self,
340            _layer: u8,
341            _nbytes: u16,
342            _start_address: u16,
343        ) -> Result<(), Self::Error> {
344            Ok(())
345        }
346    }
347
348    #[test]
349    fn test_command_execute() {
350        let mut interface = MockInterface::new();
351        let b = 0xCF;
352        let command = Command::PanelSetting(DisplayResolution::R160x296);
353
354        command.execute(&mut interface).unwrap();
355        assert_eq!(interface.data(), &[0x00, b]);
356    }
357}