lcd1602_driver/
state.rs

1use crate::command::{DataWidth, Font, LineMode, MoveDirection, RAMType, ShiftType, State};
2
3#[derive(Default)]
4pub(crate) struct LcdState {
5    data_width: DataWidth,
6    line: LineMode,
7    font: Font,
8    display_on: State,
9    cursor_on: State,
10    cursor_blink: State,
11    direction: MoveDirection,
12    shift_type: ShiftType,
13    cursor_pos: (u8, u8),
14    display_offset: u8,
15    ram_type: RAMType,
16    backlight: State,
17}
18
19impl LcdState {
20    pub(crate) fn get_backlight(&self) -> State {
21        self.backlight
22    }
23
24    pub(crate) fn set_backlight(&mut self, backlight: State) {
25        self.backlight = backlight;
26    }
27
28    pub(crate) fn get_data_width(&self) -> DataWidth {
29        self.data_width
30    }
31
32    pub(crate) fn set_data_width(&mut self, data_width: DataWidth) {
33        self.data_width = data_width;
34    }
35
36    pub(crate) fn get_line_mode(&self) -> LineMode {
37        self.line
38    }
39
40    pub(crate) fn set_line_mode(&mut self, line: LineMode) {
41        if self.get_font() == Font::Font5x11 {
42            assert!(
43                line == LineMode::OneLine,
44                "Font is 5x11, LineMode cannot be TwoLine"
45            )
46        }
47        self.line = line;
48    }
49
50    pub(crate) fn get_line_capacity(&self) -> u8 {
51        match self.get_line_mode() {
52            LineMode::OneLine => 80,
53            LineMode::TwoLine => 40,
54        }
55    }
56
57    pub(crate) fn get_font(&self) -> Font {
58        self.font
59    }
60
61    pub(crate) fn set_font(&mut self, font: Font) {
62        if self.get_line_mode() == LineMode::TwoLine {
63            assert!(
64                font == Font::Font5x8,
65                "LineMode is TwoLine, Font cannot be 5x11"
66            )
67        }
68        self.font = font;
69    }
70
71    pub(crate) fn get_display_state(&self) -> State {
72        self.display_on
73    }
74
75    pub(crate) fn set_display_state(&mut self, display: State) {
76        self.display_on = display;
77    }
78
79    pub(crate) fn get_cursor_state(&self) -> State {
80        self.cursor_on
81    }
82
83    pub(crate) fn set_cursor_state(&mut self, cursor: State) {
84        self.cursor_on = cursor;
85    }
86
87    pub(crate) fn get_cursor_blink(&self) -> State {
88        self.cursor_blink
89    }
90
91    pub(crate) fn set_cursor_blink(&mut self, blink: State) {
92        self.cursor_blink = blink;
93    }
94
95    pub(crate) fn get_direction(&self) -> MoveDirection {
96        self.direction
97    }
98
99    pub(crate) fn set_direction(&mut self, dir: MoveDirection) {
100        self.direction = dir;
101    }
102
103    pub(crate) fn get_shift_type(&self) -> ShiftType {
104        self.shift_type
105    }
106
107    pub(crate) fn set_shift_type(&mut self, shift: ShiftType) {
108        self.shift_type = shift;
109    }
110
111    pub(crate) fn get_cursor_pos(&self) -> (u8, u8) {
112        self.cursor_pos
113    }
114
115    pub(crate) fn set_cursor_pos(&mut self, pos: (u8, u8)) {
116        let line_capacity = self.get_line_capacity();
117        match self.line {
118            LineMode::OneLine => {
119                assert!(pos.0 < line_capacity, "x offset too big");
120                assert!(pos.1 < 1, "always keep y as 0 on OneLine mode");
121            }
122            LineMode::TwoLine => {
123                assert!(pos.0 < line_capacity, "x offset too big");
124                assert!(pos.1 < 2, "y offset too big");
125            }
126        }
127
128        self.cursor_pos = pos;
129    }
130
131    pub(crate) fn get_display_offset(&self) -> u8 {
132        self.display_offset
133    }
134
135    pub(crate) fn set_display_offset(&mut self, offset: u8) {
136        if offset >= self.get_line_capacity() {
137            match self.get_line_mode() {
138                LineMode::OneLine => panic!("Display Offset too big, should not bigger than 79"),
139                LineMode::TwoLine => panic!("Display Offset too big, should not bigger than 39"),
140            }
141        }
142
143        self.display_offset = offset;
144    }
145
146    pub(crate) fn shift_cursor_or_display(&mut self, st: ShiftType, dir: MoveDirection) {
147        let cur_display_offset = self.get_display_offset();
148        let cur_cursor_pos = self.get_cursor_pos();
149        let line_capacity = self.get_line_capacity();
150
151        match st {
152            ShiftType::CursorOnly => match dir {
153                MoveDirection::LeftToRight => match self.get_line_mode() {
154                    LineMode::OneLine => {
155                        if cur_cursor_pos.0 == line_capacity - 1 {
156                            self.set_cursor_pos((0, 0));
157                        } else {
158                            self.set_cursor_pos((cur_cursor_pos.0 + 1, 0));
159                        }
160                    }
161                    LineMode::TwoLine => {
162                        if cur_cursor_pos.0 == line_capacity - 1 {
163                            if cur_cursor_pos.1 == 0 {
164                                self.set_cursor_pos((0, 1));
165                            } else {
166                                self.set_cursor_pos((0, 0));
167                            }
168                        } else {
169                            self.set_cursor_pos((cur_cursor_pos.0 + 1, cur_cursor_pos.1));
170                        }
171                    }
172                },
173                MoveDirection::RightToLeft => match self.get_line_mode() {
174                    LineMode::OneLine => {
175                        if cur_cursor_pos.0 == 0 {
176                            self.set_cursor_pos((line_capacity - 1, 0));
177                        } else {
178                            self.set_cursor_pos((cur_cursor_pos.0 - 1, 0));
179                        }
180                    }
181                    LineMode::TwoLine => {
182                        if cur_cursor_pos.0 == 0 {
183                            if cur_cursor_pos.1 == 0 {
184                                self.set_cursor_pos((line_capacity - 1, 1));
185                            } else {
186                                self.set_cursor_pos((line_capacity - 1, 0));
187                            }
188                        } else {
189                            self.set_cursor_pos((cur_cursor_pos.0 - 1, cur_cursor_pos.1));
190                        }
191                    }
192                },
193            },
194            ShiftType::CursorAndDisplay => match dir {
195                MoveDirection::LeftToRight => {
196                    if cur_display_offset == line_capacity - 1 {
197                        self.set_display_offset(0)
198                    } else {
199                        self.set_display_offset(cur_display_offset + 1)
200                    };
201                }
202                MoveDirection::RightToLeft => {
203                    if cur_display_offset == 0 {
204                        self.set_display_offset(line_capacity - 1)
205                    } else {
206                        self.set_display_offset(cur_display_offset - 1)
207                    };
208                }
209            },
210        }
211    }
212
213    pub(crate) fn get_ram_type(&self) -> RAMType {
214        self.ram_type
215    }
216
217    pub(crate) fn set_ram_type(&mut self, ram_type: RAMType) {
218        self.ram_type = ram_type;
219    }
220
221    pub(crate) fn calculate_pos_by_offset(
222        &self,
223        original_pos: (u8, u8),
224        offset: (i8, i8),
225    ) -> (u8, u8) {
226        let line_capacity = self.get_line_capacity();
227
228        match self.get_line_mode() {
229            LineMode::OneLine => {
230                assert!(
231                    offset.0.unsigned_abs() < line_capacity,
232                    "x offset too big, should greater than -80 and less than 80"
233                );
234                assert!(offset.1 == 0, "y offset should always be 0 on OneLine Mode")
235            }
236            LineMode::TwoLine => {
237                assert!(
238                    offset.0.unsigned_abs() < line_capacity,
239                    "x offset too big, should greater than -40 and less than 40"
240                );
241                assert!(
242                    offset.1.abs() < 2,
243                    "y offset too big, should between -1 and 1"
244                )
245            }
246        }
247
248        match self.get_line_mode() {
249            LineMode::OneLine => {
250                let raw_x_pos = (original_pos.0 as i8) + offset.0;
251                if raw_x_pos < 0 {
252                    ((raw_x_pos + line_capacity as i8) as u8, 0)
253                } else if raw_x_pos > line_capacity as i8 {
254                    ((raw_x_pos - line_capacity as i8) as u8, 0)
255                } else {
256                    (raw_x_pos as u8, 0)
257                }
258            }
259            LineMode::TwoLine => {
260                let mut x_overflow: i8 = 0;
261
262                // this likes a "adder" in logic circuit design
263
264                let mut raw_x_pos = (original_pos.0 as i8) + offset.0;
265
266                if raw_x_pos < 0 {
267                    raw_x_pos += 2;
268                    x_overflow = -1;
269                } else if raw_x_pos > line_capacity as i8 {
270                    raw_x_pos -= 2;
271                    x_overflow = 1;
272                }
273
274                let mut raw_y_pos = (original_pos.1 as i8) + offset.1 + x_overflow;
275                if raw_y_pos < 0 {
276                    raw_y_pos += 2
277                } else if raw_y_pos > 2 {
278                    raw_y_pos -= 2
279                };
280
281                (raw_x_pos as u8, raw_y_pos as u8)
282            }
283        }
284    }
285}