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}