1#![allow(clippy::manual_range_contains)]
2#![allow(non_upper_case_globals)]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5pub use embedded_hal::blocking::i2c::{self, Read, Write};
11pub use enum_index::IndexEnum;
12use enum_index_derive::{EnumIndex, IndexEnum};
13
14pub const SEGMENTS_SIZE: usize = 16;
15pub const COMMONS_SIZE: usize = 8;
16
17pub trait Command { const COMMAND_MASK: u8; }
22
23#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
25#[repr(u8)]
26pub enum SystemSetupRegister {
27 StandBy = Self::COMMAND_MASK | 0,
29 Normal = Self::COMMAND_MASK | 1,
31}
32
33impl Command for SystemSetupRegister {
34 const COMMAND_MASK: u8 = 0b0010_0000;
36}
37
38pub type System = SystemSetupRegister;
40
41#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
43#[repr(u8)]
44pub enum RowIntSetupRegister {
45 Row = Self::COMMAND_MASK | 0b0000,
47 IntLow = Self::COMMAND_MASK | 0b0001,
49 IntHigh = Self::COMMAND_MASK | 0b0011,
51}
52
53impl Command for RowIntSetupRegister {
54 const COMMAND_MASK: u8 = 0b1010_0000;
56}
57
58pub type RowInt = RowIntSetupRegister;
60
61#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
63#[repr(u8)]
64pub enum DisplaySetupRegister {
65 Off = Self::COMMAND_MASK | 0b0000,
67 On = Self::COMMAND_MASK | 0b0001,
69 TwoHz = Self::COMMAND_MASK | 0b0011,
71 OneHz = Self::COMMAND_MASK | 0b0101,
73 HalfHz = Self::COMMAND_MASK | 0b0111,
75}
76
77impl Command for DisplaySetupRegister {
78 const COMMAND_MASK: u8 = 0b1000_0000;
80}
81
82pub type Display = DisplaySetupRegister;
84
85#[derive(Copy, Clone, Eq, PartialEq, EnumIndex, IndexEnum, Hash, PartialOrd, Ord, Debug)]
87#[repr(u8)]
88pub enum DigitalDimmingDataInput {
89 Duty1_16 = Self::COMMAND_MASK | 0b0000,
90 Duty2_16 = Self::COMMAND_MASK | 0b0001,
91 Duty3_16 = Self::COMMAND_MASK | 0b0010,
92 Duty4_16 = Self::COMMAND_MASK | 0b0011,
93 Duty5_16 = Self::COMMAND_MASK | 0b0100,
94 Duty6_16 = Self::COMMAND_MASK | 0b0101,
95 Duty7_16 = Self::COMMAND_MASK | 0b0110,
96 Duty8_16 = Self::COMMAND_MASK | 0b0111,
97 Duty9_16 = Self::COMMAND_MASK | 0b1000,
98 Duty10_16 = Self::COMMAND_MASK | 0b1001,
99 Duty11_16 = Self::COMMAND_MASK | 0b1010,
100 Duty12_16 = Self::COMMAND_MASK | 0b1011,
101 Duty13_16 = Self::COMMAND_MASK | 0b1100,
102 Duty14_16 = Self::COMMAND_MASK | 0b1101,
103 Duty15_16 = Self::COMMAND_MASK | 0b1110,
104 Duty16_16 = Self::COMMAND_MASK | 0b1111,
105}
106
107impl Command for DigitalDimmingDataInput {
108 const COMMAND_MASK: u8 = 0b1110_0000;
110}
111
112pub type Dimming = DigitalDimmingDataInput;
114
115#[derive(Copy, Clone, Eq, PartialEq, EnumIndex, IndexEnum, Hash, PartialOrd, Ord, Debug)]
117#[repr(u8)]
118pub enum DisplayDataAddressPointer {
119 Addr0 = Self::COMMAND_MASK | 0b0000,
120 Addr1 = Self::COMMAND_MASK | 0b0001,
121 Addr2 = Self::COMMAND_MASK | 0b0010,
122 Addr3 = Self::COMMAND_MASK | 0b0011,
123 Addr4 = Self::COMMAND_MASK | 0b0100,
124 Addr5 = Self::COMMAND_MASK | 0b0101,
125 Addr6 = Self::COMMAND_MASK | 0b0110,
126 Addr7 = Self::COMMAND_MASK | 0b0111,
127 Addr8 = Self::COMMAND_MASK | 0b1000,
128 Addr9 = Self::COMMAND_MASK | 0b1001,
129 Addr10 = Self::COMMAND_MASK | 0b1010,
130 Addr11 = Self::COMMAND_MASK | 0b1011,
131 Addr12 = Self::COMMAND_MASK | 0b1100,
132 Addr13 = Self::COMMAND_MASK | 0b1101,
133 Addr14 = Self::COMMAND_MASK | 0b1110,
134 Addr15 = Self::COMMAND_MASK | 0b1111,
135}
136
137impl Command for DisplayDataAddressPointer {
138 const COMMAND_MASK: u8 = 0b0000_0000;
140}
141
142pub type DDAP = DisplayDataAddressPointer;
144
145#[derive(Copy, Clone, Eq, PartialEq, EnumIndex, IndexEnum, Hash, PartialOrd, Ord, Debug)]
147#[repr(u8)]
148pub enum KeyDataAddressPointer {
149 Addr0 = Self::COMMAND_MASK | 0b000,
150 Addr1 = Self::COMMAND_MASK | 0b001,
151 Addr2 = Self::COMMAND_MASK | 0b010,
152 Addr3 = Self::COMMAND_MASK | 0b011,
153 Addr4 = Self::COMMAND_MASK | 0b100,
154 Addr5 = Self::COMMAND_MASK | 0b101,
155 Addr6 = Self::COMMAND_MASK | 0b110,
156 Addr7 = Self::COMMAND_MASK | 0b111,
157}
158
159impl Command for KeyDataAddressPointer {
160 const COMMAND_MASK: u8 = 0b0100_0000;
162}
163
164pub type KDAP = KeyDataAddressPointer;
166
167pub const INT_FLAG_ADDRESS_POINTER: u8 = 0b0110_0000;
171
172pub const IFAP: u8 = INT_FLAG_ADDRESS_POINTER;
174
175pub const TEST_MODE_HOLTEK_ONLY: u8 = 0b1101_1001;
179
180pub type Result<Error> = core::result::Result<(), Error>;
181
182#[derive(Copy, Clone, Debug, Hash)]
187pub struct HT16K33<I2C> {
188 i2c: I2C,
189 i2c_address: u8,
190 dbuf: [u8; SEGMENTS_SIZE + 1],
193 system: SystemSetupRegister,
194 display: DisplaySetupRegister,
195 rowint: RowIntSetupRegister,
196 dimming: DigitalDimmingDataInput,
197}
198
199impl<I2C> HT16K33<I2C> {
200 pub fn new(i2c: I2C, i2c_address: u8) -> Self {
204 let mut dbuf = [0; SEGMENTS_SIZE + 1];
205 dbuf[0] = DisplayDataAddressPointer::Addr0 as u8;
206
207 HT16K33 {
208 i2c,
209 i2c_address,
210 dbuf,
211 system: SystemSetupRegister::StandBy,
212 display: DisplaySetupRegister::Off,
213 rowint: RowIntSetupRegister::Row,
214 dimming: DigitalDimmingDataInput::Duty16_16,
215 }
216 }
217}
218
219pub trait HT16K33Trait<I2C, E>: Read + Write {
220 fn i2c(self) -> I2C;
222
223 fn i2c_address(&self) -> u8;
225
226 fn set_i2c_address(&mut self, i2c_address: u8);
228
229 fn system(&self) -> SystemSetupRegister;
232
233 fn write_system(&mut self, system: SystemSetupRegister) -> Result<E>;
236
237 fn display(&self) -> DisplaySetupRegister;
240
241 fn write_display(&mut self, dsr: DisplaySetupRegister) -> Result<E>;
244
245 fn rowint(&self) -> RowIntSetupRegister;
248
249 fn write_rowint(&mut self, rowint: RowIntSetupRegister) -> Result<E>;
252
253 fn dimming(&self) -> DigitalDimmingDataInput;
256
257 fn write_dimming(&mut self, dim: DigitalDimmingDataInput) -> Result<E>;
260
261 fn display_data_address_pointer(&self) -> DisplayDataAddressPointer;
264
265 fn set_display_data_address_pointer(
267 &mut self,
268 ddap: DisplayDataAddressPointer
269 );
270
271 fn dbuf(&self) -> &[u8];
273
274 fn dbuf_mut(&mut self) -> &mut [u8];
276
277 fn set_dbuf(&mut self, src: &[u8; SEGMENTS_SIZE]);
279
280 fn clear_dbuf(&mut self);
282
283 fn write_dbuf(&mut self) -> Result<E>;
285
286 fn read_dram(&mut self, buf: &mut [u8]) -> Result<E>;
288
289 fn read_dram_to_dbuf(&mut self) -> Result<E>;
291
292 fn write_dram(&mut self, ddap: DisplayDataAddressPointer, slice: &[u8])
300 -> Result<E>;
301
302 fn clear_dram(&mut self) -> Result<E> {
304 self.clear_dbuf();
305 self.write_dbuf()
306 }
307
308 fn power_on(&mut self) -> Result<E> {
314 self.write_system(SystemSetupRegister::Normal)?;
315 self.write_rowint(RowIntSetupRegister::Row)?;
316 self.write_display(DisplaySetupRegister::On)?;
317 self.write_dimming(DigitalDimmingDataInput::Duty16_16)?;
318 self.clear_dram()
319 }
320
321 fn shutdown(&mut self) -> Result<E> {
326 self.clear_dram()?;
327 self.write_dimming(DigitalDimmingDataInput::Duty16_16)?;
328 self.write_display(DisplaySetupRegister::Off)?;
329 self.write_system(SystemSetupRegister::StandBy)
330 }
331}
332
333impl<I2C, E> Read for HT16K33<I2C>
334where
335 I2C: Read<Error = E>
336{
337 type Error = E;
338
339 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<Self::Error> {
340 self.i2c.read(address, buffer)
341 }
342}
343
344impl<I2C, E> Write for HT16K33<I2C>
345where
346 I2C: Write<Error = E>
347{
348 type Error = E;
349
350 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<Self::Error> {
351 self.i2c.write(address, bytes)
352 }
353}
354
355impl<I2C, E> HT16K33Trait<I2C, E> for HT16K33<I2C>
356where
357 I2C: Read<Error = E> + Write<Error = E>
358{
359 fn i2c(self) -> I2C {self.i2c}
360
361 fn i2c_address(&self) -> u8 {self.i2c_address}
362
363 fn set_i2c_address(&mut self, i2c_address: u8) {
364 self.i2c_address = i2c_address
365 }
366
367 fn system(&self) -> System {self.system}
368
369 fn write_system(&mut self, sys: System) -> Result<E> {
370 self.write(self.i2c_address, &[sys as u8])?;
371 self.system = sys; Ok(())
372 }
373
374 fn display(&self) -> Display {self.display}
375
376 fn write_display(&mut self, dpy: Display) -> Result<E> {
377 self.write(self.i2c_address, &[dpy as u8])?;
378 self.display = dpy; Ok(())
379 }
380
381 fn rowint(&self) -> RowInt {self.rowint}
382
383 fn write_rowint(&mut self, rowint: RowInt) -> Result<E> {
384 self.write(self.i2c_address, &[rowint as u8])?;
385 self.rowint = rowint; Ok(())
386 }
387
388 fn dimming(&self) -> Dimming {self.dimming}
389
390 fn write_dimming(&mut self, dim: Dimming) -> Result<E> {
391 self.write(self.i2c_address, &[dim as u8])?;
392 self.dimming = dim; Ok(())
393 }
394
395 fn display_data_address_pointer(&self) -> DDAP {
396 DDAP::index_enum(self.dbuf[0] as usize)
397 .expect("Internal Display Buffer has been corrupted.")
398 }
399
400 fn set_display_data_address_pointer(&mut self, ddap: DDAP) {
401 self.dbuf[0] = ddap as u8
402 }
403
404 fn dbuf(&self) -> &[u8] {&self.dbuf[1..]}
405
406 fn dbuf_mut(&mut self) -> &mut [u8] {&mut self.dbuf[1..]}
407
408 fn set_dbuf(&mut self, src: &[u8; SEGMENTS_SIZE]) {
409 self.dbuf[1..].clone_from_slice(src)
410 }
411
412 fn clear_dbuf(&mut self) {self.dbuf[1..].fill(0)}
413
414 fn write_dbuf(&mut self) -> Result<E> {
415 self.i2c.write(self.i2c_address, &self.dbuf)
416 }
417
418 fn read_dram(&mut self, buf: &mut [u8]) -> Result<E> {
419 self.i2c.read(self.i2c_address, buf)
420 }
421
422 fn read_dram_to_dbuf(&mut self) -> Result<E> {
423 self.i2c.read(self.i2c_address, &mut self.dbuf[1..])
424 }
425
426 fn write_dram(&mut self, ddap: DDAP, slice: &[u8]) -> Result<E> {
427 let mut buf = [0; SEGMENTS_SIZE + 1];
428 buf[0] = ddap as u8;
429 buf[1..=slice.len()].clone_from_slice(slice);
430 self.i2c.write(self.i2c_address, &buf[..=slice.len()])
431 }
432}