adafruit_7segment/lib.rs
1// Copyright (c) 2020 Karl Thorén <karl.h.thoren@gmail.com>
2// Copyright (c) 2019 cs2dsb
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! # adafruit-7segment backpack Hal
11//!
12//! Additional features on top of the [`ht16k33` crate](https://crates.io/crates/ht16k33) to drive an [Adafruit 7-segment LED Alphanumeric Backpack](https://learn.adafruit.com/adafruit-led-backpack/0-dot-56-seven-segment-backpack) using traits from `embedded-hal`.
13//! Derived from the [`adafruit-alphanum4` crate](https://crates.io/crates/adafruit-alphanum4) and modified for the 7-segment backpacks.
14//!
15//! ## Features
16//! * Sending a `u8` to one of the 4 segments. Limited to 0x00 to 0x0F.
17//! * Sending an `AsciiChar` to one of the 4 segments. Limited to ascii hex chars and - sign.
18//! * Setting or unsetting the dot associated with one of the 4 segments.
19//! * Setting or unsetting the colon.
20//! * Formatting a `f32` to 1 to 4 segments
21//!
22//! # Usage
23//!
24//! ## Embedded platforms
25//! ### Example on a STM32F4-Discovery board
26//! For examples on other platforms see the [`ht16k33` crate](https://crates.io/crates/ht16k33).
27//!
28//! `Cargo.toml` dependencies example:
29//! ```toml
30//! [dependencies]
31//! htk16k33 = { version = "0.4.0", default-features = false }
32//! adafruit-7segment = { version = "0.1", default-features = false }
33//! embedded-hal = "0.2.3"
34//! cortex-m = "0.6.2"
35//! cortex-m-rt = "0.6.12"
36//! panic-halt = "0.2.0"
37//!
38//! [dependencies.stm32f4xx-hal]
39//! version = "0.8"
40//! features = ["rt", "stm32f407"]
41//!```
42//! Test code:
43//!```!ignore
44//! #![no_main]
45//! #![no_std]
46//!
47//! use panic_halt as _;
48//!
49//! use cortex_m;
50//! use cortex_m_rt::entry;
51//! use stm32f4xx_hal as hal;
52//!
53//! use crate::hal::{i2c::I2c, prelude::*, stm32};
54//! use ht16k33::{HT16K33, Dimming, Display};
55//! use adafruit_7segment::{SevenSegment, Index};
56//! pub use ascii::{ToAsciiChar, AsciiChar};
57//!
58//! #[entry]
59//! fn main() -> ! {
60//! if let (Some(dp), Some(cp)) = (
61//! stm32::Peripherals::take(),
62//! cortex_m::peripheral::Peripherals::take(),
63//! ) {
64//! // Set up the system clock. We want to run at 48MHz for this one.
65//! let rcc = dp.RCC.constrain();
66//! let clocks = rcc.cfgr.sysclk(48.mhz()).freeze();
67//!
68//! const DISP_I2C_ADDR: u8 = 112;
69//!
70//! // Set up I2C - SCL is PB8 and SDA is PB7; they are set to Alternate Function 4
71//! // as per the STM32F407 datasheet.
72//! let gpiob = dp.GPIOB.split();
73//! let scl = gpiob.pb8.into_alternate_af4().set_open_drain();
74//! let sda = gpiob.pb7.into_alternate_af4().set_open_drain();
75//! let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks);
76//!
77//! let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
78//! ht16k33.initialize().expect("Failed to initialize ht16k33");
79//! ht16k33.set_display(Display::ON).expect("Could not turn on the display!");
80//! ht16k33.set_dimming(Dimming::BRIGHTNESS_MIN).expect("Could not set dimming!");
81//!
82//! // Sending individual digits
83//! ht16k33.update_buffer_with_digit(Index::One, 1);
84//! ht16k33.update_buffer_with_digit(Index::Two, 2);
85//! ht16k33.update_buffer_with_digit(Index::Three, 3);
86//! ht16k33.update_buffer_with_digit(Index::Four, 4);
87//!
88//! // Sending ascii
89//! ht16k33.update_buffer_with_char(Index::One, AsciiChar::new('A'));
90//! ht16k33.update_buffer_with_char(Index::Two, AsciiChar::new('B'));
91//!
92//! // Setting the decimal point
93//! ht16k33.update_buffer_with_dot(Index::Two, true);
94//!
95//! // Formatting a float using the whole display
96//! ht16k33.update_buffer_with_float(Index::One, -3.14, 2, 10).unwrap();
97//!
98//! // Putting a character in front of a float
99//! ht16k33.update_buffer_with_char(Index::One, AsciiChar::new('b'));
100//! // Display will read "b-3.1"
101//! ht16k33.update_buffer_with_float(Index::Two, -3.14, 2, 10).unwrap();
102//!
103//! // This will panic because there aren't enough digits to display this number
104//! ht16k33.update_buffer_with_float(Index::One, 12345., 0, 10).expect("Oops");
105//!
106//! // Note: none of the above methods actually commit the buffer to the display,
107//! // call write_display_buffer to actually send it to the display
108//! ht16k33.write_display_buffer().unwrap()
109//! }
110//! loop {}
111//! }
112//!```
113//! ## All platforms, using I2C simulation
114//!```
115//! use ht16k33::i2c_mock::I2cMock;
116//! use ht16k33::{HT16K33, Dimming, Display};
117//! use adafruit_7segment::{SevenSegment, Index};
118//!
119//! // The I2C device address.
120//! const DISP_I2C_ADDR: u8 = 112;
121//!
122//! // Create a mock I2C device.
123//! let mut i2c = I2cMock::new();
124//!
125//! let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
126//! ht16k33.initialize().expect("Failed to initialize ht16k33");
127//! ht16k33.set_display(Display::ON).expect("Could not turn on the display!");
128//! ht16k33.set_dimming(Dimming::BRIGHTNESS_MIN).expect("Could not set dimming!");
129//!
130//! // Sending individual digits
131//! ht16k33.update_buffer_with_digit(Index::One, 1);
132//! ht16k33.update_buffer_with_digit(Index::Two, 2);
133//! ht16k33.update_buffer_with_digit(Index::Three, 3);
134//! ht16k33.update_buffer_with_digit(Index::Four, 4);
135//!
136//! // Note: none of the above methods actually commit the buffer to the display,
137//! // call write_display_buffer to actually send it to the display
138//! ht16k33.write_display_buffer().unwrap()
139//!```
140//! ## Performance warning
141//!
142//! Due to the api of the ht16k33 crate the display buffer is not directly accessible so each LED that makes up the character is updated sequentially. The way the hardware on this backpack is set up allows a character to be updated by setting a single 16-bit value in the buffer. Iterating over each bit of the 16 every update is clearly not optimal but it's sufficiently fast for my current usage. If the ht16k33 crate is updated to grant mut access to the buffer this can be improved.
143
144#![warn(missing_docs)]
145#![warn(missing_doc_code_examples)]
146#![doc(html_root_url = "https://docs.rs/adafruit-7segment/0.1.0")]
147#![cfg_attr(not(feature = "std"), no_std)]
148
149mod fonts;
150use fonts::*;
151
152pub use ascii::{AsciiChar, ToAsciiChar};
153use embedded_hal::blocking::i2c::{Write, WriteRead};
154use ht16k33::{DisplayData, DisplayDataAddress, LedLocation, COMMONS_SIZE, HT16K33};
155
156/// Possible errors returned by this crate.
157#[derive(Debug)]
158pub enum Error {
159 /// Error indicating there aren't enough digits to display the given float value.
160 InsufficientDigits,
161 /// Error indicating that the input cannot be displayed.
162 NotValidChar,
163}
164
165/// Trait enabling using the Adafruit 7-segment LED numeric Backpack.
166pub trait SevenSegment<E> {
167 /// Update the buffer with a digit value (0 to F) at the specified index.
168 fn update_buffer_with_digit(&mut self, index: Index, value: u8);
169 /// Update the buffer to turn the . on or off at the specified index.
170 fn update_buffer_with_dot(&mut self, index: Index, dot_on: bool);
171 /// Update the buffer to turn the : on or off.
172 fn update_buffer_with_colon(&mut self, colon_on: bool);
173 /// Update the buffer with an ascii character at the specified index.
174 fn update_buffer_with_char(&mut self, index: Index, value: AsciiChar) -> Result<(), Error>;
175 /// Update the buffer with a formatted float not starting before the specified index.
176 fn update_buffer_with_float(
177 &mut self,
178 index: Index,
179 value: f32,
180 fractional_digits: u8,
181 base: u8,
182 ) -> Result<(), Error>;
183}
184
185/// The index of a segment
186#[derive(Clone, Copy, PartialEq, PartialOrd)]
187pub enum Index {
188 /// First digit
189 One,
190 /// Second digit
191 Two,
192 /// Third digit
193 Three,
194 /// Fourth digit
195 Four,
196}
197
198impl From<Index> for u8 {
199 fn from(i: Index) -> u8 {
200 match i {
201 Index::One => 0,
202 Index::Two => 1,
203 Index::Three => 2,
204 Index::Four => 3,
205 }
206 }
207}
208
209impl From<u8> for Index {
210 fn from(v: u8) -> Index {
211 match v {
212 0 => Index::One,
213 1 => Index::Two,
214 2 => Index::Three,
215 3 => Index::Four,
216 _ => panic!("Invalid index > 3"),
217 }
218 }
219}
220
221const MINUS_SIGN: u8 = 0x40;
222
223const DOT_BIT: u8 = 7;
224
225const COLON_BIT: u8 = 1;
226
227fn set_bit<I2C, E>(display: &mut HT16K33<I2C>, index: u8, bit: u8, on: bool)
228where
229 I2C: Write<Error = E> + WriteRead<Error = E>,
230{
231 debug_assert!((bit as usize) < (COMMONS_SIZE * 2));
232 let index = index * 2;
233 let row = DisplayDataAddress::from_bits_truncate(if bit < 8 { index } else { index + 1 });
234 let common = DisplayData::from_bits_truncate(1 << (bit % 8));
235 display.update_display_buffer(LedLocation { row, common }, on);
236}
237
238fn update_bits<I2C, E>(display: &mut HT16K33<I2C>, index: Index, bits: u8)
239where
240 I2C: Write<Error = E> + WriteRead<Error = E>,
241{
242 let pos: u8;
243 if index > Index::Two {
244 // Move one step to compensate for colon at pos 2.
245 pos = u8::from(index) + 1u8;
246 } else {
247 pos = index.into();
248 }
249 for i in 0..8 {
250 let on = ((bits >> i) & 1) == 1;
251 set_bit(display, pos, i, on);
252 }
253}
254
255impl<I2C, E> SevenSegment<E> for HT16K33<I2C>
256where
257 I2C: Write<Error = E> + WriteRead<Error = E>,
258{
259 /// Update the buffer with a hex digit value (0x00 to 0x0F) at the specified index
260 /// # Arguments
261 ///
262 /// * `index` - Digit index.
263 /// * `value` - Value 0x00 to 0x0F.
264 ///
265 /// # Examples
266 ///
267 /// ```
268 /// use ht16k33::i2c_mock::I2cMock;
269 /// use ht16k33::HT16K33;
270 /// use adafruit_7segment::{SevenSegment, Index};
271 ///
272 /// // Create an I2C device.
273 /// let mut i2c = I2cMock::new();
274 ///
275 /// // The I2C device address.
276 /// const DISP_I2C_ADDR: u8 = 112;
277 ///
278 /// let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
279 ///
280 /// // Set first digit to 9.
281 /// ht16k33.update_buffer_with_digit(Index::One, 9);
282 /// ```
283 fn update_buffer_with_digit(&mut self, index: Index, value: u8) {
284 let value = value as usize;
285 assert!(value < HEX_NUMBER_FONT_TABLE.len());
286 let bits = HEX_NUMBER_FONT_TABLE[value];
287 update_bits(self, index, bits);
288 }
289
290 /// Update the buffer to turn the . on or off at the specified index
291 /// # Arguments
292 ///
293 /// * `index` - Digit index.
294 /// * `dot_on` - Enable or disable the dot.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use ht16k33::i2c_mock::I2cMock;
300 /// use ht16k33::HT16K33;
301 /// use adafruit_7segment::{SevenSegment, Index};
302 ///
303 /// // Create an I2C device.
304 /// let mut i2c = I2cMock::new();
305 ///
306 /// // The I2C device address.
307 /// const DISP_I2C_ADDR: u8 = 112;
308 ///
309 /// let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
310 ///
311 /// // Enable dot for first digit.
312 /// ht16k33.update_buffer_with_dot(Index::One, true);
313 /// ```
314 fn update_buffer_with_dot(&mut self, index: Index, dot_on: bool) {
315 let pos: u8;
316 if index > Index::Two {
317 // Move one step to compensate for colon at pos 2.
318 pos = u8::from(index) + 1u8;
319 } else {
320 pos = index.into();
321 }
322 set_bit(self, pos, DOT_BIT, dot_on);
323 }
324
325 /// Update the buffer to turn the : on or off.
326 /// # Arguments
327 ///
328 /// * `colon_on` - Enable or disable the colon.
329 ///
330 /// # Examples
331 ///
332 /// ```
333 /// use ht16k33::i2c_mock::I2cMock;
334 /// use ht16k33::HT16K33;
335 /// use adafruit_7segment::{SevenSegment, Index};
336 ///
337 /// // Create an I2C device.
338 /// let mut i2c = I2cMock::new();
339 ///
340 /// // The I2C device address.
341 /// const DISP_I2C_ADDR: u8 = 112;
342 ///
343 /// let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
344 ///
345 /// // Enable the colon.
346 /// ht16k33.update_buffer_with_colon(true);
347 /// ```
348 fn update_buffer_with_colon(&mut self, colon_on: bool) {
349 // The colon is at address 2.
350 set_bit(self, 2u8, COLON_BIT, colon_on);
351 }
352
353 /// Update the buffer with an ascii character at the specified index.
354 /// # Arguments
355 ///
356 /// * `index` - Digit index.
357 /// * `value` - Ascii character.
358 ///
359 /// # Examples
360 ///
361 /// ```
362 /// use ht16k33::i2c_mock::I2cMock;
363 /// use ht16k33::HT16K33;
364 /// use adafruit_7segment::{SevenSegment, Index, AsciiChar};
365 ///
366 /// // Create an I2C device.
367 /// let mut i2c = I2cMock::new();
368 ///
369 /// // The I2C device address.
370 /// const DISP_I2C_ADDR: u8 = 112;
371 ///
372 /// let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
373 ///
374 /// // Set first digit to 'c'.
375 /// ht16k33.update_buffer_with_char(Index::One, AsciiChar::new('c')).expect("Failed to encode char to buffer!");
376 /// ```
377 fn update_buffer_with_char(&mut self, index: Index, value: AsciiChar) -> Result<(), Error> {
378 if value.is_ascii_hexdigit() {
379 let val: u8;
380 if value.is_ascii_digit() {
381 // 0-9 converted to hex value
382 val = value.as_byte() - b'0';
383 } else {
384 // a-f or A-F converted to hex value
385 val = 0x0A + (value.to_ascii_uppercase().as_byte() - b'A');
386 }
387 let val = val as usize;
388 assert!(val < HEX_NUMBER_FONT_TABLE.len());
389 let bits = HEX_NUMBER_FONT_TABLE[val];
390 update_bits(self, index, bits);
391 } else if value == '-' {
392 update_bits(self, index, MINUS_SIGN);
393 } else {
394 return Err(Error::NotValidChar);
395 }
396
397 Ok(())
398 }
399
400 /// Update the buffer with a formatted float not starting before the specified index
401 /// The logic for this is copied mostly from from the adafruit library. Only difference is this allows the start index to be > 0
402 ///
403 /// # Arguments
404 ///
405 /// * `index` - Digit index.
406 /// * `value` - float value.
407 /// * `fractional_digits` - Number of fractional digits.
408 /// * `base` - Base to use.
409 ///
410 /// # Examples
411 ///
412 /// ```
413 /// use ht16k33::i2c_mock::I2cMock;
414 /// use ht16k33::HT16K33;
415 /// use adafruit_7segment::{SevenSegment, Index};
416 ///
417 /// // Create an I2C device.
418 /// let mut i2c = I2cMock::new();
419 ///
420 /// // The I2C device address.
421 /// const DISP_I2C_ADDR: u8 = 112;
422 ///
423 /// let mut ht16k33 = HT16K33::new(i2c, DISP_I2C_ADDR);
424 ///
425 /// // Write 9.9 from pos 2
426 /// ht16k33.update_buffer_with_float(Index::Two, 9.9, 1, 10);
427 /// ```
428 fn update_buffer_with_float(
429 &mut self,
430 index: Index,
431 mut value: f32,
432 mut fractional_digits: u8,
433 base: u8,
434 ) -> Result<(), Error> {
435 let index = u8::from(index);
436
437 // Available digits on display
438 let mut numeric_digits = 4 - index;
439
440 let is_negative = if value < 0. {
441 // The sign will take up one digit
442 numeric_digits -= 1;
443 // Flip the sign to do the rest of the formatting
444 value *= -1.;
445 true
446 } else {
447 false
448 };
449
450 let base = base as u32;
451 let basef = base as f32;
452
453 // Work out the multiplier needed to get all fraction digits into an integer
454 let mut to_int_factor = base.pow(fractional_digits as u32) as f32;
455
456 // Get an integer containing digits to be displayed
457 let mut display_number = ((value * to_int_factor) + 0.5) as u32;
458
459 // Calculate the upper bound given the number of digits available
460 let too_big = base.pow(numeric_digits as u32);
461
462 // If the number is too large, reduce fractional digits
463 while display_number >= too_big {
464 fractional_digits -= 1;
465 to_int_factor /= basef;
466 display_number = ((value * to_int_factor) + 0.5) as u32;
467 }
468
469 // Did we lose the decimal?
470 if to_int_factor < 1. {
471 return Err(Error::InsufficientDigits);
472 }
473
474 // Digit we're working on, less the start position
475 let mut display_pos = (3 - index) as i8;
476
477 if display_number == 0 {
478 // Write out the 0
479 self.update_buffer_with_digit((index + (display_pos as u8)).into(), 0);
480 // Move the current pos along
481 display_pos -= 1;
482 } else {
483 let mut i = 0;
484 while display_number != 0 || i <= fractional_digits {
485 let digit_index: Index = (index + (display_pos as u8)).into();
486 // Write out the current digit
487 self.update_buffer_with_digit(digit_index, (display_number % base) as u8);
488 // Add the decimal if necessary
489 if fractional_digits != 0 && i == fractional_digits {
490 self.update_buffer_with_dot(digit_index, true);
491 }
492 // Move the current pos along
493 display_pos -= 1;
494 // Move the number along
495 display_number /= base;
496 i += 1;
497 }
498 }
499
500 if is_negative {
501 // Add the minus sign
502 update_bits(self, (index + (display_pos as u8)).into(), MINUS_SIGN);
503 // Move the current pos along
504 display_pos -= 1;
505 }
506
507 // Clear any remaining segments
508 while display_pos >= 0 {
509 update_bits(self, (index + (display_pos as u8)).into(), 0);
510 // Move the current pos along
511 display_pos -= 1;
512 }
513
514 Ok(())
515 }
516}
517
518#[cfg(test)]
519mod tests {
520 extern crate std;
521 use embedded_hal_mock as hal;
522
523 use self::hal::i2c::Mock as I2cMock;
524 use super::*;
525
526 const ADDRESS: u8 = 0;
527
528 #[test]
529 fn update_buffer_with_dot() {
530 let expectations = [];
531
532 let mut i2c = I2cMock::new(&expectations);
533 let mut ht16k33 = HT16K33::new(i2c, ADDRESS);
534
535 ht16k33.update_buffer_with_dot(Index::One, true);
536 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b1000_0000);
537 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
538 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b0000_0000);
539 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
540 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
541 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
542 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b0000_0000);
543 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
544 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0000_0000);
545 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
546
547 ht16k33.update_buffer_with_dot(Index::Two, true);
548 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b1000_0000);
549 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
550 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b1000_0000);
551 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
552 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
553 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
554 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b0000_0000);
555 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
556 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0000_0000);
557 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
558
559 ht16k33.update_buffer_with_dot(Index::Three, true);
560 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b1000_0000);
561 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
562 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b1000_0000);
563 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
564 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
565 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
566 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b1000_0000);
567 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
568 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0000_0000);
569 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
570
571 ht16k33.update_buffer_with_dot(Index::Four, true);
572 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b1000_0000);
573 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
574 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b1000_0000);
575 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
576 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
577 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
578 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b1000_0000);
579 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
580 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b1000_0000);
581 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
582
583 i2c = ht16k33.destroy();
584 i2c.done();
585 }
586
587 #[test]
588 fn update_buffer_with_colon() {
589 let expectations = [];
590
591 let mut i2c = I2cMock::new(&expectations);
592 let mut ht16k33 = HT16K33::new(i2c, ADDRESS);
593
594 // Enable colon
595 ht16k33.update_buffer_with_colon(true);
596 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0000_0000);
597 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
598 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b0000_0000);
599 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
600 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0010);
601 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
602 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b0000_0000);
603
604 i2c = ht16k33.destroy();
605 i2c.done();
606 }
607
608 #[test]
609 fn update_buffer_with_digit() {
610 let expectations = [];
611
612 let mut i2c = I2cMock::new(&expectations);
613 let mut ht16k33 = HT16K33::new(i2c, ADDRESS);
614
615 // Write an A
616 ht16k33.update_buffer_with_digit(Index::One, 0x0A);
617 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_0111);
618
619 // Write an B
620 ht16k33.update_buffer_with_digit(Index::One, 0x0B);
621 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_1100);
622
623 // Write an 0
624 ht16k33.update_buffer_with_digit(Index::One, 0x00);
625 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0011_1111);
626
627 // Write an 9
628 ht16k33.update_buffer_with_digit(Index::One, 0x09);
629 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0110_1111);
630
631 i2c = ht16k33.destroy();
632 i2c.done();
633 }
634
635 #[test]
636 fn update_buffer_with_char() {
637 let expectations = [];
638
639 let mut i2c = I2cMock::new(&expectations);
640 let mut ht16k33 = HT16K33::new(i2c, ADDRESS);
641
642 // Write an A
643 assert!(ht16k33
644 .update_buffer_with_char(Index::One, AsciiChar::new('A'))
645 .is_ok());
646 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_0111);
647
648 // Write an a
649 assert!(ht16k33
650 .update_buffer_with_char(Index::One, AsciiChar::new('a'))
651 .is_ok());
652 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_0111);
653
654 // Write an B
655 assert!(ht16k33
656 .update_buffer_with_char(Index::One, AsciiChar::new('B'))
657 .is_ok());
658 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_1100);
659
660 // Write an b
661 assert!(ht16k33
662 .update_buffer_with_char(Index::One, AsciiChar::new('b'))
663 .is_ok());
664 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0111_1100);
665
666 // Write an 0
667 assert!(ht16k33
668 .update_buffer_with_char(Index::One, AsciiChar::new('0'))
669 .is_ok());
670 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0011_1111);
671
672 // Write an 9
673 assert!(ht16k33
674 .update_buffer_with_char(Index::One, AsciiChar::new('9'))
675 .is_ok());
676 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0110_1111);
677
678 // Write an -
679 assert!(ht16k33
680 .update_buffer_with_char(Index::One, AsciiChar::new('-'))
681 .is_ok());
682 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0100_0000);
683
684 i2c = ht16k33.destroy();
685 i2c.done();
686 }
687
688 #[test]
689 fn update_buffer_with_float() {
690 let expectations = [];
691
692 let mut i2c = I2cMock::new(&expectations);
693 let mut ht16k33 = HT16K33::new(i2c, ADDRESS);
694
695 assert!(ht16k33
696 .update_buffer_with_float(Index::One, 99.9, 2, 10)
697 .is_ok());
698 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0110_1111);
699 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
700 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b1110_1111);
701 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
702 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
703 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
704 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b0110_1111);
705 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
706 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0011_1111);
707 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
708 assert_eq!(ht16k33.display_buffer()[10].bits(), 0b0000_0000);
709 assert_eq!(ht16k33.display_buffer()[11].bits(), 0b0000_0000);
710 assert_eq!(ht16k33.display_buffer()[12].bits(), 0b0000_0000);
711 assert_eq!(ht16k33.display_buffer()[13].bits(), 0b0000_0000);
712 assert_eq!(ht16k33.display_buffer()[14].bits(), 0b0000_0000);
713 assert_eq!(ht16k33.display_buffer()[15].bits(), 0b0000_0000);
714
715 assert!(ht16k33
716 .update_buffer_with_float(Index::One, -99.9, 2, 10)
717 .is_ok());
718 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0100_0000);
719 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
720 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b0110_1111);
721 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
722 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
723 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
724 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b1110_1111);
725 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
726 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0110_1111);
727 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
728 assert_eq!(ht16k33.display_buffer()[10].bits(), 0b0000_0000);
729 assert_eq!(ht16k33.display_buffer()[11].bits(), 0b0000_0000);
730 assert_eq!(ht16k33.display_buffer()[12].bits(), 0b0000_0000);
731 assert_eq!(ht16k33.display_buffer()[13].bits(), 0b0000_0000);
732 assert_eq!(ht16k33.display_buffer()[14].bits(), 0b0000_0000);
733 assert_eq!(ht16k33.display_buffer()[15].bits(), 0b0000_0000);
734
735 ht16k33.clear_display_buffer();
736 assert!(ht16k33
737 .update_buffer_with_float(Index::Two, 9.9, 1, 10)
738 .is_ok());
739 assert_eq!(ht16k33.display_buffer()[0].bits(), 0b0000_0000);
740 assert_eq!(ht16k33.display_buffer()[1].bits(), 0b0000_0000);
741 assert_eq!(ht16k33.display_buffer()[2].bits(), 0b0000_0000);
742 assert_eq!(ht16k33.display_buffer()[3].bits(), 0b0000_0000);
743 assert_eq!(ht16k33.display_buffer()[4].bits(), 0b0000_0000);
744 assert_eq!(ht16k33.display_buffer()[5].bits(), 0b0000_0000);
745 assert_eq!(ht16k33.display_buffer()[6].bits(), 0b1110_1111);
746 assert_eq!(ht16k33.display_buffer()[7].bits(), 0b0000_0000);
747 assert_eq!(ht16k33.display_buffer()[8].bits(), 0b0110_1111);
748 assert_eq!(ht16k33.display_buffer()[9].bits(), 0b0000_0000);
749 assert_eq!(ht16k33.display_buffer()[10].bits(), 0b0000_0000);
750 assert_eq!(ht16k33.display_buffer()[11].bits(), 0b0000_0000);
751 assert_eq!(ht16k33.display_buffer()[12].bits(), 0b0000_0000);
752 assert_eq!(ht16k33.display_buffer()[13].bits(), 0b0000_0000);
753 assert_eq!(ht16k33.display_buffer()[14].bits(), 0b0000_0000);
754 assert_eq!(ht16k33.display_buffer()[15].bits(), 0b0000_0000);
755
756 i2c = ht16k33.destroy();
757 i2c.done();
758 }
759}