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 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}