1use core::cell::Cell;
56use kernel::hil::gpio;
57use kernel::hil::text_screen::{TextScreen, TextScreenClient};
58use kernel::hil::time::{self, Alarm, Frequency};
59use kernel::utilities::cells::{OptionalCell, TakeCell};
60use kernel::ErrorCode;
61
62static LCD_CLEARDISPLAY: u8 = 0x01;
64static LCD_ENTRYMODESET: u8 = 0x04;
65static LCD_DISPLAYCONTROL: u8 = 0x08;
66static LCD_FUNCTIONSET: u8 = 0x20;
67static LCD_SETDDRAMADDR: u8 = 0x80;
68
69static LCD_ENTRYLEFT: u8 = 0x02;
71static LCD_ENTRYSHIFTDECREMENT: u8 = 0x00;
72
73static LCD_DISPLAYON: u8 = 0x04;
75static LCD_CURSORON: u8 = 0x02;
76static LCD_BLINKON: u8 = 0x01;
77static LCD_BLINKOFF: u8 = 0x00;
78
79static LCD_8BITMODE: u8 = 0x10;
81static LCD_4BITMODE: u8 = 0x00;
82static LCD_2LINE: u8 = 0x08;
83static LCD_1LINE: u8 = 0x00;
84static LCD_5X8DOTS: u8 = 0x00;
85
86pub const BUF_LEN: usize = 4;
87
88#[derive(Copy, Clone, PartialEq)]
90enum LCDStatus {
91 Idle,
92 Begin0,
93 Begin0_1,
94 Begin1,
95 Begin1_2,
96 Begin2,
97 Begin2_3,
98 Begin3,
99 Begin4,
100 Begin5,
101 Begin6,
102 Begin7,
103 Begin8,
104 Begin9,
105 Begin10,
106 Begin11,
107 Begin12,
108 Printing,
109 PulseLow,
110 PulseHigh,
111 Command,
112 Clear,
113}
114
115pub struct HD44780<'a, A: Alarm<'a>> {
116 rs_pin: &'a dyn gpio::Pin,
117 en_pin: &'a dyn gpio::Pin,
118 data_4_pin: &'a dyn gpio::Pin,
119 data_5_pin: &'a dyn gpio::Pin,
120 data_6_pin: &'a dyn gpio::Pin,
121 data_7_pin: &'a dyn gpio::Pin,
122
123 width: Cell<u8>,
124 height: Cell<u8>,
125
126 display_function: Cell<u8>,
127 display_control: Cell<u8>,
128 display_mode: Cell<u8>,
129 num_lines: Cell<u8>,
130 row_offsets: TakeCell<'static, [u8]>,
131
132 alarm: &'a A,
133
134 lcd_status: Cell<LCDStatus>,
135 lcd_after_pulse_status: Cell<LCDStatus>,
136 lcd_after_command_status: Cell<LCDStatus>,
137 lcd_after_delay_status: Cell<LCDStatus>,
138 command_to_finish: Cell<u8>,
139
140 begin_done: Cell<bool>,
141 initialized: Cell<bool>,
142
143 text_screen_client: OptionalCell<&'a dyn TextScreenClient>,
144
145 done_printing: Cell<bool>,
146
147 write_buffer: TakeCell<'static, [u8]>,
148 write_len: Cell<u8>,
149 write_buffer_len: Cell<u8>,
150 write_offset: Cell<u8>,
151}
152
153impl<'a, A: Alarm<'a>> HD44780<'a, A> {
154 pub fn new(
155 rs_pin: &'a dyn gpio::Pin,
156 en_pin: &'a dyn gpio::Pin,
157 data_4_pin: &'a dyn gpio::Pin,
158 data_5_pin: &'a dyn gpio::Pin,
159 data_6_pin: &'a dyn gpio::Pin,
160 data_7_pin: &'a dyn gpio::Pin,
161 row_offsets: &'static mut [u8],
162 alarm: &'a A,
163 width: u8,
164 height: u8,
165 ) -> HD44780<'a, A> {
166 rs_pin.make_output();
167 en_pin.make_output();
168 data_4_pin.make_output();
169 data_5_pin.make_output();
170 data_6_pin.make_output();
171 data_7_pin.make_output();
172 let hd44780 = HD44780 {
173 rs_pin,
174 en_pin,
175 data_4_pin,
176 data_5_pin,
177 data_6_pin,
178 data_7_pin,
179 width: Cell::new(width),
180 height: Cell::new(height),
181 display_function: Cell::new(LCD_4BITMODE | LCD_1LINE | LCD_5X8DOTS),
182 display_control: Cell::new(0),
183 display_mode: Cell::new(0),
184 num_lines: Cell::new(0),
185 row_offsets: TakeCell::new(row_offsets),
186 alarm,
187 lcd_status: Cell::new(LCDStatus::Idle),
188 lcd_after_pulse_status: Cell::new(LCDStatus::Idle),
189 lcd_after_command_status: Cell::new(LCDStatus::Idle),
190 lcd_after_delay_status: Cell::new(LCDStatus::Idle),
191 command_to_finish: Cell::new(0),
192 begin_done: Cell::new(false),
193 initialized: Cell::new(false),
194 text_screen_client: OptionalCell::empty(),
195 done_printing: Cell::new(false),
196 write_buffer: TakeCell::empty(),
197 write_len: Cell::new(0),
198 write_buffer_len: Cell::new(0),
199 write_offset: Cell::new(0),
200 };
201 hd44780.init(width, height);
202
203 hd44780
204 }
205
206 fn init(&self, col: u8, row: u8) {
216 self.begin_done.set(false);
217 self.width.set(col);
218 self.height.set(row);
219
220 if row > 1 {
221 self.display_function
222 .replace(self.display_function.get() | LCD_2LINE);
223 }
224
225 self.num_lines.replace(row);
226 let _ = self.set_rows(0x00, 0x40, 0x00 + col, 0x40 + col);
227 }
228
229 pub fn screen_command(&self, command: usize, op: usize, value: u8) -> Result<(), ErrorCode> {
230 if self.lcd_status.get() == LCDStatus::Idle {
231 match command {
232 1 => {
233 if op == 0 {
234 self.display_control.set(self.display_control.get() | value);
235 } else {
236 self.display_control
237 .set(self.display_control.get() & !value);
238 }
239 self.command_to_finish
240 .replace(LCD_DISPLAYCONTROL | self.display_control.get());
241 self.lcd_command(self.command_to_finish.get(), LCDStatus::Idle);
242 Ok(())
243 }
244
245 2 => {
246 self.lcd_clear(LCDStatus::Idle);
247 Ok(())
248 }
249
250 _ => Err(ErrorCode::INVAL),
251 }
252 } else {
253 Err(ErrorCode::BUSY)
254 }
255 }
256
257 fn set_rows(&self, row0: u8, row1: u8, row2: u8, row3: u8) -> Result<(), ErrorCode> {
263 self.row_offsets.map(|buffer| {
264 buffer[0] = row0;
265 buffer[1] = row1;
266 buffer[2] = row2;
267 buffer[3] = row3;
268 });
269 Ok(())
270 }
271
272 fn pulse(&self, after_pulse_status: LCDStatus) {
283 self.lcd_after_pulse_status.set(after_pulse_status);
284 self.en_pin.clear();
285 self.set_delay(500, LCDStatus::PulseLow);
286 }
287
288 fn write_4_bits(&self, value: u8, next_status: LCDStatus) {
299 if (value >> 0) & 0x01 != 0 {
300 self.data_4_pin.set();
301 } else {
302 self.data_4_pin.clear();
303 }
304
305 if (value >> 1) & 0x01 != 0 {
306 self.data_5_pin.set();
307 } else {
308 self.data_5_pin.clear();
309 }
310
311 if (value >> 2) & 0x01 != 0 {
312 self.data_6_pin.set();
313 } else {
314 self.data_6_pin.clear();
315 }
316
317 if (value >> 3) & 0x01 != 0 {
318 self.data_7_pin.set();
319 } else {
320 self.data_7_pin.clear();
321 }
322
323 self.pulse(next_status);
324 }
325
326 fn continue_ops(&self) {
329 let state = self.lcd_status.get();
330
331 match state {
332 LCDStatus::Idle => {
335 self.text_screen_client.map(|client| {
336 if self.begin_done.get() {
337 self.begin_done.set(false);
338 self.initialized.set(true);
339 client.command_complete(Ok(()));
340 } else if self.write_len.get() > 0 {
341 self.write_character();
342 } else if self.done_printing.get() {
343 self.done_printing.set(false);
344 if self.write_buffer.is_some() {
345 self.write_buffer.take().map(|buffer| {
346 client.write_complete(
347 buffer,
348 self.write_buffer_len.get() as usize,
349 Ok(()),
350 )
351 });
352 }
353 } else {
354 client.command_complete(Ok(()));
355 }
356 });
357 }
358
359 LCDStatus::Begin0 => {
360 self.rs_pin.clear();
361 self.en_pin.clear();
362
363 if (self.display_function.get() & LCD_8BITMODE) == 0 {
364 self.write_4_bits(0x03, LCDStatus::Begin0_1);
365 } else {
366 self.rs_pin.clear();
367 self.lcd_command(
368 (LCD_FUNCTIONSET | self.display_function.get()) >> 4,
369 LCDStatus::Begin4,
370 );
371 }
372 }
373
374 LCDStatus::Begin0_1 => {
375 self.set_delay(200, LCDStatus::Begin1);
376 }
377
378 LCDStatus::Begin1 => {
379 self.write_4_bits(0x03, LCDStatus::Begin1_2);
380 }
381
382 LCDStatus::Begin1_2 => {
383 self.set_delay(200, LCDStatus::Begin2);
384 }
385
386 LCDStatus::Begin2 => {
387 self.write_4_bits(0x03, LCDStatus::Begin2_3);
388 }
389
390 LCDStatus::Begin2_3 => {
391 self.set_delay(500, LCDStatus::Begin3);
392 }
393
394 LCDStatus::Begin3 => {
395 self.write_4_bits(0x02, LCDStatus::Begin9);
396 }
397
398 LCDStatus::Begin4 => {
399 self.command_to_finish
400 .set(LCD_FUNCTIONSET | self.display_function.get());
401 self.lcd_command(
402 LCD_FUNCTIONSET | self.display_function.get(),
403 LCDStatus::Begin5,
404 );
405 }
406
407 LCDStatus::Begin5 => self.set_delay(200, LCDStatus::Begin6),
408
409 LCDStatus::Begin6 => {
410 self.lcd_command(
411 LCD_FUNCTIONSET | self.display_function.get(),
412 LCDStatus::Begin7,
413 );
414 }
415
416 LCDStatus::Begin7 => {
417 self.set_delay(500, LCDStatus::Begin8);
418 }
419
420 LCDStatus::Begin8 => {
421 self.lcd_command(
422 LCD_FUNCTIONSET | self.display_function.get(),
423 LCDStatus::Begin9,
424 );
425 }
426
427 LCDStatus::Begin9 => {
428 self.command_to_finish
429 .set(LCD_FUNCTIONSET | self.display_function.get());
430 self.lcd_command(
431 LCD_FUNCTIONSET | self.display_function.get(),
432 LCDStatus::Begin10,
433 );
434 }
435
436 LCDStatus::Begin10 => {
437 self.display_control
438 .set(LCD_DISPLAYON | LCD_CURSORON | LCD_BLINKOFF);
439 self.lcd_display(LCDStatus::Begin11);
440 }
441
442 LCDStatus::Begin11 => {
443 self.lcd_clear(LCDStatus::Begin12);
444 }
445
446 LCDStatus::Begin12 => {
447 self.display_mode
448 .set(LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
449 self.command_to_finish
450 .set(LCD_ENTRYMODESET | self.display_mode.get());
451 self.begin_done.set(true);
452 self.lcd_command(self.command_to_finish.get(), LCDStatus::Idle);
453 }
454
455 LCDStatus::Clear => {
456 self.set_delay(500, self.lcd_after_delay_status.get());
457 }
458
459 LCDStatus::Printing => {
460 self.write_4_bits(self.command_to_finish.get(), LCDStatus::Idle);
461 }
462
463 LCDStatus::PulseLow => {
464 self.en_pin.set();
465 self.set_delay(500, LCDStatus::PulseHigh);
466 }
467
468 LCDStatus::Command => {
469 self.write_4_bits(
470 self.command_to_finish.get(),
471 self.lcd_after_command_status.get(),
472 );
473 }
474
475 LCDStatus::PulseHigh => {
476 self.en_pin.clear();
477 self.set_delay(500, self.lcd_after_pulse_status.get());
478 }
479 }
480 }
481
482 fn lcd_display(&self, next_state: LCDStatus) {
492 self.command_to_finish
493 .set(LCD_DISPLAYCONTROL | self.display_control.get());
494 self.lcd_command(LCD_DISPLAYCONTROL | self.display_control.get(), next_state);
495 }
496
497 fn lcd_command(&self, value: u8, next_state: LCDStatus) {
510 self.lcd_after_command_status.set(next_state);
511 self.command_to_finish.set(value);
512 self.rs_pin.clear();
513 self.write_4_bits(value >> 4, LCDStatus::Command);
514 }
515
516 fn lcd_clear(&self, next_state: LCDStatus) {
525 self.lcd_after_delay_status.set(next_state);
526 self.lcd_command(LCD_CLEARDISPLAY, LCDStatus::Clear);
527 }
528
529 fn set_delay(&self, timer: u32, next_status: LCDStatus) {
542 self.lcd_status.set(next_status);
543 self.alarm.set_alarm(
544 self.alarm.now(),
545 A::Ticks::from(<A::Frequency>::frequency() / timer),
546 );
547 }
548
549 fn write_character(&self) {
556 let offset = self.write_offset.get() as usize;
557 let mut value = 0;
558 self.write_buffer.map(|buffer| {
559 value = buffer[offset];
560 });
561 self.done_printing.set(false);
562 self.write_offset.set(self.write_offset.get() + 1);
563 self.write_len.set(self.write_len.get() - 1);
564 if self.write_len.get() == 0 {
565 self.done_printing.set(true);
566 }
567 self.rs_pin.set();
568 self.command_to_finish.set(value);
569 self.write_4_bits(value >> 4, LCDStatus::Printing);
570 }
571
572 fn set_cursor(&self, col: u8, row: u8) {
583 let mut value: u8 = 0;
584 self.row_offsets.map(|buffer| {
585 value = buffer[row as usize];
586 });
587 self.command_to_finish
588 .replace(LCD_SETDDRAMADDR | (col + value));
589 self.lcd_command(self.command_to_finish.get(), LCDStatus::Idle);
590 }
591}
592
593impl<'a, A: Alarm<'a>> time::AlarmClient for HD44780<'a, A> {
594 fn alarm(&self) {
597 self.continue_ops();
598 }
599}
600
601impl<'a, A: Alarm<'a>> TextScreen<'a> for HD44780<'a, A> {
602 fn get_size(&self) -> (usize, usize) {
603 (16, 2)
604 }
605
606 fn print(
607 &self,
608 buffer: &'static mut [u8],
609 len: usize,
610 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
611 if self.lcd_status.get() == LCDStatus::Idle {
612 self.write_buffer.replace(buffer);
613 self.write_len.replace(len as u8);
614 self.write_buffer_len.replace(len as u8);
615 self.write_offset.set(0);
616 self.write_character();
617 Ok(())
618 } else {
619 Err((ErrorCode::BUSY, buffer))
620 }
621 }
622
623 fn set_cursor(&self, x_position: usize, y_position: usize) -> Result<(), ErrorCode> {
624 if self.lcd_status.get() == LCDStatus::Idle {
625 let mut line_number: u8 = y_position as u8;
626 if line_number >= 4 {
627 line_number = 3;
628 }
629
630 if line_number >= self.num_lines.get() {
631 line_number = self.num_lines.get() - 1;
632 }
633
634 self.set_cursor(x_position as u8, line_number);
635 Ok(())
636 } else {
637 Err(ErrorCode::BUSY)
638 }
639 }
640
641 fn hide_cursor(&self) -> Result<(), ErrorCode> {
642 self.screen_command(1, 1, LCD_CURSORON)
643 }
644
645 fn show_cursor(&self) -> Result<(), ErrorCode> {
646 self.screen_command(1, 0, LCD_CURSORON)
647 }
648
649 fn blink_cursor_on(&self) -> Result<(), ErrorCode> {
650 self.screen_command(1, 0, LCD_BLINKON)
651 }
652
653 fn blink_cursor_off(&self) -> Result<(), ErrorCode> {
654 self.screen_command(1, 1, LCD_BLINKON)
655 }
656
657 fn display_on(&self) -> Result<(), ErrorCode> {
658 if !self.initialized.get() {
659 if self.lcd_status.get() == LCDStatus::Idle {
660 self.set_delay(10, LCDStatus::Begin0);
661 Ok(())
662 } else {
663 Err(ErrorCode::BUSY)
664 }
665 } else {
666 self.screen_command(1, 0, LCD_DISPLAYON)
667 }
668 }
669
670 fn display_off(&self) -> Result<(), ErrorCode> {
671 self.screen_command(1, 1, LCD_DISPLAYON)
672 }
673
674 fn clear(&self) -> Result<(), ErrorCode> {
675 self.screen_command(2, 0, 0)
676 }
677
678 fn set_client(&self, client: Option<&'a dyn TextScreenClient>) {
679 if let Some(client) = client {
680 self.text_screen_client.set(client);
681 } else {
682 self.text_screen_client.clear();
683 }
684 }
685}