hd44780_controller/controller/
async_controller.rs

1use core::marker::PhantomData;
2
3use crate::{
4    charset::{Charset, FallbackCharset, MinimalCharset},
5    command::{Commands, *},
6    device::{AsyncDevice, CommandExtAsync},
7};
8
9use super::{config::*, state::*, Controller};
10
11impl<D: AsyncDevice> Controller<D, Uninit> {
12    pub async fn init(mut self) -> Result<Controller<D, Init>, super::Error> {
13        self.device
14            .execute_commands_async::<Commands, _>(&[
15                Enter4Bit.into(),
16                FunctionSet {
17                    data_length: self.initial_config.data_length,
18                    number_of_lines: self.initial_config.lines,
19                    character_font: self.initial_config.font,
20                }
21                .into(),
22            ])
23            .await?;
24
25        let mut controller: Controller<_, Init> = Controller {
26            device: self.device,
27            initial_config: self.initial_config,
28            runtime_config: self.runtime_config,
29            _state: PhantomData,
30        };
31
32        controller.set_runtime_config(self.runtime_config).await?;
33        controller.clear().await?;
34
35        Ok(controller)
36    }
37
38    pub fn release(self) -> D {
39        self.device
40    }
41}
42
43impl<D: AsyncDevice> Controller<D, Init> {
44    pub async fn clear(&mut self) -> Result<(), super::Error> {
45        Ok(self.device.execute_command_async(&ClearDisplay).await?)
46    }
47
48    pub async fn reset(&mut self) -> Result<(), super::Error> {
49        self.clear().await?;
50        self.set_runtime_config(RuntimeConfig::default()).await?;
51        self.set_cursor_position(0, 0).await
52    }
53
54    pub async fn return_home(&mut self) -> Result<(), super::Error> {
55        Ok(self.device.execute_command_async(&ReturnHome).await?)
56    }
57
58    pub fn initial_config(&self) -> InitialConfig {
59        self.initial_config
60    }
61
62    pub fn runtime_config(&self) -> RuntimeConfig {
63        self.runtime_config
64    }
65
66    pub async fn set_runtime_config(&mut self, cfg: RuntimeConfig) -> Result<(), super::Error> {
67        self.device
68            .execute_commands_async::<Commands, _>(&[
69                DisplayOnOff {
70                    display: cfg.display,
71                    cursor: cfg.cursor,
72                    blinking: cfg.blink,
73                }
74                .into(),
75                EntryModeSet {
76                    cursor_move_direction: cfg.cursor_direction,
77                    shift: cfg.shift,
78                }
79                .into(),
80                SetBacklight(cfg.backlight).into(),
81            ])
82            .await?;
83
84        self.runtime_config = cfg;
85
86        Ok(())
87    }
88
89    pub fn backlight(&self) -> bool {
90        self.runtime_config.backlight
91    }
92
93    pub async fn set_backlight(&mut self, state: bool) -> Result<(), super::Error> {
94        let new_config = RuntimeConfig {
95            backlight: state,
96            ..self.runtime_config()
97        };
98        self.set_runtime_config(new_config).await
99    }
100
101    pub fn cursor_blinking(&self) -> bool {
102        self.runtime_config.blink
103    }
104
105    pub async fn set_cursor_blinking(&mut self, state: bool) -> Result<(), super::Error> {
106        let new_config = RuntimeConfig {
107            blink: state,
108            ..self.runtime_config()
109        };
110        self.set_runtime_config(new_config).await
111    }
112
113    pub fn cursor_visible(&self) -> bool {
114        self.runtime_config.cursor
115    }
116
117    pub async fn set_cursor_visible(&mut self, state: bool) -> Result<(), super::Error> {
118        let new_config = RuntimeConfig {
119            cursor: state,
120            ..self.runtime_config()
121        };
122        self.set_runtime_config(new_config).await
123    }
124
125    pub async fn set_cursor_position(&mut self, row: u8, col: u8) -> Result<(), super::Error> {
126        if row >= 4 || col >= 0x40 {
127            return Err(super::Error::OutOfBounds);
128        }
129
130        let addr = match (row, col) {
131            (0, c) => c,
132            (1, c) => 0x40 + c,
133            (2, c) => 0x14 + c,
134            (3, c) => 0x54 + c,
135            _ => unreachable!(),
136        };
137
138        self.device
139            .execute_command_async(&SetDDRamAddress(addr))
140            .await?;
141
142        Ok(())
143    }
144
145    pub async fn write_raw_char(&mut self, code: u8) -> Result<(), super::Error> {
146        Ok(self.device.execute_command_async(&WriteChar(code)).await?)
147    }
148
149    pub async fn write_char_with_charset<C: Charset, const FALLBACK_CODE: u8>(
150        &mut self,
151        c: char,
152        charset: &FallbackCharset<C, FALLBACK_CODE>,
153    ) -> Result<(), super::Error> {
154        self.write_raw_char(charset.char_to_code(c)).await
155    }
156
157    pub async fn write_char(&mut self, c: char) -> Result<(), super::Error> {
158        self.write_char_with_charset(c, &MinimalCharset::BLANK_FALLBACK)
159            .await
160    }
161
162    pub async fn write_raw_str(&mut self, raw_code: &[u8]) -> Result<(), super::Error> {
163        for c in raw_code.iter().copied() {
164            self.write_raw_char(c).await?;
165        }
166        Ok(())
167    }
168
169    pub async fn write_str_with_charset<C: Charset, const FALLBACK_CODE: u8>(
170        &mut self,
171        s: &str,
172        charset: &FallbackCharset<C, FALLBACK_CODE>,
173    ) -> Result<(), super::Error> {
174        for c in s.chars() {
175            self.write_char_with_charset(c, charset).await?;
176        }
177        Ok(())
178    }
179
180    pub async fn write_str(&mut self, s: &str) -> Result<(), super::Error> {
181        self.write_str_with_charset(s, &MinimalCharset::BLANK_FALLBACK)
182            .await
183    }
184
185    #[cfg(feature = "fmt")]
186    #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
187    pub async fn write_fmt_with_charset<
188        C: Charset,
189        const FALLBACK_CODE: u8,
190        const BUFFER_SIZE: usize,
191    >(
192        &mut self,
193        args: core::fmt::Arguments<'_>,
194        charset: &FallbackCharset<C, FALLBACK_CODE>,
195    ) -> Result<(), super::Error> {
196        let mut buffer = heapless::String::<BUFFER_SIZE>::new();
197        // string formatting should be infallible
198        let _ = core::fmt::write(&mut buffer, args);
199        self.write_str_with_charset(&buffer, charset).await
200    }
201
202    #[cfg(feature = "fmt")]
203    #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
204    pub async fn write_fmt<const BUFFER_SIZE: usize>(
205        &mut self,
206        args: core::fmt::Arguments<'_>,
207    ) -> Result<(), super::Error> {
208        // placeholders for const generic is not yet supported.
209        self.write_fmt_with_charset::<_, b' ', BUFFER_SIZE>(args, &MinimalCharset::BLANK_FALLBACK)
210            .await
211    }
212
213    pub fn device(&mut self) -> &mut D {
214        &mut self.device
215    }
216
217    pub fn release(self) -> D {
218        self.device
219    }
220}