1use crate::command_structs::*;
16use crate::spi::{DcxPin, Read, ReadBits as _, WriteU8, WriteU8s};
17
18#[derive(Debug)]
21pub struct Commands<S> { spi: S }
22
23impl<S: DcxPin> Commands<S> {
24 pub fn new(mut spi: S) -> Self {
26 spi.set_dcx_command_mode();
27 Self{spi}
28 }
29}
30
31impl<S> Commands<S> where S: DcxPin,
32 for<'a> S: WriteU8<'a> + WriteU8s<'a> {
33 #[inline(always)]
35 pub async fn caset(&mut self, begin: u16, end: u16) {
36 self.command_with_u16_pair(0x2A, begin, end).await;
37 }
38
39 #[inline(always)]
41 pub async fn raset(&mut self, begin: u16, end: u16) {
42 self.command_with_u16_pair(0x2B, begin, end).await;
43 }
44
45 #[inline(always)]
48 pub async fn ramwr(&mut self) -> RamWriter<'_, S> {
49 self.command(0x2C).await;
50 self.spi.set_dcx_data_mode();
51 RamWriter{spi: &mut self.spi}
53 }
54
55 #[inline(always)]
66 pub async fn rgbset(&mut self) -> RamWriter<'_, S> {
67 self.command(0x2D).await;
68 self.spi.set_dcx_data_mode();
69 RamWriter{spi: &mut self.spi}
71 }
72
73 #[inline(always)]
76 pub async fn ptlar(&mut self, begin: u16, end: u16) {
77 self.command_with_u16_pair(0x30, begin, end).await;
78 }
79
80 #[inline(always)]
82 pub async fn scrlar(&mut self, top: u16, visible: u16, bottom: u16) {
83 let data = [
84 (top >> 8) as u8, (top & 0xFF) as u8,
85 (visible >> 8) as u8, (visible & 0xFF) as u8,
86 (bottom >> 8) as u8, (bottom & 0xFF) as u8,
87 ];
88 self.command_with_u8s(0x33, &data).await;
89 }
90
91 async fn command_with_u16_pair(
93 &mut self, cmd: u8, first: u16, second: u16) {
94 self.command(cmd).await;
95 self.spi.set_dcx_data_mode();
96 let data = [(first >> 8) as u8, (first & 0xFF) as u8,
97 (second >> 8) as u8, (second & 0xFF) as u8];
98 self.spi.write_u8s(&data).await;
99 self.spi.set_dcx_command_mode();
100 }
101
102 #[inline(always)]
103 async fn command_with_u8s(&mut self, cmd: u8, data: &[u8]) {
104 self.spi.write_u8(cmd).await;
105 self.spi.set_dcx_data_mode();
106 self.spi.write_u8s(data).await;
107 self.spi.set_dcx_command_mode();
108 }
109
110 #[inline(always)]
111 async fn command(&mut self, cmd: u8) {
112 self.spi.write_u8(cmd).await;
113 }
114
115 async fn command_with_u8(&mut self, cmd: u8, data: u8) {
116 self.command(cmd).await;
117 self.spi.set_dcx_data_mode();
118 self.spi.write_u8(data).await;
119 self.spi.set_dcx_command_mode();
120 }
121
122 #[inline(always)]
124 pub async fn nop(&mut self) { self.command(0x00).await; }
125 #[inline(always)]
127 pub async fn swreset(&mut self) { self.command(0x01).await; }
128 #[inline(always)]
130 pub async fn slpin(&mut self) { self.command(0x10).await; }
131 #[inline(always)]
133 pub async fn slpout(&mut self) { self.command(0x11).await; }
134 #[inline(always)]
136 pub async fn ptlon(&mut self) { self.command(0x12).await; }
137 #[inline(always)]
139 pub async fn noron(&mut self) { self.command(0x13).await; }
140 #[inline(always)]
142 pub async fn invoff(&mut self) { self.command(0x20).await; }
143 #[inline(always)]
145 pub async fn invon(&mut self) { self.command(0x21).await; }
146 #[inline(always)]
149 pub async fn dispoff(&mut self) { self.command(0x28).await; }
150 #[inline(always)]
152 pub async fn dispon(&mut self) { self.command(0x29).await; }
153 #[inline(always)]
155 pub async fn teoff(&mut self) { self.command(0x34).await; }
156 #[inline(always)]
158 pub async fn teon(&mut self, te_mode: bool) {
159 self.command_with_u8(0x35, if te_mode {1} else {0}).await; }
160 #[inline(always)]
162 pub async fn madctl(&mut self, data: Madctl) {
163 self.command_with_u8(0x36, data.into()).await; }
164 #[inline(always)]
167 pub async fn idmoff(&mut self) { self.command(0x38).await; }
168 #[inline(always)]
170 pub async fn idmon(&mut self) { self.command(0x39).await; }
171 #[inline(always)]
174 pub async fn colmod(&mut self, data: Colmod) {
175 self.command_with_u8(0x3A, data.into()).await; }
176
177 }
179
180#[derive(Debug)]
182pub struct RamWriter<'s, S: DcxPin> { spi: &'s mut S }
183
184impl<'s, S: DcxPin> Drop for RamWriter<'s, S> {
185 fn drop(&mut self) { self.spi.set_dcx_command_mode(); }
186}
187
188impl<'a, 's, S: DcxPin + WriteU8<'a>> WriteU8<'a> for RamWriter<'s, S> {
189 type WriteU8Done = <S as WriteU8<'a>>::WriteU8Done;
190
191 fn write_u8(&'a mut self, data: u8) -> Self::WriteU8Done {
192 self.spi.write_u8(data)
193 }
194}
195
196impl<'a, 's, S: DcxPin + WriteU8s<'a>> WriteU8s<'a> for RamWriter<'s, S> {
197 type WriteU8sDone = <S as WriteU8s<'a>>::WriteU8sDone;
198
199 fn write_u8s(&'a mut self, data: &'a [u8]) -> Self::WriteU8sDone {
200 self.spi.write_u8s(data)
201 }
202}
203
204impl<S> Commands<S> where S: DcxPin,
205 for<'a> S: WriteU8<'a> + Read<'a> {
206 async fn read_command(&mut self, cmd: u8, num_bits: usize) -> u32 {
207 self.spi.write_u8(cmd).await;
208 let mut r = self.spi.start_reading();
209 r.read_bits(num_bits).await
210 }
211
212 #[inline(always)]
217 pub async fn rddid(&mut self) -> [u8; 3] {
218 let r = self.read_command(0x04, 25).await;
219 [(r >> 16) as u8, (r >> 8 & 0xFF) as u8, (r & 0xFF) as u8]
220 }
221
222 #[inline(always)]
225 pub async fn rdid1(&mut self) -> u8 {
226 self.read_command(0xDA, 8).await as u8
227 }
228
229 #[inline(always)]
232 pub async fn rdid2(&mut self) -> u8 {
233 self.read_command(0xDB, 8).await as u8
234 }
235
236 #[inline(always)]
238 pub async fn rdid3(&mut self) -> u8 {
239 self.read_command(0xDC, 8).await as u8
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use mockall::{predicate, Sequence};
246
247 use crate::testing_device::{block_on, MockDevice, MockPlainIO};
248 use super::*;
249
250 macro_rules! test_simple_write_with_name {
251 ($name:tt, $fn:tt $args:tt, code: $code:expr, data: $data:expr) => {
252 #[test]
253 fn $name() {
254 let mut cmds = create_mock();
255 cmds.spi.expect_standard_write_command($code, $data);
256 block_on(cmds.$fn$args);
257 }
258 };
259 }
260 macro_rules! test_simple_write {
261 ($fn:tt $args:tt, code: $code:expr, data: $data:expr) => {
262 test_simple_write_with_name!(
263 $fn, $fn $args, code: $code, data: $data);
264 };
265 }
266
267 test_simple_write!(nop(), code: 0x00, data: &[]);
268 test_simple_write!(swreset(), code: 0x01, data: &[]);
269 test_simple_write!(slpin(), code: 0x10, data: &[]);
270 test_simple_write!(slpout(), code: 0x11, data: &[]);
271 test_simple_write!(ptlon(), code: 0x12, data: &[]);
272 test_simple_write!(noron(), code: 0x13, data: &[]);
273 test_simple_write!(invoff(), code: 0x20, data: &[]);
274 test_simple_write!(invon(), code: 0x21, data: &[]);
275 test_simple_write!(dispoff(), code: 0x28, data: &[]);
277 test_simple_write!(dispon(), code: 0x29, data: &[]);
278 test_simple_write!(caset(0x1234, 0x5678), code: 0x2A,
279 data: &[0x12, 0x34, 0x56, 0x78]);
280 test_simple_write!(raset(0x9876, 0x5432), code: 0x2B,
281 data: &[0x98, 0x76, 0x54, 0x32]);
282 #[test]
283 fn ramwr() {
284 let mut cmds = create_mock();
285 cmds.spi.expect_standard_write_command(
286 0x2C, &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD]);
287 block_on(async {
288 let mut rw = cmds.ramwr().await;
289 rw.write_u8(0x01).await;
290 rw.write_u8s(&[0x23, 0x45]).await;
291 rw.write_u8s(&[]).await;
292 rw.write_u8s(&[0x67, 0x89, 0xAB, 0xCD]).await;
293 });
294 }
295 #[test]
296 fn rgbset() {
297 let mut cmds = create_mock();
298 cmds.spi.expect_standard_write_command(0x2D, &[0x35; 128]);
299 block_on(async {
300 let mut rw = cmds.rgbset().await;
301 rw.write_u8(0x35).await;
302 rw.write_u8s(&[0x35; 27]).await;
303 rw.write_u8s(&[0x35; 50]).await;
304 rw.write_u8s(&[0x35; 50]).await;
305 });
306 }
307 test_simple_write!(ptlar(0x1357, 0x2468), code: 0x30,
308 data: &[0x13, 0x57, 0x24, 0x68]);
309 test_simple_write!(scrlar(0x2143, 0x3254, 0x4365), code: 0x33,
310 data: &[0x21, 0x43, 0x32, 0x54, 0x43, 0x65]);
311 test_simple_write!(teoff(), code: 0x34, data: &[]);
312 #[test]
313 fn teon_mode0() {
314 let mut cmds = create_mock();
315 cmds.spi.expect_standard_write_command(0x35, &[0x00]);
316 block_on(cmds.teon(false));
317 }
318 #[test]
319 fn teon_mode1() {
320 let mut cmds = create_mock();
321 cmds.spi.expect_standard_write_command(0x35, &[0x01]);
322 block_on(cmds.teon(true));
323 }
324 #[test]
325 fn madctl_test0() {
326 use crate::command_structs::{
327 Madctl, RowOrder, ColumnOrder, RowColumnSwap, ColorComponentOrder};
328 let mut mctl = Madctl::default();
329 mctl.set_row_address_order(RowOrder::TopToBottom)
330 .set_column_address_order(ColumnOrder::LeftToRight)
331 .set_row_column_swap(RowColumnSwap::Swapped)
332 .set_vertical_refresh_order(RowOrder::BottomToTop)
333 .set_horizontal_refresh_order(ColumnOrder::RightToLeft)
334 .set_rgb_order(ColorComponentOrder::BlueGreenRed);
335
336 let mut cmds = create_mock();
337 cmds.spi.expect_standard_write_command(0x36, &[0xC0]);
338 block_on(cmds.madctl(mctl));
339 }
340 #[test]
341 fn madctl_test1() {
342 use crate::command_structs::{
343 Madctl, RowOrder, ColumnOrder, RowColumnSwap, ColorComponentOrder};
344 let mut mctl = Madctl::default();
345 mctl.set_row_address_order(RowOrder::BottomToTop)
346 .set_column_address_order(ColumnOrder::RightToLeft)
347 .set_row_column_swap(RowColumnSwap::Unswapped)
348 .set_vertical_refresh_order(RowOrder::TopToBottom)
349 .set_horizontal_refresh_order(ColumnOrder::LeftToRight)
350 .set_rgb_order(ColorComponentOrder::RedGreenBlue);
351
352 let mut cmds = create_mock();
353 cmds.spi.expect_standard_write_command(0x36, &[0x3C]);
354 block_on(cmds.madctl(mctl));
355 }
356 test_simple_write!(idmoff(), code: 0x38, data: &[]);
358 test_simple_write!(idmon(), code: 0x39, data: &[]);
359 test_simple_write_with_name!(colmod_r4g4b4, colmod(Colmod::R4G4B4),
360 code: 0x3A, data: &[0b011]);
361 test_simple_write_with_name!(colmod_r5g6b5, colmod(Colmod::R5G6B5),
362 code: 0x3A, data: &[0b101]);
363 test_simple_write_with_name!(colmod_r6g6b6, colmod(Colmod::R6G6B6),
364 code: 0x3A, data: &[0b110]);
365
366 impl Commands<MockDevice> {
369 fn mock(&mut self) -> &mut MockPlainIO {
370 self.spi.mock()
371 }
372 }
373
374 fn create_mock() -> Commands<MockDevice> {
375 Commands::new(Default::default())
376 }
377
378 fn set_read_command_expectations(
379 mock: &mut MockPlainIO, code: u8, bits: &str) {
380 let mut seq = Sequence::new();
381 mock.expect_write_command()
382 .with(predicate::eq(code))
383 .times(1)
384 .in_sequence(&mut seq);
385 mock.expect_start_reading()
386 .times(1)
387 .in_sequence(&mut seq);
388 for c in bits.chars() {
389 mock.expect_read_bit()
390 .times(1)
391 .in_sequence(&mut seq)
392 .returning(move || c != '0');
393 }
394 mock.expect_finish_reading()
395 .times(1)
396 .in_sequence(&mut seq);
397 }
398
399 #[test]
400 fn rdid1() {
401 let mut cmds = create_mock();
402 const DATA: u8 = 0b10100110;
403 set_read_command_expectations(
404 cmds.mock(), 0xDA, &std::format!("{:08b}", DATA));
405 let v = block_on(cmds.rdid1());
406 assert_eq!(v, DATA);
407 }
408
409 #[test]
410 fn rdid2() {
411 let mut cmds = create_mock();
412 const DATA: u8 = 0b01010111;
413 set_read_command_expectations(
414 cmds.mock(), 0xDB, &std::format!("{:08b}", DATA));
415 let v = block_on(cmds.rdid2());
416 assert_eq!(v, DATA);
417 }
418
419 #[test]
420 fn rdid3() {
421 let mut cmds = create_mock();
422 const DATA: u8 = 0b01100111;
423 set_read_command_expectations(
424 cmds.mock(), 0xDC, &std::format!("{:08b}", DATA));
425 let v = block_on(cmds.rdid3());
426 assert_eq!(v, DATA);
427 }
428
429 #[test]
430 fn rddid() {
431 let mut cmds = create_mock();
432 const DATA_U32: u32 = 0b0_11110000_11010010_01100001;
433 const DATA_ARR: [u8; 3] = [0b11110000, 0b11010010, 0b01100001];
434 set_read_command_expectations(
435 cmds.mock(), 0x04, &std::format!("{:25b}", DATA_U32));
436 let v = block_on(cmds.rddid());
437 assert_eq!(v, DATA_ARR);
438 }
439
440}