1use embedded_hal::delay::DelayNs;
2
3use crate::command::{Font, LineMode, MoveDirection, RAMType, ShiftType};
4use crate::sender::SendCommand;
5use crate::{command::CommandSet, lcd::State};
6
7use super::{Anim, Basic, BasicRead, CGRAMGraph, Ext, ExtRead, Lcd};
8
9impl<'a, 'b, Sender, Delayer, const READABLE: bool> Basic for Lcd<'a, 'b, Sender, Delayer, READABLE>
10where
11 Sender: SendCommand<Delayer, READABLE>,
12 Delayer: DelayNs,
13{
14 fn set_backlight(&mut self, backlight: State) {
15 self.sender.set_actual_backlight(backlight);
16 self.state.set_backlight(backlight);
17 }
18
19 fn get_backlight(&self) -> State {
20 self.state.get_backlight()
21 }
22
23 fn write_byte_to_cur(&mut self, byte: u8) {
24 assert!(
25 self.get_ram_type() == RAMType::DDRam,
26 "Current in CGRAM, use .set_cursor_pos() to change to DDRAM"
27 );
28
29 self.sender.wait_and_send(
30 CommandSet::WriteDataToRAM(byte),
31 self.delayer,
32 self.poll_interval_us,
33 );
34
35 let last_pos = self.get_cursor_pos();
38 let line_capacity = self.get_line_capacity();
39
40 let raw_pos = match self.get_direction() {
41 MoveDirection::RightToLeft => match self.get_line_mode() {
42 LineMode::OneLine => {
43 if last_pos.0 == 0 {
44 (line_capacity - 1, 0)
45 } else {
46 (last_pos.0 - 1, 0)
47 }
48 }
49 LineMode::TwoLine => {
50 if last_pos.0 == 0 {
51 if last_pos.1 == 1 {
52 (line_capacity - 1, 0)
53 } else {
54 (line_capacity - 1, 1)
55 }
56 } else {
57 (last_pos.0 - 1, last_pos.1)
58 }
59 }
60 },
61 MoveDirection::LeftToRight => match self.get_line_mode() {
62 LineMode::OneLine => {
63 if last_pos.0 == line_capacity - 1 {
64 (0, 0)
65 } else {
66 (last_pos.0 + 1, 0)
67 }
68 }
69 LineMode::TwoLine => {
70 if last_pos.0 == line_capacity - 1 {
71 if last_pos.1 == 0 {
72 (0, 1)
73 } else {
74 (0, 0)
75 }
76 } else {
77 (last_pos.0 + 1, last_pos.1)
78 }
79 }
80 },
81 };
82 self.state.set_cursor_pos(raw_pos);
83 }
84
85 fn write_graph_to_cgram(&mut self, index: u8, graph_data: &CGRAMGraph) {
86 if graph_data.lower.is_some() {
87 assert!(index < 4, "Only 4 graphs allowed in CGRAM for 5x11 Font")
88 } else {
89 assert!(index < 8, "Only 8 graphs allowed in CGRAM for 5x8 Font")
90 }
91
92 assert!(
93 graph_data.upper.iter().all(|&line| line < 2u8.pow(5)),
94 "Only lower 5 bits use to construct the graph"
95 );
96
97 if let Some(graph_data_lower) = graph_data.lower {
98 assert!(
99 graph_data_lower.iter().all(|&line| line < 2u8.pow(5)),
100 "Only lower 5 bits use to construct the graph"
101 );
102 }
103
104 let direction_flipped = if self.get_direction() == MoveDirection::RightToLeft {
107 self.set_direction(MoveDirection::LeftToRight);
108 true
109 } else {
110 false
111 };
112
113 self.set_cgram_addr(
115 index
116 .checked_shl(match graph_data.lower {
117 None => 3,
118 Some(_) => 4,
119 })
120 .unwrap(),
121 );
122
123 graph_data.upper.iter().for_each(|&line_data| {
124 self.sender.wait_and_send(
125 CommandSet::WriteDataToRAM(line_data),
126 self.delayer,
127 self.poll_interval_us,
128 );
129 });
130
131 if let Some(graph_data_lower) = graph_data.lower {
132 graph_data_lower.iter().for_each(|&line_data| {
133 self.sender.wait_and_send(
134 CommandSet::WriteDataToRAM(line_data),
135 self.delayer,
136 self.poll_interval_us,
137 );
138 });
139 }
140
141 if direction_flipped {
143 self.set_direction(MoveDirection::RightToLeft)
144 }
145 }
146
147 fn clean_display(&mut self) {
148 self.sender.wait_and_send(
149 CommandSet::ClearDisplay,
150 self.delayer,
151 self.poll_interval_us,
152 );
153 }
154
155 fn return_home(&mut self) {
156 self.state.set_cursor_pos((0, 0));
157 self.state.set_display_offset(0);
158
159 self.sender
160 .wait_and_send(CommandSet::ReturnHome, self.delayer, self.poll_interval_us);
161 }
162
163 fn set_line_mode(&mut self, line: LineMode) {
164 self.state.set_line_mode(line);
165
166 self.sender.wait_and_send(
167 CommandSet::FunctionSet(
168 self.state.get_data_width(),
169 self.get_line_mode(),
170 self.get_font(),
171 ),
172 self.delayer,
173 self.poll_interval_us,
174 );
175 }
176
177 fn get_line_mode(&self) -> LineMode {
178 self.state.get_line_mode()
179 }
180
181 fn set_font(&mut self, font: Font) {
182 self.state.set_font(font);
183
184 self.sender.wait_and_send(
185 CommandSet::FunctionSet(
186 self.state.get_data_width(),
187 self.get_line_mode(),
188 self.get_font(),
189 ),
190 self.delayer,
191 self.poll_interval_us,
192 );
193 }
194 fn get_font(&self) -> Font {
195 self.state.get_font()
196 }
197 fn set_display_state(&mut self, display: State) {
198 self.state.set_display_state(display);
199
200 self.sender.wait_and_send(
201 CommandSet::DisplayOnOff {
202 display: self.get_display_state(),
203 cursor: self.get_cursor_state(),
204 cursor_blink: self.get_cursor_blink_state(),
205 },
206 self.delayer,
207 self.poll_interval_us,
208 );
209 }
210 fn get_display_state(&self) -> State {
211 self.state.get_display_state()
212 }
213 fn set_cursor_state(&mut self, cursor: State) {
214 self.state.set_cursor_state(cursor);
215
216 self.sender.wait_and_send(
217 CommandSet::DisplayOnOff {
218 display: self.get_display_state(),
219 cursor: self.get_cursor_state(),
220 cursor_blink: self.get_cursor_blink_state(),
221 },
222 self.delayer,
223 self.poll_interval_us,
224 );
225 }
226 fn get_cursor_state(&self) -> State {
227 self.state.get_cursor_state()
228 }
229 fn get_ram_type(&self) -> RAMType {
230 self.state.get_ram_type()
231 }
232 fn set_cursor_blink_state(&mut self, blink: State) {
233 self.state.set_cursor_blink(blink);
234
235 self.sender.wait_and_send(
236 CommandSet::DisplayOnOff {
237 display: self.get_display_state(),
238 cursor: self.get_cursor_state(),
239 cursor_blink: self.get_cursor_blink_state(),
240 },
241 self.delayer,
242 self.poll_interval_us,
243 );
244 }
245 fn get_cursor_blink_state(&self) -> State {
246 self.state.get_cursor_blink()
247 }
248 fn set_direction(&mut self, dir: MoveDirection) {
249 self.state.set_direction(dir);
250
251 self.sender.wait_and_send(
252 CommandSet::EntryModeSet(self.get_direction(), self.get_shift_type()),
253 self.delayer,
254 self.poll_interval_us,
255 );
256 }
257 fn get_direction(&self) -> MoveDirection {
258 self.state.get_direction()
259 }
260 fn set_shift_type(&mut self, shift: ShiftType) {
261 self.state.set_shift_type(shift);
262
263 self.sender.wait_and_send(
264 CommandSet::EntryModeSet(self.get_direction(), self.get_shift_type()),
265 self.delayer,
266 self.poll_interval_us,
267 );
268 }
269 fn get_shift_type(&self) -> ShiftType {
270 self.state.get_shift_type()
271 }
272 fn set_cursor_pos(&mut self, pos: (u8, u8)) {
273 self.state.set_ram_type(RAMType::DDRam);
274 self.state.set_cursor_pos(pos);
275
276 let raw_pos: u8 = pos.1 * 0x40 + pos.0;
279
280 self.sender.wait_and_send(
281 CommandSet::SetDDRAM(raw_pos),
282 self.delayer,
283 self.poll_interval_us,
284 );
285 }
286 fn set_cgram_addr(&mut self, addr: u8) {
287 assert!(addr < 2u8.pow(6), "CGRAM Address overflow");
288
289 self.state.set_ram_type(RAMType::CGRam);
290
291 self.sender.wait_and_send(
292 CommandSet::SetCGRAM(addr),
293 self.delayer,
294 self.poll_interval_us,
295 );
296 }
297 fn get_cursor_pos(&self) -> (u8, u8) {
298 self.state.get_cursor_pos()
299 }
300 fn shift_cursor_or_display(&mut self, shift_type: ShiftType, dir: MoveDirection) {
301 self.state.shift_cursor_or_display(shift_type, dir);
302
303 self.sender.wait_and_send(
304 CommandSet::CursorOrDisplayShift(shift_type, dir),
305 self.delayer,
306 self.poll_interval_us,
307 );
308 }
309 fn get_display_offset(&self) -> u8 {
310 self.state.get_display_offset()
311 }
312
313 fn set_poll_interval(&mut self, interval_us: u32) {
314 self.poll_interval_us = interval_us;
315 }
316
317 fn get_poll_interval_us(&self) -> u32 {
318 self.poll_interval_us
319 }
320
321 fn get_line_capacity(&self) -> u8 {
322 self.state.get_line_capacity()
323 }
324
325 fn calculate_pos_by_offset(&self, start: (u8, u8), offset: (i8, i8)) -> (u8, u8) {
326 self.state.calculate_pos_by_offset(start, offset)
327 }
328
329 fn delay_ms(&mut self, ms: u32) {
330 self.delayer.delay_ms(ms);
331 }
332
333 fn delay_us(&mut self, us: u32) {
334 self.delayer.delay_us(us)
335 }
336}
337
338impl<'a, 'b, Sender, Delayer> BasicRead for Lcd<'a, 'b, Sender, Delayer, true>
339where
340 Sender: SendCommand<Delayer, true>,
341 Delayer: DelayNs,
342{
343 fn read_u8_from_cur(&mut self) -> u8 {
344 self.sender
345 .wait_and_send(
346 CommandSet::ReadDataFromRAM,
347 self.delayer,
348 self.poll_interval_us,
349 )
350 .unwrap()
351 }
352}
353
354impl<'a, 'b, Sender, Delayer, const READABLE: bool> Ext for Lcd<'a, 'b, Sender, Delayer, READABLE>
355where
356 Delayer: DelayNs,
357 Sender: SendCommand<Delayer, READABLE>,
358{
359}
360
361impl<'a, 'b, Sender, Delayer> ExtRead for Lcd<'a, 'b, Sender, Delayer, true>
362where
363 Delayer: DelayNs,
364 Sender: SendCommand<Delayer, true>,
365{
366}
367
368impl<'a, 'b, Sender, Delayer, const READABLE: bool> Anim for Lcd<'a, 'b, Sender, Delayer, READABLE>
369where
370 Delayer: DelayNs,
371 Sender: SendCommand<Delayer, READABLE>,
372{
373}