hd44780_controller/controller/
async_controller.rs1use core::marker::PhantomData;
2
3use crate::{
4 charset::{InfallibleCharset, 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_raw_str(
150 &mut self,
151 raw_code: impl Iterator<Item = u8>,
152 ) -> Result<(), super::Error> {
153 for c in raw_code {
154 self.write_raw_char(c).await?;
155 }
156 Ok(())
157 }
158
159 pub async fn write_raw_line(
160 &mut self,
161 row: u8,
162 raw_code: impl Iterator<Item = u8>,
163 ) -> Result<(), super::Error> {
164 self.set_cursor_position(row, 0).await?;
165 for (_, c) in (0..40).zip(raw_code.chain(core::iter::repeat(b' '))) {
166 self.write_raw_char(c).await?;
167 }
168 Ok(())
169 }
170
171 pub async fn write_char_with_charset<C: InfallibleCharset>(
172 &mut self,
173 c: char,
174 charset: C,
175 ) -> Result<(), super::Error> {
176 self.write_raw_char(charset.char_to_code(c)).await
177 }
178
179 pub async fn write_str_with_charset<C: InfallibleCharset>(
180 &mut self,
181 s: impl Iterator<Item = char>,
182 charset: C,
183 ) -> Result<(), super::Error> {
184 self.write_raw_str(s.map(|c| charset.char_to_code(c))).await
185 }
186
187 pub async fn write_line_with_charset<C: InfallibleCharset>(
188 &mut self,
189 row: u8,
190 s: impl Iterator<Item = char>,
191 charset: C,
192 ) -> Result<(), super::Error> {
193 self.set_cursor_position(row, 0).await?;
194 self.write_raw_line(row, s.map(|c| charset.char_to_code(c)))
195 .await
196 }
197
198 pub async fn write_char(&mut self, c: char) -> Result<(), super::Error> {
199 self.write_char_with_charset(c, MinimalCharset::BLANK_FALLBACK)
200 .await
201 }
202
203 pub async fn write_str(&mut self, s: impl Iterator<Item = char>) -> Result<(), super::Error> {
204 self.write_str_with_charset(s, MinimalCharset::BLANK_FALLBACK)
205 .await
206 }
207
208 pub async fn write_line(
209 &mut self,
210 row: u8,
211 s: impl Iterator<Item = char>,
212 ) -> Result<(), super::Error> {
213 self.write_line_with_charset(row, s, MinimalCharset::BLANK_FALLBACK)
214 .await
215 }
216
217 #[cfg(feature = "fmt")]
218 #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
219 pub async fn write_line_fmt_with_charset<C: InfallibleCharset, const BUFFER_SIZE: usize>(
220 &mut self,
221 row: u8,
222 args: core::fmt::Arguments<'_>,
223 charset: C,
224 ) -> Result<(), super::Error> {
225 let mut buffer = heapless::String::<BUFFER_SIZE>::new();
226 let _ = core::fmt::write(&mut buffer, args);
228 self.write_line_with_charset(row, buffer.chars(), charset)
229 .await
230 }
231
232 #[cfg(feature = "fmt")]
233 #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
234 pub async fn write_line_fmt<const BUFFER_SIZE: usize>(
235 &mut self,
236 row: u8,
237 args: core::fmt::Arguments<'_>,
238 ) -> Result<(), super::Error> {
239 self.write_line_fmt_with_charset::<_, BUFFER_SIZE>(
240 row,
241 args,
242 MinimalCharset::BLANK_FALLBACK,
243 )
244 .await
245 }
246
247 #[cfg(feature = "fmt")]
248 #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
249 pub async fn write_fmt_with_charset<C: InfallibleCharset, const BUFFER_SIZE: usize>(
250 &mut self,
251 args: core::fmt::Arguments<'_>,
252 charset: C,
253 ) -> Result<(), super::Error> {
254 let mut buffer = heapless::String::<BUFFER_SIZE>::new();
255 let _ = core::fmt::write(&mut buffer, args);
257 self.write_str_with_charset(buffer.chars(), charset).await
258 }
259
260 #[cfg(feature = "fmt")]
261 #[cfg_attr(docsrs, doc(cfg(feature = "fmt")))]
262 pub async fn write_fmt<const BUFFER_SIZE: usize>(
263 &mut self,
264 args: core::fmt::Arguments<'_>,
265 ) -> Result<(), super::Error> {
266 self.write_fmt_with_charset::<_, BUFFER_SIZE>(args, MinimalCharset::BLANK_FALLBACK)
268 .await
269 }
270
271 pub fn device(&mut self) -> &mut D {
272 &mut self.device
273 }
274
275 pub fn release(self) -> D {
276 self.device
277 }
278}