1#![no_std]
48#![allow(non_upper_case_globals)]
49#[cfg(feature = "galloc")]
50extern crate alloc;
51
52pub mod utils;
53
54#[cfg(feature = "fx")]
55pub mod fx;
56
57#[cfg(feature = "demo")]
58pub mod demo;
59
60use embedded_hal::digital::v2::{InputPin, OutputPin};
61
62#[cfg(not(any(feature = "clkdio", feature = "clkdiostb")))]
63compile_error!("Either feature \"clkdio\" or \"clkdiostb\" must be enabled for this crate. Otherwise there is no reason to use it");
64
65#[derive(Debug)]
68pub enum TmError {
69 Dio,
70 Ack(u8),
73 Clk,
74 Stb,
75 Input,
77}
78
79#[inline]
81fn tm_bus_send<DIO, CLK, D>(
82 dio: &mut DIO,
83 clk: &mut CLK,
84 delay_us: &mut D,
85 bus_delay_us: u16,
86 mut byte: u8,
87) -> Result<(), TmError>
88where
89 DIO: InputPin + OutputPin,
90 CLK: OutputPin,
91 D: FnMut(u16) -> (),
92{
93 for _ in 0..8 {
94 clk.set_low().map_err(|_| TmError::Clk)?;
95 delay_us(bus_delay_us);
97
98 let high = byte & 0b1 != 0;
99 byte = byte >> 1;
100 if high {
101 dio.set_high().map_err(|_| TmError::Dio)?;
102 } else {
103 dio.set_low().map_err(|_| TmError::Dio)?;
104 }
105 delay_us(bus_delay_us);
106
107 clk.set_high().map_err(|_| TmError::Clk)?;
108 delay_us(bus_delay_us);
109 }
110 Ok(())
111}
112
113#[inline]
115#[cfg(feature = "keys")]
116fn tm_bus_read<DIO, CLK, D>(
117 dio: &mut DIO,
118 clk: &mut CLK,
119 delay_us: &mut D,
120 bus_delay_us: u16,
121) -> Result<u8, TmError>
122where
123 DIO: InputPin + OutputPin,
124 CLK: OutputPin,
125 D: FnMut(u16) -> (),
126{
127 let mut byte = 0;
128 for i in 0..8 {
129 clk.set_low().map_err(|_| TmError::Clk)?;
130 delay_us(bus_delay_us);
131 clk.set_high().map_err(|_| TmError::Clk)?;
133 if dio.is_high().map_err(|_| TmError::Dio)? {
134 byte = byte | 0x80 >> i;
135 }
136 delay_us(bus_delay_us);
137 }
138 Ok(byte)
139}
140
141#[cfg(feature = "clkdio")]
142fn tm_bus_dio_wait_ack<DIO, D>(
143 dio: &mut DIO,
144 delay_us: &mut D,
145 bus_delay_us: u16,
146 expect_high: bool,
147 err: u8,
148) -> Result<(), TmError>
149where
150 DIO: InputPin + OutputPin,
151 D: FnMut(u16) -> (),
152{
153 for _ in 0..5 {
154 if expect_high == dio.is_high().map_err(|_| TmError::Dio)? {
155 return Ok(());
156 }
157 delay_us(bus_delay_us);
158 }
159
160 Err(TmError::Ack(err))
161}
162
163#[inline]
165#[cfg(feature = "clkdio")]
166fn tm_bus_2wire_start<DIO, CLK, D>(
167 dio: &mut DIO,
168 clk: &mut CLK,
169 delay_us: &mut D,
170 bus_delay_us: u16,
171) -> Result<(), TmError>
172where
173 DIO: InputPin + OutputPin,
174 CLK: OutputPin,
175 D: FnMut(u16) -> (),
176{
177 clk.set_high().map_err(|_| TmError::Clk)?;
178 dio.set_low().map_err(|_| TmError::Dio)?;
179 delay_us(bus_delay_us);
180 Ok(())
181}
182
183#[inline]
184#[cfg(feature = "clkdio")]
185fn tm_bus_2wire_stop<DIO, CLK, D>(
186 dio: &mut DIO,
187 clk: &mut CLK,
188 delay_us: &mut D,
189 bus_delay_us: u16,
190) -> Result<(), TmError>
191where
192 DIO: InputPin + OutputPin,
193 CLK: OutputPin,
194 D: FnMut(u16) -> (),
195{
196 dio.set_low().map_err(|_| TmError::Dio)?;
197 delay_us(bus_delay_us);
198
199 clk.set_high().map_err(|_| TmError::Clk)?;
200 delay_us(bus_delay_us);
201
202 dio.set_high().map_err(|_| TmError::Dio)?;
203 tm_bus_dio_wait_ack(dio, delay_us, bus_delay_us, true, 255)?;
204 delay_us(bus_delay_us);
205 Ok(())
206}
207
208#[cfg(feature = "clkdio")]
210fn tm_bus_2wire_ack<DIO, CLK, D>(
211 dio: &mut DIO,
212 clk: &mut CLK,
213 delay_us: &mut D,
214 bus_delay_us: u16,
215 err_code: u8,
216 verify_last: bool,
217) -> Result<(), TmError>
218where
219 DIO: InputPin + OutputPin,
220 CLK: OutputPin,
221 D: FnMut(u16) -> (),
222{
223 dio.set_high().map_err(|_| TmError::Dio)?;
225 clk.set_low().map_err(|_| TmError::Clk)?;
226 delay_us(bus_delay_us);
227
228 tm_bus_dio_wait_ack(dio, delay_us, bus_delay_us, false, err_code + 1)?;
230
231 clk.set_high().map_err(|_| TmError::Clk)?;
233 delay_us(bus_delay_us);
234
235 tm_bus_dio_wait_ack(dio, delay_us, bus_delay_us, false, err_code + 2)?;
237
238 clk.set_low().map_err(|_| TmError::Clk)?;
240 delay_us(bus_delay_us);
241
242 if verify_last {
244 tm_bus_dio_wait_ack(dio, delay_us, bus_delay_us, true, err_code + 3)?;
246 }
247
248 Ok(())
249}
250
251#[inline]
252#[cfg(feature = "clkdio")]
253fn tm_bus_2wire_send_byte_ack<DIO, CLK, D>(
254 dio: &mut DIO,
255 clk: &mut CLK,
256 delay_us: &mut D,
257 bus_delay_us: u16,
258 byte: u8,
259 err_code: u8,
260) -> Result<(), TmError>
261where
262 DIO: InputPin + OutputPin,
263 CLK: OutputPin,
264 D: FnMut(u16) -> (),
265{
266 tm_bus_send(dio, clk, delay_us, bus_delay_us, byte)?;
267 let verify_last = byte & COM_DATA_READ != COM_DATA_READ;
268 tm_bus_2wire_ack(dio, clk, delay_us, bus_delay_us, err_code, verify_last)
269}
270
271#[inline]
272#[cfg(all(feature = "keys", feature = "clkdio"))]
273fn tm_bus_2wire_read_byte_ack<DIO, CLK, D>(
274 dio: &mut DIO,
275 clk: &mut CLK,
276 delay_us: &mut D,
277 bus_delay_us: u16,
278 err_code: u8,
279) -> Result<u8, TmError>
280where
281 DIO: InputPin + OutputPin,
282 CLK: OutputPin,
283 D: FnMut(u16) -> (),
284{
285 let result = tm_bus_read(dio, clk, delay_us, bus_delay_us);
286 tm_bus_2wire_ack(dio, clk, delay_us, bus_delay_us, err_code, true)?;
287 result
288}
289
290#[inline]
300#[cfg(feature = "clkdio")]
301pub fn tm_send_bytes_2wire<DIO, CLK, D>(
302 dio: &mut DIO,
303 clk: &mut CLK,
304 delay_us: &mut D,
305 delay_value: u16,
306 bytes: &[u8],
307) -> Result<(), TmError>
308where
309 DIO: InputPin + OutputPin,
310 CLK: OutputPin,
311 D: FnMut(u16) -> (),
312{
313 tm_bus_2wire_start(dio, clk, delay_us, delay_value)?;
314
315 let mut send = Err(TmError::Input);
316 let mut iter = 10;
317 for bt in bytes {
318 send = tm_bus_2wire_send_byte_ack(dio, clk, delay_us, delay_value, bt.clone(), iter);
319 if send.is_err() {
320 break;
321 }
322 iter += 10;
323 }
324
325 let stop = tm_bus_2wire_stop(dio, clk, delay_us, delay_value);
326 if send.is_err() {
327 send
328 } else {
329 stop
330 }
331}
332
333#[inline]
340#[cfg(all(feature = "keys", feature = "clkdio"))]
341pub fn tm_read_byte_2wire<DIO, CLK, D>(
342 dio: &mut DIO,
343 clk: &mut CLK,
344 delay_us: &mut D,
345 delay_value: u16,
346) -> Result<u8, TmError>
347where
348 DIO: InputPin + OutputPin,
349 CLK: OutputPin,
350 D: FnMut(u16) -> (),
351{
352 tm_bus_2wire_start(dio, clk, delay_us, delay_value)?;
353
354 tm_bus_2wire_send_byte_ack(dio, clk, delay_us, delay_value, COM_DATA_READ, 230)?;
355
356 let read = tm_bus_2wire_read_byte_ack(dio, clk, delay_us, delay_value, 240);
357
358 let stop = tm_bus_2wire_stop(dio, clk, delay_us, delay_value);
359 if stop.is_err() {
360 if read.is_err() {
361 return read;
362 } else {
363 return Err(stop.err().unwrap());
364 }
365 }
366 read
367}
368
369#[inline]
383#[cfg(feature = "clkdiostb")]
384pub fn tm_send_bytes_3wire<DIO, CLK, STB, D>(
385 dio: &mut DIO,
386 clk: &mut CLK,
387 stb: &mut STB,
388 delay_us: &mut D,
389 delay_value: u16,
390 bytes: &[u8],
391) -> Result<(), TmError>
392where
393 DIO: InputPin + OutputPin,
394 CLK: OutputPin,
395 STB: OutputPin,
396 D: FnMut(u16) -> (),
397{
398 delay_us(delay_value);
399 stb.set_low().map_err(|_| TmError::Stb)?;
400 delay_us(delay_value);
401
402 let mut send = Err(TmError::Input);
403 for bt in bytes {
404 send = tm_bus_send(dio, clk, delay_us, delay_value, bt.clone());
405 if send.is_err() {
406 break;
407 }
408 }
412 delay_us(delay_value);
413 stb.set_high().map_err(|_| TmError::Stb)?;
414 clk.set_high().map_err(|_| TmError::Stb)?;
415 dio.set_high().map_err(|_| TmError::Stb)?;
416 send
417}
418
419#[inline]
429#[cfg(all(feature = "keys", feature = "clkdiostb"))]
430pub fn tm_read_bytes_3wire<DIO, CLK, STB, D>(
431 dio: &mut DIO,
432 clk: &mut CLK,
433 stb: &mut STB,
434 delay_us: &mut D,
435 delay_value: u16,
436 read_count: u8,
437) -> Result<[u8; 4], TmError>
438where
439 DIO: InputPin + OutputPin,
440 CLK: OutputPin,
441 STB: OutputPin,
442 D: FnMut(u16) -> (),
443{
444 let mut read_err = None;
445 let mut response = [0_u8; 4];
446
447 if read_count <= 0 || read_count > response.len() as u8 {
448 return Err(TmError::Input);
449 }
450
451 delay_us(delay_value);
452 stb.set_low().map_err(|_| TmError::Stb)?;
453 delay_us(delay_value);
454
455 let res_init = tm_bus_send(dio, clk, delay_us, delay_value, COM_DATA_READ);
456 dio.set_high().map_err(|_| TmError::Stb)?;
457 if res_init.is_err() {
458 read_err = Some(res_init.unwrap_err());
459 } else {
460 delay_us(delay_value);
463 for i in 0..(read_count as usize) {
464 match tm_bus_read(dio, clk, delay_us, delay_value) {
465 Ok(b) => {
466 response[i] = b;
467 }
468 Err(e) => {
469 read_err = Some(e);
470 break;
471 }
472 }
473 }
474 }
475
476 stb.set_high().map_err(|_| TmError::Stb)?;
477 clk.set_high().map_err(|_| TmError::Stb)?;
478 dio.set_high().map_err(|_| TmError::Stb)?;
479
480 if read_err.is_some() {
481 return Err(read_err.unwrap());
482 }
483 Ok(response)
484}
485
486pub const TM1638_RESPONSE_SIZE: u8 = 4;
488pub const TM1638_MAX_SEGMENTS: u8 = 10;
490
491pub const TM1637_RESPONSE_SIZE: u8 = 1;
493pub const TM1637_MAX_SEGMENTS: u8 = 6;
495
496pub const TM1637_BUS_DELAY_US: u16 = 475;
498
499pub const TM1638_BUS_DELAY_US: u16 = 1;
501
502pub const BUS_DELAY_US: u16 = 500;
505
506pub const COM_DATA: u8 = 0b01000000;
508
509pub const COM_DISPLAY: u8 = 0b10000000;
511
512pub const COM_ADDRESS: u8 = 0b11000000;
514
515pub const COM_DATA_ADDRESS_ADD: u8 = COM_DATA | 0b000000;
517pub const COM_DATA_ADDRESS_FIXED: u8 = COM_DATA | 0b000100;
519pub const COM_DATA_READ: u8 = COM_DATA | 0b000010;
521
522pub const COM_DISPLAY_ON: u8 = 0b10001000;
525pub const DISPLAY_BRIGHTNESS_MASK: u8 = 0b00000111;
527pub const COM_DISPLAY_OFF: u8 = 0b10000000;
529
530pub const SEG_1: u8 = 0b1;
532pub const SEG_2: u8 = 0b10;
534pub const SEG_3: u8 = 0b100;
536pub const SEG_4: u8 = 0b1000;
538pub const SEG_5: u8 = 0b10000;
540pub const SEG_6: u8 = 0b100000;
542pub const SEG_7: u8 = 0b1000000;
544pub const SEG_8: u8 = 0b10000000;
546
547pub const SEG_9: u8 = SEG_1;
549pub const SEG_10: u8 = SEG_2;
551pub const SEG_11: u8 = SEG_3;
553pub const SEG_12: u8 = SEG_4;
555
556pub const CHAR_0: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6;
557pub const CHAR_1: u8 = SEG_2 | SEG_3;
558pub const CHAR_2: u8 = SEG_1 | SEG_2 | SEG_4 | SEG_5 | SEG_7;
559pub const CHAR_3: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_7;
560pub const CHAR_4: u8 = SEG_2 | SEG_3 | SEG_6 | SEG_7;
561pub const CHAR_5: u8 = SEG_1 | SEG_3 | SEG_4 | SEG_6 | SEG_7;
562pub const CHAR_6: u8 = SEG_1 | SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
563pub const CHAR_7: u8 = SEG_1 | SEG_2 | SEG_3;
564pub const CHAR_8: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
565pub const CHAR_9: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_6 | SEG_7;
566pub const CHAR_A: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_5 | SEG_6 | SEG_7;
567pub const CHAR_a: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_7;
568pub const CHAR_b: u8 = SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
569pub const CHAR_C: u8 = SEG_1 | SEG_4 | SEG_5 | SEG_6;
570pub const CHAR_c: u8 = SEG_4 | SEG_5 | SEG_7;
571pub const CHAR_d: u8 = SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_7;
572pub const CHAR_E: u8 = SEG_1 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
573pub const CHAR_e: u8 = SEG_1 | SEG_2 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
574pub const CHAR_F: u8 = SEG_1 | SEG_5 | SEG_6 | SEG_7;
575pub const CHAR_G: u8 = SEG_1 | SEG_3 | SEG_4 | SEG_5 | SEG_6;
576pub const CHAR_H: u8 = SEG_2 | SEG_3 | SEG_5 | SEG_6 | SEG_7;
577pub const CHAR_h: u8 = SEG_3 | SEG_5 | SEG_6 | SEG_7;
578pub const CHAR_I: u8 = SEG_2 | SEG_3;
579pub const CHAR_i: u8 = SEG_3;
580pub const CHAR_J: u8 = SEG_2 | SEG_3 | SEG_4 | SEG_5;
581pub const CHAR_L: u8 = SEG_4 | SEG_5 | SEG_6;
582pub const CHAR_l: u8 = SEG_4 | SEG_5;
583pub const CHAR_N: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_5 | SEG_6;
584pub const CHAR_n: u8 = SEG_3 | SEG_5 | SEG_7;
585pub const CHAR_O: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6;
586pub const CHAR_o: u8 = SEG_3 | SEG_4 | SEG_5 | SEG_7;
587pub const CHAR_P: u8 = SEG_1 | SEG_2 | SEG_5 | SEG_6 | SEG_7;
588pub const CHAR_q: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_6 | SEG_7;
589pub const CHAR_R: u8 = SEG_1 | SEG_5 | SEG_6;
590pub const CHAR_r: u8 = SEG_5 | SEG_7;
591pub const CHAR_S: u8 = SEG_1 | SEG_3 | SEG_4 | SEG_6 | SEG_7;
592pub const CHAR_t: u8 = SEG_4 | SEG_5 | SEG_6 | SEG_7;
593pub const CHAR_U: u8 = SEG_2 | SEG_3 | SEG_4 | SEG_5 | SEG_6;
594pub const CHAR_u: u8 = SEG_3 | SEG_4 | SEG_5;
595pub const CHAR_y: u8 = SEG_2 | SEG_3 | SEG_4 | SEG_6 | SEG_7;
596pub const CHAR_CYR_E: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4 | SEG_7;
597pub const CHAR_CYR_B: u8 = SEG_1 | SEG_3 | SEG_4 | SEG_5 | SEG_6 | SEG_7;
598pub const CHAR_DEGREE: u8 = SEG_1 | SEG_2 | SEG_6 | SEG_7;
599pub const CHAR_MINUS: u8 = SEG_7;
600pub const CHAR_UNDERSCORE: u8 = SEG_4;
601pub const CHAR_BRACKET_LEFT: u8 = SEG_1 | SEG_4 | SEG_5 | SEG_6;
602pub const CHAR_BRACKET_RIGHT: u8 = SEG_1 | SEG_2 | SEG_3 | SEG_4;
603
604pub const DIGITS: [u8; 10] = [
606 CHAR_0, CHAR_1, CHAR_2, CHAR_3, CHAR_4, CHAR_5, CHAR_6, CHAR_7, CHAR_8, CHAR_9,
607];