1use core::marker::PhantomData;
2
3pub use embedded_hal::delay::DelayNs;
4#[cfg(feature="async")]
5pub use embedded_hal_async::delay::DelayNs as ADelay;
6
7pub mod commands;
8pub mod interfaces;
9pub mod layout;
10
11pub use interfaces::*;
12pub use layout::*;
13
14pub use commands::Commands::*;
15pub use commands::*;
16
17pub enum SendType<'s> {
19 Command(Commands),
20 Text(&'s str),
21 CustomChar(u8),
22}
23
24pub enum BusBits {
25 Bus4Bits,
26 Bus8Bits,
27}
28
29enum LCDEntryMode {
30 LCDShiftMode = 0x01,
31 LCDDirection = 0x02,
32}
33
34enum LCDDisplayControl {
35 LCDBlink = 0x01,
36 LCDCursor = 0x02,
37 LCDDisplay = 0x04,
38}
39
40pub struct Blocking;
41#[cfg(feature="async")]
42pub struct Async;
43
44pub struct LiquidCrystal<'interface, T: Interface, const COLS: u8, const LINES: usize, MODE = Blocking> {
45 interface: &'interface mut T,
46 corrent_enable: u8,
47 bus: BusBits,
48 layout: Layout<COLS, LINES>,
49 entry_mode: u8,
50 display_control: u8,
51 _mode: PhantomData<MODE>,
52}
53
54impl<'interface, T: Interface, const COLS: u8, const LINES: usize>
55 LiquidCrystal<'interface, T, COLS, LINES>
56{
57 pub fn new(
58 interface: &'interface mut T,
59 bus: BusBits,
60 layout: Layout<COLS, LINES>,
61 ) -> LiquidCrystal<'interface, T, COLS, LINES> {
62 LiquidCrystal {
63 interface,
64 bus,
65 layout,
66 corrent_enable: 0b11,
67 entry_mode: 0x06, display_control: 0x0C, _mode: PhantomData,
70 }
71 }
72
73 #[cfg(feature="async")]
74 pub fn asynch(self) -> LiquidCrystal<'interface, T, COLS, LINES, Async> {
75 LiquidCrystal {
76 interface: self.interface,
77 bus: self.bus,
78 layout: self.layout,
79 corrent_enable: self.corrent_enable,
80 entry_mode: self.entry_mode,
81 display_control: self.display_control,
82 _mode: PhantomData,
83 }
84 }
85
86 fn send8bits(&mut self, delay: &mut impl DelayNs, data: u8, rs_state: u8) {
87 self.interface.send(rs_state, data);
88 self.interface
89 .send(rs_state | (self.corrent_enable << 2), data);
90 delay.delay_us(1);
91 self.interface.send(rs_state, data);
92 }
93
94 fn send4bits(&mut self, delay: &mut impl DelayNs, data: u8, rs_state: u8) {
95 let high_nibble = data & 0xF0;
96 let low_nibble = data << 4;
97 self.send8bits(delay, high_nibble, rs_state);
98 delay.delay_us(1);
99 self.send8bits(delay, low_nibble, rs_state);
100 }
101
102 pub fn send(&mut self, delay: &mut impl DelayNs, data: u8, rs_state: u8) {
108 match self.bus {
109 BusBits::Bus8Bits => self.send8bits(delay, data, rs_state),
110 BusBits::Bus4Bits => self.send4bits(delay, data, rs_state),
111 };
112
113 if rs_state == 1 {
114 delay.delay_us(2);
115 } else {
116 delay.delay_us(40);
117 }
118 }
119
120 pub fn begin(&mut self, delay: &mut impl DelayNs) {
121 delay.delay_ms(50);
122 self.send8bits(delay, 0x30, 0);
123 delay.delay_us(4100);
124 self.send8bits(delay, 0x30, 0);
125 delay.delay_us(100);
126 self.send8bits(delay, 0x30, 0);
127 delay.delay_us(100);
128 match self.bus {
129 BusBits::Bus8Bits => self.send8bits(delay, 0x38, 0),
130 BusBits::Bus4Bits => {
131 self.send8bits(delay, 0x20, 0);
132 self.send(delay, 0x28, 0);
133 }
134 };
135 self.write(delay, SendType::Command(Clear));
136 self.write(delay, SendType::Command(Reset));
137 self.update_config(delay);
138 }
139
140 pub fn write<'s>(&mut self, delay: &mut impl DelayNs, data: SendType<'s>) -> &mut Self {
159 match data {
160 SendType::Command(x) => {
161 self.send(delay, x as u8, 0x00);
162 delay.delay_us(2000);
163 }
164 SendType::Text(x) => {
165 for text in x.chars() {
166 self.send(delay, text as u8, RS);
167 }
168 }
169 SendType::CustomChar(slot) => {
170 if slot < 8 {
171 self.send(delay, slot, RS);
172 }
173 }
174 };
175 self
176 }
177
178 pub fn set_cursor(&mut self, delay: &mut impl DelayNs, line: usize, colum: u8) -> &mut Self {
181 if (line < LINES) || (colum < COLS) {
182 self.send(delay, self.layout.addrs[line] + colum, 0);
183 }
184 self
185 }
186
187 pub fn custom_char(
190 &mut self,
191 delay: &mut impl DelayNs,
192 char_array: &[u8; 8],
193 slot: u8,
194 ) -> &mut Self {
195 if slot < 8 {
196 self.send(delay, 0x40 | (slot << 3), 0x00);
197 for c in 0..8 {
198 self.send(delay, char_array[c], RS);
199 }
200 }
201 self.write(delay, SendType::Command(Reset));
202 self
203 }
204
205 pub fn update_config(&mut self, delay: &mut impl DelayNs) -> &mut Self {
207 self.send(delay, self.display_control, 0);
208 self.send(delay, self.entry_mode, 0);
209 self
210 }
211}
212
213#[cfg(feature="async")]
214impl<'interface, T: Interface, const COLS: u8, const LINES: usize>
215 LiquidCrystal<'interface, T, COLS, LINES, Async>
216{
217 pub fn blocking(self) -> LiquidCrystal<'interface, T, COLS, LINES, Blocking> {
218 LiquidCrystal {
219 interface: self.interface,
220 bus: self.bus,
221 layout: self.layout,
222 corrent_enable: self.corrent_enable,
223 entry_mode: self.entry_mode,
224 display_control: self.display_control,
225 _mode: PhantomData,
226 }
227 }
228
229 async fn send8bits(&mut self, delay: &mut impl ADelay, data: u8, rs_state: u8) {
230 self.interface.send(rs_state, data);
231 self.interface
232 .send(rs_state | (self.corrent_enable << 2), data);
233 delay.delay_us(1).await;
234 self.interface.send(rs_state, data);
235 }
236
237 async fn send4bits(&mut self, delay: &mut impl ADelay, data: u8, rs_state: u8) {
238 let high_nibble = data & 0xF0;
239 let low_nibble = data << 4;
240 self.send8bits(delay, high_nibble, rs_state).await;
241 delay.delay_us(1).await;
242 self.send8bits(delay, low_nibble, rs_state).await;
243 }
244
245 pub async fn send(&mut self, delay: &mut impl ADelay, data: u8, rs_state: u8) {
251 match self.bus {
252 BusBits::Bus8Bits => self.send8bits(delay, data, rs_state).await,
253 BusBits::Bus4Bits => self.send4bits(delay, data, rs_state).await,
254 };
255
256 if rs_state == 1 {
257 delay.delay_us(2).await;
258 } else {
259 delay.delay_us(40).await;
260 }
261 }
262
263 pub async fn begin(&mut self, delay: &mut impl ADelay) {
264 delay.delay_ms(50).await;
265 self.send8bits(delay, 0x30, 0).await;
266 delay.delay_us(4100).await;
267 self.send8bits(delay, 0x30, 0).await;
268 delay.delay_us(100).await;
269 self.send8bits(delay, 0x30, 0).await;
270 delay.delay_us(100).await;
271 match self.bus {
272 BusBits::Bus8Bits => self.send8bits(delay, 0x38, 0).await,
273 BusBits::Bus4Bits => {
274 self.send8bits(delay, 0x20, 0).await;
275 self.send(delay, 0x28, 0).await;
276 }
277 };
278 self.write(delay, SendType::Command(Clear)).await;
279 self.write(delay, SendType::Command(Reset)).await;
280 self.update_config(delay).await;
281 }
282
283 pub async fn write<'s>(&mut self, delay: &mut impl ADelay, data: SendType<'s>) -> &mut Self {
302 match data {
303 SendType::Command(x) => {
304 self.send(delay, x as u8, 0x00).await;
305 delay.delay_us(2000).await;
306 }
307 SendType::Text(x) => {
308 for text in x.chars() {
309 self.send(delay, text as u8, RS).await;
310 }
311 }
312 SendType::CustomChar(slot) => {
313 if slot < 8 {
314 self.send(delay, slot, RS).await;
315 }
316 }
317 };
318 self
319 }
320
321 pub async fn set_cursor(&mut self, delay: &mut impl ADelay, line: usize, colum: u8) -> &mut Self {
324 if (line < LINES) || (colum < COLS) {
325 self.send(delay, self.layout.addrs[line] + colum, 0).await;
326 }
327 self
328 }
329
330 pub async fn custom_char(
333 &mut self,
334 delay: &mut impl ADelay,
335 char_array: &[u8; 8],
336 slot: u8,
337 ) -> &mut Self {
338 if slot < 8 {
339 self.send(delay, 0x40 | (slot << 3), 0x00).await;
340 for c in 0..8 {
341 self.send(delay, char_array[c], RS).await;
342 }
343 }
344 self.write(delay, SendType::Command(Reset)).await;
345 self
346 }
347
348 pub async fn update_config(&mut self, delay: &mut impl ADelay) -> &mut Self {
350 self.send(delay, self.display_control, 0).await;
351 self.send(delay, self.entry_mode, 0).await;
352 self
353 }
354}
355
356impl<'interface, T: Interface, const COLS: u8, const LINES: usize, MODE>
357 LiquidCrystal<'interface, T, COLS, LINES, MODE>
358{
359 pub fn echo(&mut self) -> &mut Self {
361 self.corrent_enable = 0b11;
362 self
363 }
364
365 pub fn select_lcd(&mut self, en: u8) -> &mut Self {
368 if en < 2 {
369 self.corrent_enable = 1 << en;
370 }
371 self
372 }
373
374 #[inline]
377 pub fn enable_blink(&mut self) -> &mut Self {
378 self.display_control |= LCDDisplayControl::LCDBlink as u8;
379 self
380 }
381
382 #[inline]
385 pub fn enable_cursor(&mut self) -> &mut Self {
386 self.display_control |= LCDDisplayControl::LCDCursor as u8;
387 self
388 }
389
390 #[inline]
393 pub fn enable_display(&mut self) -> &mut Self {
394 self.display_control |= LCDDisplayControl::LCDDisplay as u8;
395 self
396 }
397
398 #[inline]
401 pub fn enable_autoscroll(&mut self) -> &mut Self {
402 self.entry_mode |= LCDEntryMode::LCDShiftMode as u8;
403 self
404 }
405
406 #[inline]
409 pub fn disable_blink(&mut self) -> &mut Self {
410 self.display_control &= !(LCDDisplayControl::LCDBlink as u8);
411 self
412 }
413
414 #[inline]
417 pub fn disable_cursor(&mut self) -> &mut Self {
418 self.display_control &= !(LCDDisplayControl::LCDCursor as u8);
419 self
420 }
421
422 #[inline]
425 pub fn disable_display(&mut self) -> &mut Self {
426 self.display_control &= !(LCDDisplayControl::LCDDisplay as u8);
427 self
428 }
429
430 #[inline]
433 pub fn disable_autoscroll(&mut self) -> &mut Self {
434 self.entry_mode &= !(LCDEntryMode::LCDShiftMode as u8);
435 self
436 }
437
438 #[inline]
441 pub fn set_autoscroll_increment(&mut self) -> &mut Self {
442 self.entry_mode |= LCDEntryMode::LCDDirection as u8;
443 self
444 }
445
446 #[inline]
449 pub fn set_autoscroll_decrement(&mut self) -> &mut Self {
450 self.entry_mode &= !(LCDEntryMode::LCDDirection as u8);
451 self
452 }
453}