lcd1602_driver/sender/
parallel_sender.rs

1//! 4-pin/8-pin parallel interface driver
2
3use embedded_hal::{
4    delay::DelayNs,
5    digital::{InputPin, OutputPin, StatefulOutputPin},
6};
7
8use crate::{
9    command::{Bits, Command, ReadWriteOp, RegisterSelection, State},
10    sender::{IfReadable, SendCommand},
11    utils::{BitOps, BitState},
12};
13
14/// [`ParallelSender`] is the parallel interface to drive LCD1602
15pub struct ParallelSender<ControlPin, DBPin, BLPin, const PIN_CNT: usize, const READABLE: bool>
16where
17    ControlPin: OutputPin,
18    DBPin: OutputPin + IfReadable<READABLE>,
19    BLPin: StatefulOutputPin,
20{
21    rs_pin: ControlPin,
22    rw_pin: Option<ControlPin>,
23    en_pin: ControlPin,
24    db_pins: [DBPin; PIN_CNT],
25    bl_pin: Option<BLPin>,
26}
27
28impl<ControlPin, DBPin, BLPin> ParallelSender<ControlPin, DBPin, BLPin, 4, true>
29where
30    ControlPin: OutputPin,
31    DBPin: OutputPin + InputPin,
32    BLPin: StatefulOutputPin,
33{
34    /// Create 4-pin parallel driver, will need other 3 pins to control LCD,
35    /// and a optional pin to control backlight (better connect the pin to a transistor)
36    #[allow(clippy::too_many_arguments)]
37    pub fn new_4pin(
38        rs: ControlPin,
39        rw: ControlPin,
40        en: ControlPin,
41        db4: DBPin,
42        db5: DBPin,
43        db6: DBPin,
44        db7: DBPin,
45        bl: Option<BLPin>,
46    ) -> Self {
47        Self {
48            rs_pin: rs,
49            rw_pin: Some(rw),
50            en_pin: en,
51            db_pins: [db4, db5, db6, db7],
52            bl_pin: bl,
53        }
54    }
55}
56
57impl<ControlPin, DBPin, BLPin> ParallelSender<ControlPin, DBPin, BLPin, 4, false>
58where
59    ControlPin: OutputPin,
60    DBPin: OutputPin,
61    BLPin: StatefulOutputPin,
62{
63    /// Create 4-pin parallel driver, will need other 2 pins to control LCD,
64    /// and a optional pin to control backlight (better connect the pin to a transistor)
65    #[allow(clippy::too_many_arguments)]
66    pub fn new_4pin_write_only(
67        rs: ControlPin,
68        en: ControlPin,
69        db4: DBPin,
70        db5: DBPin,
71        db6: DBPin,
72        db7: DBPin,
73        bl: Option<BLPin>,
74    ) -> Self {
75        Self {
76            rs_pin: rs,
77            rw_pin: None,
78            en_pin: en,
79            db_pins: [db4, db5, db6, db7],
80            bl_pin: bl,
81        }
82    }
83}
84
85impl<ControlPin, DBPin, BLPin> ParallelSender<ControlPin, DBPin, BLPin, 8, true>
86where
87    ControlPin: OutputPin,
88    DBPin: OutputPin + InputPin,
89    BLPin: StatefulOutputPin,
90{
91    /// Create 8-pin parallel driver, will need other 3 pins to control LCD,
92    /// and a optional pin to control backlight (better connect the pin to a transistor)
93    #[allow(clippy::too_many_arguments)]
94    pub fn new_8pin(
95        rs: ControlPin,
96        rw: ControlPin,
97        en: ControlPin,
98        db0: DBPin,
99        db1: DBPin,
100        db2: DBPin,
101        db3: DBPin,
102        db4: DBPin,
103        db5: DBPin,
104        db6: DBPin,
105        db7: DBPin,
106        bl: Option<BLPin>,
107    ) -> Self {
108        Self {
109            rs_pin: rs,
110            rw_pin: Some(rw),
111            en_pin: en,
112            db_pins: [db0, db1, db2, db3, db4, db5, db6, db7],
113            bl_pin: bl,
114        }
115    }
116}
117
118impl<ControlPin, DBPin, BLPin> ParallelSender<ControlPin, DBPin, BLPin, 8, false>
119where
120    ControlPin: OutputPin,
121    DBPin: OutputPin,
122    BLPin: StatefulOutputPin,
123{
124    /// Create 8-pin parallel driver, will need other 2 pins to control LCD,
125    /// and a optional pin to control backlight (better connect the pin to a transistor)
126    #[allow(clippy::too_many_arguments)]
127    pub fn new_8pin_write_only(
128        rs: ControlPin,
129        en: ControlPin,
130        db0: DBPin,
131        db1: DBPin,
132        db2: DBPin,
133        db3: DBPin,
134        db4: DBPin,
135        db5: DBPin,
136        db6: DBPin,
137        db7: DBPin,
138        bl: Option<BLPin>,
139    ) -> Self {
140        Self {
141            rs_pin: rs,
142            rw_pin: None,
143            en_pin: en,
144            db_pins: [db0, db1, db2, db3, db4, db5, db6, db7],
145            bl_pin: bl,
146        }
147    }
148}
149
150// Both Read-Write and Write-Only Sender support write-to-lcd method
151impl<ControlPin, DBPin, BLPin, const PIN_CNT: usize, const READABLE: bool>
152    ParallelSender<ControlPin, DBPin, BLPin, PIN_CNT, READABLE>
153where
154    ControlPin: OutputPin,
155    DBPin: OutputPin + IfReadable<READABLE>,
156    BLPin: StatefulOutputPin,
157{
158    fn push_bits(&mut self, raw_bits: u8) {
159        self.db_pins
160            .iter_mut()
161            .enumerate()
162            .for_each(|(index, pin)| match raw_bits.check_bit(index as u8) {
163                BitState::Set => {
164                    pin.set_high().ok().unwrap();
165                }
166                BitState::Clear => {
167                    pin.set_low().ok().unwrap();
168                }
169            });
170    }
171}
172
173// Read-Write Sender also support read-from-lcd method
174impl<ControlPin, DBPin, BLPin, const PIN_CNT: usize>
175    ParallelSender<ControlPin, DBPin, BLPin, PIN_CNT, true>
176where
177    ControlPin: OutputPin,
178    DBPin: OutputPin + InputPin,
179    BLPin: StatefulOutputPin,
180{
181    fn fetch_bits(&mut self) -> u8 {
182        self.db_pins
183            .iter_mut()
184            .enumerate()
185            // use .fold() to change same value in different iteration
186            .fold(0u8, |mut acc, (index, pin)| {
187                // in open drain mode, set pin high to release control
188                pin.set_high().ok().unwrap();
189                // it's incorrect to use .get_state() here, which return what we want to put pin in, rather what pin real state
190                match pin.is_low() {
191                    Ok(val) => match val {
192                        false => acc.set_bit(index as u8),
193                        true => acc.clear_bit(index as u8),
194                    },
195                    Err(_) => panic!("Something wrong when read from pin"),
196                };
197                acc
198            })
199    }
200}
201
202macro_rules! backlight_fns {
203    () => {
204        fn get_actual_backlight(&mut self) -> State {
205            match self.bl_pin.as_mut() {
206                Some(bl_pin) => match bl_pin.is_set_high().unwrap() {
207                    true => State::On,
208                    false => State::Off,
209                },
210                None => Default::default(),
211            }
212        }
213
214        fn set_actual_backlight(&mut self, backlight: State) {
215            if let Some(bl_pin) = self.bl_pin.as_mut() {
216                match backlight {
217                    State::Off => bl_pin.set_low().unwrap(),
218                    State::On => bl_pin.set_high().unwrap(),
219                }
220            }
221        }
222    };
223}
224
225impl<ControlPin, DBPin, BLPin, const PIN_CNT: usize, Delayer> SendCommand<Delayer, true>
226    for ParallelSender<ControlPin, DBPin, BLPin, PIN_CNT, true>
227where
228    ControlPin: OutputPin,
229    DBPin: OutputPin + InputPin,
230    BLPin: StatefulOutputPin,
231    Delayer: DelayNs,
232{
233    backlight_fns!();
234
235    fn send(&mut self, command: Command) -> Option<u8> {
236        assert!(
237            PIN_CNT == 4 || PIN_CNT == 8,
238            "Pins other than 4 or 8 are not supported"
239        );
240
241        self.en_pin.set_low().ok().unwrap();
242
243        match command.get_register_selection() {
244            RegisterSelection::Command => {
245                self.rs_pin.set_low().ok().unwrap();
246            }
247            RegisterSelection::Data => {
248                self.rs_pin.set_high().ok().unwrap();
249            }
250        }
251
252        {
253            let rw_pin = self.rw_pin.as_mut().expect("RW pin for readable");
254            match command.get_read_write_op() {
255                ReadWriteOp::Write => {
256                    rw_pin.set_low().ok().unwrap();
257                }
258                ReadWriteOp::Read => {
259                    rw_pin.set_high().ok().unwrap();
260                }
261            }
262        }
263
264        match command.get_read_write_op() {
265            ReadWriteOp::Write => {
266                let bits = command
267                    .get_data()
268                    .expect("Write command but no data provide");
269                match PIN_CNT {
270                    4 => match bits {
271                        Bits::Bit4(raw_bits) => {
272                            assert!(raw_bits < 2u8.pow(4), "data is greater than 4 bits");
273                            self.push_bits(raw_bits);
274                            self.en_pin.set_high().ok().unwrap();
275                            self.en_pin.set_low().ok().unwrap();
276                        }
277                        Bits::Bit8(raw_bits) => {
278                            self.push_bits(raw_bits >> 4);
279                            self.en_pin.set_high().ok().unwrap();
280                            self.en_pin.set_low().ok().unwrap();
281                            self.push_bits(raw_bits & 0b1111);
282                            self.en_pin.set_high().ok().unwrap();
283                            self.en_pin.set_low().ok().unwrap();
284                        }
285                    },
286
287                    8 => {
288                        if let Bits::Bit8(raw_bits) = bits {
289                            self.push_bits(raw_bits);
290                            self.en_pin.set_high().ok().unwrap();
291                            self.en_pin.set_low().ok().unwrap();
292                        } else {
293                            panic!("in 8 pin mode, data should always be 8 bit")
294                        }
295                    }
296
297                    _ => unreachable!(),
298                }
299
300                None
301            }
302            ReadWriteOp::Read => match PIN_CNT {
303                4 => {
304                    self.en_pin.set_high().ok().unwrap();
305                    let high_4_bits = self.fetch_bits().checked_shl(4).unwrap();
306                    self.en_pin.set_low().ok().unwrap();
307                    self.en_pin.set_high().ok().unwrap();
308                    let low_4_bits = self.fetch_bits();
309                    self.en_pin.set_low().ok().unwrap();
310                    Some(high_4_bits + low_4_bits)
311                }
312
313                8 => {
314                    self.en_pin.set_high().ok().unwrap();
315                    let bits = self.fetch_bits();
316                    self.en_pin.set_low().ok().unwrap();
317                    Some(bits)
318                }
319
320                _ => unreachable!(),
321            },
322        }
323    }
324}
325
326impl<ControlPin, DBPin, BLPin, const PIN_CNT: usize, Delayer> SendCommand<Delayer, false>
327    for ParallelSender<ControlPin, DBPin, BLPin, PIN_CNT, false>
328where
329    ControlPin: OutputPin,
330    DBPin: OutputPin,
331    BLPin: StatefulOutputPin,
332    Delayer: DelayNs,
333{
334    backlight_fns!();
335
336    fn send(&mut self, command: Command) -> Option<u8> {
337        assert!(
338            PIN_CNT == 4 || PIN_CNT == 8,
339            "Pins other than 4 or 8 are not supported"
340        );
341
342        self.en_pin.set_low().ok().unwrap();
343
344        match command.get_register_selection() {
345            RegisterSelection::Command => {
346                self.rs_pin.set_low().ok().unwrap();
347            }
348            RegisterSelection::Data => {
349                self.rs_pin.set_high().ok().unwrap();
350            }
351        }
352
353        match command.get_read_write_op() {
354            ReadWriteOp::Write => {
355                let bits = command
356                    .get_data()
357                    .expect("Write command but no data provide");
358                match PIN_CNT {
359                    4 => match bits {
360                        Bits::Bit4(raw_bits) => {
361                            assert!(raw_bits < 2u8.pow(4), "data is greater than 4 bits");
362                            self.push_bits(raw_bits);
363                            self.en_pin.set_high().ok().unwrap();
364                            self.en_pin.set_low().ok().unwrap();
365                        }
366                        Bits::Bit8(raw_bits) => {
367                            self.push_bits(raw_bits >> 4);
368                            self.en_pin.set_high().ok().unwrap();
369                            self.en_pin.set_low().ok().unwrap();
370                            self.push_bits(raw_bits & 0b1111);
371                            self.en_pin.set_high().ok().unwrap();
372                            self.en_pin.set_low().ok().unwrap();
373                        }
374                    },
375
376                    8 => {
377                        if let Bits::Bit8(raw_bits) = bits {
378                            self.push_bits(raw_bits);
379                            self.en_pin.set_high().ok().unwrap();
380                            self.en_pin.set_low().ok().unwrap();
381                        } else {
382                            panic!("in 8 pin mode, data should always be 8 bit")
383                        }
384                    }
385
386                    _ => unreachable!(),
387                }
388
389                None
390            }
391            ReadWriteOp::Read => unreachable!(),
392        }
393    }
394}