lcd1602_driver/
command.rs

1//! Command to control LCD
2
3use crate::utils::BitOps;
4
5/// It contain all commands from LCD1602 datasheet
6#[derive(Clone, Copy, PartialEq)]
7#[allow(missing_docs)]
8pub enum CommandSet {
9    ClearDisplay,
10    ReturnHome,
11    EntryModeSet(MoveDirection, ShiftType),
12    DisplayOnOff {
13        display: State,
14        cursor: State,
15        cursor_blink: State,
16    },
17    CursorOrDisplayShift(ShiftType, MoveDirection),
18    /// This is not a command from datasheet.  
19    /// It's the first (half) command of 4 pin mode  
20    /// we name it, to make things tidy
21    HalfFunctionSet,
22    FunctionSet(DataWidth, LineMode, Font),
23    SetCGRAM(u8),
24    SetDDRAM(u8),
25    ReadBusyFlagAndAddress,
26    WriteDataToRAM(u8),
27    ReadDataFromRAM,
28}
29
30/// [`MoveDirection`] defines the cursor and display window move direction
31#[derive(Clone, Copy, PartialEq, Default)]
32pub enum MoveDirection {
33    #[allow(missing_docs)]
34    RightToLeft,
35    #[allow(missing_docs)]
36    #[default]
37    LeftToRight,
38}
39
40/// [`ShiftType`] defines the movement is cursor only or both cursor and display window
41#[derive(Clone, Copy, Default, PartialEq)]
42pub enum ShiftType {
43    #[allow(missing_docs)]
44    #[default]
45    CursorOnly,
46    #[allow(missing_docs)]
47    CursorAndDisplay,
48}
49
50/// [`State`] defines a On/Off state
51#[derive(Clone, Copy, PartialEq, Default)]
52pub enum State {
53    #[allow(missing_docs)]
54    Off,
55    #[allow(missing_docs)]
56    #[default]
57    On,
58}
59
60/// [`DataWidth`] defines data width of a [`Command`]  
61/// Should match current Sender's pin config
62#[derive(Clone, Copy, Default, PartialEq)]
63pub enum DataWidth {
64    #[allow(missing_docs)]
65    #[default]
66    Bit4,
67    #[allow(missing_docs)]
68    Bit8,
69}
70
71/// [`LineMode`] is current LCD display line count
72#[derive(Clone, Copy, Default, PartialEq)]
73pub enum LineMode {
74    #[allow(missing_docs)]
75    OneLine,
76    #[allow(missing_docs)]
77    #[default]
78    TwoLine,
79}
80
81/// [`Font`] is current display font
82#[derive(Clone, Copy, Default, PartialEq)]
83pub enum Font {
84    #[allow(missing_docs)]
85    #[default]
86    Font5x8,
87    #[allow(missing_docs)]
88    Font5x11,
89}
90
91/// [`RAMType`] is the type of memory to access
92#[derive(Clone, Copy, Default, PartialEq)]
93pub enum RAMType {
94    /// Display Data RAM
95    #[default]
96    DDRam,
97    /// Character Generator RAM
98    CGRam,
99}
100
101/// A sender should parse a [`Command`] and send the data to hardware to write/read data to/from hardware.
102pub struct Command {
103    rs: RegisterSelection,
104    rw: ReadWriteOp,
105    data: Option<Bits>, // if it's a read command, then data should be filled by reading process
106}
107
108/// [`RegisterSelection`] defines LCD1602's register type that driver interact with.  
109/// A sender should change its "RS" pin state based on this variant.
110#[derive(Clone, Copy, PartialEq)]
111pub enum RegisterSelection {
112    /// Access to Command register
113    Command,
114    /// Access to Data register
115    Data,
116}
117
118/// [`ReadWriteOp`] defines read/write operation that driver interact with.  
119/// A sender should change its "RW" pin state based on this variant.
120#[derive(Clone, Copy, PartialEq)]
121pub enum ReadWriteOp {
122    /// It's a write command
123    Write,
124    /// It's a read command
125    Read,
126}
127
128/// [`Bits`] defines *current command's* data width.  
129/// Most of the command should be 8 bit long, but **fisrt** command in [`DataWidth::Bit4`] mode is special, it requires 4 bit data.
130#[derive(Clone, Copy, PartialEq)]
131pub enum Bits {
132    /// Current command has 4 bit long data
133    Bit4(u8),
134    /// Current command has 8 bit long data
135    Bit8(u8),
136}
137
138#[allow(dead_code)]
139impl Command {
140    pub(crate) fn new(rs: RegisterSelection, rw: ReadWriteOp, data: Option<Bits>) -> Self {
141        if (rw == ReadWriteOp::Write) && (data.is_none()) {
142            panic!("Write Operation Should have Data");
143        }
144
145        Self { rs, rw, data }
146    }
147
148    pub(crate) fn get_register_selection(&self) -> RegisterSelection {
149        self.rs
150    }
151
152    pub(crate) fn set_register_selection(&mut self, rs: RegisterSelection) {
153        self.rs = rs
154    }
155
156    pub(crate) fn get_read_write_op(&self) -> ReadWriteOp {
157        self.rw
158    }
159
160    pub(crate) fn set_read_write_op(&mut self, rw: ReadWriteOp) {
161        self.rw = rw
162    }
163
164    pub(crate) fn get_data(&self) -> Option<Bits> {
165        self.data
166    }
167
168    pub(crate) fn set_data(&mut self, data: Option<Bits>) {
169        self.data = data
170    }
171}
172
173impl From<CommandSet> for Command {
174    fn from(command: CommandSet) -> Self {
175        match command {
176            CommandSet::ClearDisplay => {
177                let raw_bits: u8 = 0b0000_0001;
178                Self::new(
179                    RegisterSelection::Command,
180                    ReadWriteOp::Write,
181                    Some(Bits::Bit8(raw_bits)),
182                )
183            }
184
185            CommandSet::ReturnHome => {
186                let raw_bits: u8 = 0b0000_0010;
187                Self::new(
188                    RegisterSelection::Command,
189                    ReadWriteOp::Write,
190                    Some(Bits::Bit8(raw_bits)),
191                )
192            }
193
194            CommandSet::EntryModeSet(dir, st) => {
195                let mut raw_bits: u8 = 0b0000_0100;
196
197                match dir {
198                    MoveDirection::RightToLeft => raw_bits.clear_bit(1),
199                    MoveDirection::LeftToRight => raw_bits.set_bit(1),
200                };
201
202                match st {
203                    ShiftType::CursorOnly => raw_bits.clear_bit(0),
204                    ShiftType::CursorAndDisplay => raw_bits.set_bit(0),
205                };
206
207                Self::new(
208                    RegisterSelection::Command,
209                    ReadWriteOp::Write,
210                    Some(Bits::Bit8(raw_bits)),
211                )
212            }
213
214            CommandSet::DisplayOnOff {
215                display,
216                cursor,
217                cursor_blink,
218            } => {
219                let mut raw_bits = 0b0000_1000;
220
221                match display {
222                    State::Off => raw_bits.clear_bit(2),
223                    State::On => raw_bits.set_bit(2),
224                };
225                match cursor {
226                    State::Off => raw_bits.clear_bit(1),
227                    State::On => raw_bits.set_bit(1),
228                };
229                match cursor_blink {
230                    State::Off => raw_bits.clear_bit(0),
231                    State::On => raw_bits.set_bit(0),
232                };
233
234                Self::new(
235                    RegisterSelection::Command,
236                    ReadWriteOp::Write,
237                    Some(Bits::Bit8(raw_bits)),
238                )
239            }
240
241            CommandSet::CursorOrDisplayShift(st, dir) => {
242                let mut raw_bits = 0b0001_0000;
243
244                match st {
245                    ShiftType::CursorOnly => raw_bits.clear_bit(3),
246                    ShiftType::CursorAndDisplay => raw_bits.set_bit(3),
247                };
248
249                match dir {
250                    MoveDirection::RightToLeft => raw_bits.clear_bit(2),
251                    MoveDirection::LeftToRight => raw_bits.set_bit(2),
252                };
253
254                Self::new(
255                    RegisterSelection::Command,
256                    ReadWriteOp::Write,
257                    Some(Bits::Bit8(raw_bits)),
258                )
259            }
260
261            CommandSet::HalfFunctionSet => Self::new(
262                RegisterSelection::Command,
263                ReadWriteOp::Write,
264                Some(Bits::Bit4(0b0010)),
265            ),
266
267            CommandSet::FunctionSet(width, line, font) => {
268                let mut raw_bits = 0b0010_0000;
269
270                match width {
271                    DataWidth::Bit4 => raw_bits.clear_bit(4),
272                    DataWidth::Bit8 => raw_bits.set_bit(4),
273                };
274
275                match line {
276                    LineMode::OneLine => raw_bits.clear_bit(3),
277                    LineMode::TwoLine => raw_bits.set_bit(3),
278                };
279
280                match font {
281                    Font::Font5x8 => raw_bits.clear_bit(2),
282                    Font::Font5x11 => raw_bits.set_bit(2),
283                };
284
285                Self::new(
286                    RegisterSelection::Command,
287                    ReadWriteOp::Write,
288                    Some(Bits::Bit8(raw_bits)),
289                )
290            }
291
292            CommandSet::SetCGRAM(addr) => {
293                let mut raw_bits = 0b0100_0000;
294
295                assert!(addr < 2u8.pow(6), "CGRAM address out of range");
296
297                raw_bits += addr;
298
299                Self::new(
300                    RegisterSelection::Command,
301                    ReadWriteOp::Write,
302                    Some(Bits::Bit8(raw_bits)),
303                )
304            }
305
306            CommandSet::SetDDRAM(addr) => {
307                let mut raw_bits = 0b1000_0000;
308
309                assert!(addr < 2u8.pow(7), "DDRAM address out of range");
310
311                raw_bits += addr;
312
313                Self::new(
314                    RegisterSelection::Command,
315                    ReadWriteOp::Write,
316                    Some(Bits::Bit8(raw_bits)),
317                )
318            }
319
320            CommandSet::ReadBusyFlagAndAddress => {
321                Self::new(RegisterSelection::Command, ReadWriteOp::Read, None)
322            }
323
324            CommandSet::WriteDataToRAM(data) => Self::new(
325                RegisterSelection::Data,
326                ReadWriteOp::Write,
327                Some(Bits::Bit8(data)),
328            ),
329
330            CommandSet::ReadDataFromRAM => {
331                Self::new(RegisterSelection::Data, ReadWriteOp::Read, None)
332            }
333        }
334    }
335}