hd44780_controller/controller/
async_controller.rs1use 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 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 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}