1#![no_std]
2
3mod control_word;
4mod font5x7;
5
6pub use control_word::PeakCurrent;
7use control_word::*;
8use core::cell::RefCell;
9use embedded_hal::digital::{ErrorType, OutputPin};
10pub use font5x7::FONT5X7;
11use num_traits::{ToPrimitive, Zero};
12
13pub const CHAR_HEIGHT: usize = 7;
14pub const CHAR_WIDTH: usize = 5;
15const DEVICE_CHARS: u8 = 4;
16
17pub struct UnconfiguredPin;
18
19impl OutputPin for UnconfiguredPin {
20 fn set_low(&mut self) -> Result<(), Self::Error> {
21 Ok(())
22 }
23
24 fn set_high(&mut self) -> Result<(), Self::Error> {
25 Ok(())
26 }
27}
28
29impl ErrorType for UnconfiguredPin {
30 type Error = core::convert::Infallible;
31}
32
33#[derive(Debug)]
34pub enum Hcms29xxError<PinErr> {
35 PinNotConfigured,
36 ValueTooLong,
37 DataPinError(PinErr),
38 RsPinError(PinErr),
39 ClkPinError(PinErr),
40 CePinError(PinErr),
41 BlankPinError(PinErr),
42 OscSelPinError(PinErr),
43 ResetPinError(PinErr),
44}
45
46pub struct Hcms29xx<
47 const NUM_CHARS: usize,
48 DataPin,
49 RsPin,
50 ClkPin,
51 CePin,
52 BlankPin = UnconfiguredPin,
53 OscSelPin = UnconfiguredPin,
54 ResetPin = UnconfiguredPin,
55> where
56 DataPin: OutputPin,
57 RsPin: OutputPin,
58 ClkPin: OutputPin,
59 CePin: OutputPin,
60 BlankPin: OutputPin,
61 OscSelPin: OutputPin,
62 ResetPin: OutputPin,
63{
64 data: RefCell<DataPin>,
65 rs: RefCell<RsPin>,
66 clk: RefCell<ClkPin>,
67 ce: RefCell<CePin>,
68 blank: RefCell<BlankPin>,
69 osc_sel: RefCell<OscSelPin>,
70 reset: RefCell<ResetPin>,
71 control_word_0: ControlWord0,
72 control_word_1: ControlWord1,
73 data_out_mode: DataOutMode,
75 font_ascii_start_index: u8,
76}
77
78impl<
79 const NUM_CHARS: usize,
80 DataPin,
81 RsPin,
82 ClkPin,
83 CePin,
84 BlankPin,
85 OscSelPin,
86 ResetPin,
87 PinErr,
88 > Hcms29xx<NUM_CHARS, DataPin, RsPin, ClkPin, CePin, BlankPin, OscSelPin, ResetPin>
89where
90 DataPin: OutputPin + ErrorType<Error = PinErr>,
91 RsPin: OutputPin + ErrorType<Error = PinErr>,
92 ClkPin: OutputPin + ErrorType<Error = PinErr>,
93 CePin: OutputPin + ErrorType<Error = PinErr>,
94 BlankPin: OutputPin + ErrorType<Error = PinErr>,
95 OscSelPin: OutputPin + ErrorType<Error = PinErr>,
96 ResetPin: OutputPin + ErrorType<Error = PinErr>,
97{
98 const _ASSERT_MIN_CHARS: () = assert!(NUM_CHARS >= 4, "NUM_CHARS must be at least 4");
99
100 pub fn new(
101 data: DataPin,
102 rs: RsPin,
103 clk: ClkPin,
104 ce: CePin,
105 blank: BlankPin,
106 osc_sel: OscSelPin,
107 reset: ResetPin,
108 ) -> Result<Self, Hcms29xxError<PinErr>> {
109 let data_ref_cell = RefCell::new(data);
110 let rs_ref_cell = RefCell::new(rs);
111 let clk_ref_cell = RefCell::new(clk);
112 let ce_ref_cell = RefCell::new(ce);
113 let blank_ref_cell = RefCell::new(blank);
114 let osc_sel_ref_cell = RefCell::new(osc_sel);
115 let reset_ref_cell = RefCell::new(reset);
116
117 data_ref_cell
118 .borrow_mut()
119 .set_low()
120 .map_err(Hcms29xxError::DataPinError)?;
121 ce_ref_cell
122 .borrow_mut()
123 .set_high()
124 .map_err(Hcms29xxError::CePinError)?;
125 blank_ref_cell
126 .borrow_mut()
127 .set_high()
128 .map_err(Hcms29xxError::BlankPinError)?;
129 osc_sel_ref_cell
131 .borrow_mut()
132 .set_high()
133 .map_err(Hcms29xxError::OscSelPinError)?;
134 reset_ref_cell
135 .borrow_mut()
136 .set_high()
137 .map_err(Hcms29xxError::ResetPinError)?;
138
139 Ok(Hcms29xx {
140 data: data_ref_cell,
141 rs: rs_ref_cell,
142 clk: clk_ref_cell,
143 ce: ce_ref_cell,
144 blank: blank_ref_cell,
145 osc_sel: osc_sel_ref_cell,
146 reset: reset_ref_cell,
147 control_word_0: ControlWord0::default(),
148 control_word_1: ControlWord1::default(),
149 data_out_mode: DataOutMode::Serial,
150 #[cfg(feature = "avr-progmem")]
151 font_ascii_start_index: FONT5X7.load_at(0) - 1,
152 #[cfg(not(feature = "avr-progmem"))]
153 font_ascii_start_index: FONT5X7[0] - 1,
154 })
155 }
156
157 pub fn destroy(self) -> (DataPin, RsPin, ClkPin, CePin, BlankPin, OscSelPin, ResetPin) {
158 (
159 self.data.into_inner(),
160 self.rs.into_inner(),
161 self.clk.into_inner(),
162 self.ce.into_inner(),
163 self.blank.into_inner(),
164 self.osc_sel.into_inner(),
165 self.reset.into_inner(),
166 )
167 }
168
169 pub fn begin(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
170 self.clear()?;
171
172 self.update_control_word(self.control_word_0.bits())?;
173 self.update_control_word(self.control_word_1.bits())?;
174
175 Ok(())
176 }
177
178 pub fn clear(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
179 self.set_dot_data()?;
180 for _ in 0..NUM_CHARS * CHAR_WIDTH {
181 self.send_byte(0x00)?;
182 }
183 self.end_transfer()?;
184 Ok(())
185 }
186
187 pub fn print_ascii_bytes(&mut self, bytes: &[u8]) -> Result<(), Hcms29xxError<PinErr>> {
188 self.set_dot_data()?;
189 for i in 0..NUM_CHARS {
190 if i >= bytes.len() || bytes[i] < self.font_ascii_start_index {
191 break;
192 }
193 let char_index: usize = (bytes[i] - self.font_ascii_start_index) as usize * CHAR_WIDTH;
194 for col in 0..CHAR_WIDTH {
195 #[cfg(feature = "avr-progmem")]
196 self.send_byte(FONT5X7.load_at(char_index + col))?;
197 #[cfg(not(feature = "avr-progmem"))]
198 self.send_byte(FONT5X7[char_index + col])?;
199 }
200 }
201 self.end_transfer()?;
202 Ok(())
203 }
204
205 pub fn print_cols(&mut self, cols: &[u8]) -> Result<(), Hcms29xxError<PinErr>> {
206 self.set_dot_data()?;
207 for &byte in cols {
208 self.send_byte(byte)?;
209 }
210 self.end_transfer()?;
211 Ok(())
212 }
213
214 pub fn print_int<T>(&mut self, value: T) -> Result<(), Hcms29xxError<PinErr>>
215 where
216 T: Copy + Zero + ToPrimitive,
217 {
218 if NUM_CHARS <= 10 {
220 self.print_int_32bit(value)
221 } else {
222 self.print_int_64bit(value)
223 }
224 }
225
226 fn print_int_32bit<T>(&mut self, value: T) -> Result<(), Hcms29xxError<PinErr>>
227 where
228 T: Copy + Zero + ToPrimitive,
229 {
230 const fn max_unsigned_for_chars(chars: usize) -> u32 {
231 let mut power_of_10 = 1u32;
232 let mut i = 0;
233 while i < chars {
234 power_of_10 = power_of_10.saturating_mul(10);
235 i += 1;
236 }
237 power_of_10.saturating_sub(1)
238 }
239
240 const fn max_signed_for_chars(chars: usize) -> i32 {
241 max_unsigned_for_chars(chars - 1) as i32
242 }
243
244 let (mut has_sign, mut value) = if let Some(signed_val) = value.to_i32() {
245 let max_signed = max_signed_for_chars(NUM_CHARS);
246 if signed_val < -max_signed || signed_val > max_signed {
247 return Err(Hcms29xxError::ValueTooLong);
248 }
249 if signed_val < 0 {
250 (true, (-signed_val) as u32)
251 } else {
252 (false, signed_val as u32)
253 }
254 } else if let Some(unsigned_val) = value.to_u32() {
255 let max_unsigned = max_unsigned_for_chars(NUM_CHARS);
256 if unsigned_val > max_unsigned {
257 return Err(Hcms29xxError::ValueTooLong);
258 }
259 (false, unsigned_val)
260 } else {
261 return Err(Hcms29xxError::ValueTooLong);
262 };
263
264 let mut buf = [b' '; NUM_CHARS];
265 buf[NUM_CHARS - 1] = b'0';
266
267 for index in (0..NUM_CHARS).rev() {
268 buf[index] = if value > 0 {
269 let digit = b'0' + (value % 10) as u8;
270 value /= 10;
271 digit
272 } else if has_sign {
273 has_sign = false;
274 b'-'
275 } else {
276 break;
277 };
278 }
279
280 self.print_ascii_bytes(&buf)
281 }
282
283 fn print_int_64bit<T>(&mut self, value: T) -> Result<(), Hcms29xxError<PinErr>>
284 where
285 T: Copy + Zero + ToPrimitive,
286 {
287 const fn max_unsigned_64_for_chars(chars: usize) -> u64 {
288 let mut power_of_10 = 1u64;
289 let mut i = 0;
290 while i < chars {
291 power_of_10 = power_of_10.saturating_mul(10);
292 i += 1;
293 }
294 power_of_10.saturating_sub(1)
295 }
296
297 const fn max_signed_64_for_chars(chars: usize) -> i64 {
298 max_unsigned_64_for_chars(chars - 1) as i64
299 }
300
301 let (mut has_sign, mut value) = if let Some(signed_val) = value.to_i64() {
302 let max_signed = max_signed_64_for_chars(NUM_CHARS);
303 if signed_val < -max_signed || signed_val > max_signed {
304 return Err(Hcms29xxError::ValueTooLong);
305 }
306 if signed_val < 0 {
307 (true, (-signed_val) as u64)
308 } else {
309 (false, signed_val as u64)
310 }
311 } else if let Some(unsigned_val) = value.to_u64() {
312 let max_unsigned = max_unsigned_64_for_chars(NUM_CHARS);
313 if unsigned_val > max_unsigned {
314 return Err(Hcms29xxError::ValueTooLong);
315 }
316 (false, unsigned_val)
317 } else {
318 return Err(Hcms29xxError::ValueTooLong);
319 };
320
321 let mut buf = [b' '; NUM_CHARS];
322 buf[NUM_CHARS - 1] = b'0';
323
324 for index in (0..NUM_CHARS).rev() {
325 buf[index] = if value > 0 {
326 let digit = b'0' + (value % 10) as u8;
327 value /= 10;
328 digit
329 } else if has_sign {
330 has_sign = false;
331 b'-'
332 } else {
333 break;
334 };
335 }
336
337 self.print_ascii_bytes(&buf)
338 }
339
340 #[cfg(feature = "print_float")]
341 pub fn print_float<T>(&mut self, value: T, precision: u8) -> Result<(), Hcms29xxError<PinErr>>
342 where
343 T: Copy + ToPrimitive,
344 {
345 let float_val = value.to_f32().ok_or(Hcms29xxError::ValueTooLong)?;
346 let mut buf = [b' '; NUM_CHARS];
347
348 if float_val.is_nan() {
350 buf[(NUM_CHARS - 3)..].copy_from_slice(b"NaN");
351 return self.print_ascii_bytes(&buf);
352 }
353 if float_val.is_infinite() {
354 let inf_str = if float_val.is_sign_positive() {
355 b"+Inf"
356 } else {
357 b"-Inf"
358 };
359 buf[(NUM_CHARS - inf_str.len())..].copy_from_slice(inf_str);
360 return self.print_ascii_bytes(&buf);
361 }
362
363 let is_negative = float_val.is_sign_negative();
364 let abs_val = float_val.abs();
365
366 let integer_digits = if abs_val < 1.0 {
368 1
369 } else {
370 let mut temp = abs_val as u32;
371 let mut digits = 0;
372 while temp > 0 {
373 digits += 1;
374 temp /= 10;
375 }
376 digits
377 };
378 let total_chars = (if is_negative { 1 } else { 0 })
379 + integer_digits
380 + (if precision > 0 { 1 } else { 0 })
381 + precision as usize;
382 if total_chars > NUM_CHARS {
383 return Err(Hcms29xxError::ValueTooLong);
384 }
385
386 let mut pos = NUM_CHARS;
388 let mut scale_factor = 1.0f32;
389 for _ in 0..precision {
390 scale_factor *= 10.0;
391 }
392 let rounded_val = abs_val * scale_factor + 0.5;
393 let mut digits = rounded_val as u32;
394
395 for _ in 0..precision {
396 pos -= 1;
397 buf[pos] = b'0' + (digits % 10) as u8;
398 digits /= 10;
399 }
400
401 if precision > 0 {
402 pos -= 1;
403 buf[pos] = b'.';
404 }
405
406 if digits == 0 {
407 pos -= 1;
408 buf[pos] = b'0';
409 } else {
410 while digits > 0 {
411 pos -= 1;
412 buf[pos] = b'0' + (digits % 10) as u8;
413 digits /= 10;
414 }
415 }
416
417 if is_negative {
418 pos -= 1;
419 buf[pos] = b'-';
420 }
421
422 self.print_ascii_bytes(&buf)
423 }
424
425 #[deprecated(since = "0.2.0", note = "Use print_int instead")]
426 pub fn print_i32(&mut self, value: i32) -> Result<(), Hcms29xxError<PinErr>> {
427 self.print_int_32bit(value)
428 }
429
430 #[deprecated(since = "0.2.0", note = "Use print_int instead")]
431 pub fn print_u32(&mut self, value: u32) -> Result<(), Hcms29xxError<PinErr>> {
432 self.print_int_32bit(value)
433 }
434
435 pub fn display_blank(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
436 self.blank
437 .borrow_mut()
438 .set_high()
439 .map_err(Hcms29xxError::BlankPinError)?;
440 Ok(())
441 }
442
443 pub fn display_sleep(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
444 self.control_word_0.set_wake_bit(SleepMode::Sleep);
445 self.update_control_word(self.control_word_0.bits())?;
446 Ok(())
447 }
448
449 pub fn display_wake(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
450 self.control_word_0.set_wake_bit(SleepMode::Normal);
451 self.update_control_word(self.control_word_0.bits())?;
452 Ok(())
453 }
454
455 pub fn display_unblank(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
456 self.blank
457 .borrow_mut()
458 .set_low()
459 .map_err(Hcms29xxError::BlankPinError)?;
460 Ok(())
461 }
462
463 pub fn reset(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
464 self.reset
465 .borrow_mut()
466 .set_low()
467 .map_err(Hcms29xxError::ResetPinError)?;
468 self.reset
469 .borrow_mut()
470 .set_high()
471 .map_err(Hcms29xxError::ResetPinError)?;
472 Ok(())
473 }
474
475 pub fn set_brightness(&mut self, brightness: u8) -> Result<(), Hcms29xxError<PinErr>> {
476 self.control_word_0.set_brightness_bits(brightness);
477 self.update_control_word(self.control_word_0.bits())?;
478 Ok(())
479 }
480
481 pub fn set_peak_current(&mut self, current: PeakCurrent) -> Result<(), Hcms29xxError<PinErr>> {
482 self.control_word_0.set_peak_current_bits(current);
483 self.update_control_word(self.control_word_0.bits())?;
484 Ok(())
485 }
486
487 pub fn set_ext_osc_prescale_direct(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
488 self.control_word_1
489 .set_ext_osc_prescaler_bit(ExtOscPrescaler::Direct);
490 self.update_control_word(self.control_word_1.bits())?;
491 Ok(())
492 }
493
494 pub fn set_ext_osc_prescale_div8(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
495 self.control_word_1
496 .set_ext_osc_prescaler_bit(ExtOscPrescaler::Div8);
497 self.update_control_word(self.control_word_1.bits())?;
498 Ok(())
499 }
500
501 pub fn set_ext_osc(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
502 self.osc_sel
503 .borrow_mut()
504 .set_low()
505 .map_err(Hcms29xxError::OscSelPinError)?;
506 Ok(())
507 }
508
509 pub fn set_int_osc(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
510 self.osc_sel
511 .borrow_mut()
512 .set_high()
513 .map_err(Hcms29xxError::OscSelPinError)?;
514 Ok(())
515 }
516
517 pub fn set_serial_data_out(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
518 self.control_word_1
519 .set_data_out_mode_bit(DataOutMode::Serial);
520 self.update_control_word(self.control_word_1.bits())?;
521
522 self.data_out_mode = DataOutMode::Serial;
524
525 Ok(())
526 }
527
528 pub fn set_simultaneous_data_out(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
529 self.control_word_1
530 .set_data_out_mode_bit(DataOutMode::Simultaneous);
531 self.update_control_word(self.control_word_1.bits())?;
532
533 self.data_out_mode = DataOutMode::Simultaneous;
535
536 Ok(())
537 }
538
539 fn update_control_word(&mut self, control_word: u8) -> Result<(), Hcms29xxError<PinErr>> {
540 let times_to_send = if self.data_out_mode == DataOutMode::Serial {
541 NUM_CHARS as u8 / DEVICE_CHARS
542 } else {
543 1
544 };
545
546 self.set_control_data()?;
547 for _ in 0..times_to_send {
548 self.send_byte(control_word)?;
549 }
550 self.end_transfer()?;
551
552 Ok(())
553 }
554
555 fn set_dot_data(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
556 self.clk
557 .borrow_mut()
558 .set_high()
559 .map_err(Hcms29xxError::ClkPinError)?;
560 self.rs
561 .borrow_mut()
562 .set_low()
563 .map_err(Hcms29xxError::RsPinError)?;
564 self.ce
565 .borrow_mut()
566 .set_low()
567 .map_err(Hcms29xxError::CePinError)?;
568 Ok(())
569 }
570
571 fn set_control_data(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
572 self.clk
573 .borrow_mut()
574 .set_high()
575 .map_err(Hcms29xxError::ClkPinError)?;
576 self.rs
577 .borrow_mut()
578 .set_high()
579 .map_err(Hcms29xxError::RsPinError)?;
580 self.ce
581 .borrow_mut()
582 .set_low()
583 .map_err(Hcms29xxError::CePinError)?;
584 Ok(())
585 }
586
587 fn send_byte(&mut self, byte: u8) -> Result<(), Hcms29xxError<PinErr>> {
588 for i in 0..8 {
589 self.clk
590 .borrow_mut()
591 .set_low()
592 .map_err(Hcms29xxError::ClkPinError)?;
593 if (byte & (1 << (7 - i))) != 0 {
594 self.data
595 .borrow_mut()
596 .set_high()
597 .map_err(Hcms29xxError::DataPinError)?;
598 } else {
599 self.data
600 .borrow_mut()
601 .set_low()
602 .map_err(Hcms29xxError::DataPinError)?;
603 }
604 self.clk
605 .borrow_mut()
606 .set_high()
607 .map_err(Hcms29xxError::ClkPinError)?;
608 }
609 Ok(())
610 }
611
612 fn end_transfer(&mut self) -> Result<(), Hcms29xxError<PinErr>> {
613 self.ce
614 .borrow_mut()
615 .set_high()
616 .map_err(Hcms29xxError::CePinError)?;
617 self.clk
618 .borrow_mut()
619 .set_low()
620 .map_err(Hcms29xxError::ClkPinError)?;
621 Ok(())
622 }
623}