use core::future::pending; pub const DS3231_ADDR: u8 = 0x68; pub const TUSB322_ADDR: u8 = 0x47; pub const PCA9685_ADDR_1: u8 = 0x41; pub const PCA9685_ADDR_2: u8 = 0x42; pub const PCA9685_ADDR_3: u8 = 0x43; pub const PCA9685_ALL_CALL: u8 = 0x70; // Default enabled pub const PCA9685_SUB_CALL_1: u8 = 0x71; // Default disabled pub const PCA9685_SUB_CALL_2: u8 = 0x72; // Default disabled pub const PCA9685_SUB_CALL_3: u8 = 0x73; // Default disabled const MAP_DOT_ADDR: u8 = PCA9685_ADDR_2; const MAP_DOT_PIN: u8 = 15; const MAP_ADDR: usize = 0; const MAP_PIN: usize = 1; const DIGIT_FADE_DURATION_US: u32 = 1_000_000; const REFRESH_RATE_US: u32 = 1000; const DIGIT_RNG_FADE_DURATION_US: u32 = 200_000; const DIGIT_RNG_FADE_ITERATIONS: usize = 20; const DIGIT_RNG_REFRESH_INTERVAL: usize = 60; const DIGIT_RNG_REFRESH_VARIANCE: usize = 30; const DOT_MIN_BRIGHTNESS: u32 = 256; const DOT_MAX_BRIGHTNESS: u32 = 640; const DOT_FADE_DURATION_US: u32 = 1_000_000; const DIGIT_MAX_BRIGHTNESS: u32 = 4096; const DIGIT_MIN_BRIGHTNESS: u32 = 0; const NUM_TUBES: usize = 4; const NUM_DIGITS: usize = 10; struct DigitToPin { address: u8, pin: usize, } struct PwmDriver { digit: [DigitToPin; 10], } struct PwmOutputMap { driver: [PwmDriver; 4], dot_address: u8, dot_pin: usize, } static TUBE_MAPPING: PwmOutputMap = { PwmOutputMap { driver: [ PwmDriver { digit: [ DigitToPin { address: PCA9685_ADDR_1, pin: 8, }, // Tube 0 Digit 0 DigitToPin { address: PCA9685_ADDR_1, pin: 9, }, // Tube 0 Digit 1 DigitToPin { address: PCA9685_ADDR_1, pin: 10, }, // Tube 0 Digit 2 DigitToPin { address: PCA9685_ADDR_1, pin: 12, }, // Tube 0 Digit 3 DigitToPin { address: PCA9685_ADDR_1, pin: 15, }, // Tube 0 Digit 4 DigitToPin { address: PCA9685_ADDR_1, pin: 14, }, // Tube 0 Digit 5 DigitToPin { address: PCA9685_ADDR_1, pin: 11, }, // Tube 0 Digit 6 DigitToPin { address: PCA9685_ADDR_1, pin: 0, }, // Tube 0 Digit 7 DigitToPin { address: PCA9685_ADDR_1, pin: 1, }, // Tube 0 Digit 8 DigitToPin { address: PCA9685_ADDR_1, pin: 13, }, // Tube 0 Digit 9 ], }, PwmDriver { digit: [ DigitToPin { address: PCA9685_ADDR_1, pin: 5, }, // Tube 1 Digit 0 DigitToPin { address: PCA9685_ADDR_1, pin: 6, }, // Tube 1 Digit 1 DigitToPin { address: PCA9685_ADDR_1, pin: 7, }, // Tube 1 Digit 2 DigitToPin { address: PCA9685_ADDR_1, pin: 2, }, // Tube 1 Digit 3 DigitToPin { address: PCA9685_ADDR_2, pin: 4, }, // Tube 1 Digit 4 DigitToPin { address: PCA9685_ADDR_2, pin: 1, }, // Tube 1 Digit 5 DigitToPin { address: PCA9685_ADDR_1, pin: 4, }, // Tube 1 Digit 6 DigitToPin { address: PCA9685_ADDR_2, pin: 2, }, // Tube 1 Digit 7 DigitToPin { address: PCA9685_ADDR_2, pin: 3, }, // Tube 1 Digit 8 DigitToPin { address: PCA9685_ADDR_1, pin: 3, }, // Tube 1 Digit 9 ], }, PwmDriver { digit: [ DigitToPin { address: PCA9685_ADDR_3, pin: 8, }, // Tube 2 Digit 0 DigitToPin { address: PCA9685_ADDR_3, pin: 9, }, // Tube 2 Digit 1 DigitToPin { address: PCA9685_ADDR_3, pin: 10, }, // Tube 2 Digit 2 DigitToPin { address: PCA9685_ADDR_3, pin: 12, }, // Tube 2 Digit 3 DigitToPin { address: PCA9685_ADDR_2, pin: 12, }, // Tube 2 Digit 4 DigitToPin { address: PCA9685_ADDR_2, pin: 13, }, // Tube 2 Digit 5 DigitToPin { address: PCA9685_ADDR_3, pin: 11, }, // Tube 2 Digit 6 DigitToPin { address: PCA9685_ADDR_2, pin: 14, }, // Tube 2 Digit 7 DigitToPin { address: PCA9685_ADDR_2, pin: 11, }, // Tube 2 Digit 8 DigitToPin { address: PCA9685_ADDR_3, pin: 13, }, // Tube 2 Digit 9 ], }, PwmDriver { digit: [ DigitToPin { address: PCA9685_ADDR_3, pin: 5, }, // Tube 3 Digit 0 DigitToPin { address: PCA9685_ADDR_3, pin: 6, }, // Tube 3 Digit 1 DigitToPin { address: PCA9685_ADDR_3, pin: 7, }, // Tube 3 Digit 2 DigitToPin { address: PCA9685_ADDR_3, pin: 2, }, // Tube 3 Digit 3 DigitToPin { address: PCA9685_ADDR_3, pin: 14, }, // Tube 3 Digit 4 DigitToPin { address: PCA9685_ADDR_3, pin: 15, }, // Tube 3 Digit 5 DigitToPin { address: PCA9685_ADDR_3, pin: 4, }, // Tube 3 Digit 6 DigitToPin { address: PCA9685_ADDR_3, pin: 1, }, // Tube 3 Digit 7 DigitToPin { address: PCA9685_ADDR_3, pin: 0, }, // Tube 3 Digit 8 DigitToPin { address: PCA9685_ADDR_3, pin: 3, }, // Tube 3 Digit 9 ], }, ], dot_address: PCA9685_ADDR_2, dot_pin: 15, } }; #[derive(PartialEq)] enum DigitState { Idle, Incrementing, Decrementing, } struct Digit { current_state: DigitState, value: u32, pwm_start: u32, pwm_end: u32, updated: bool, } impl Digit { const fn default() -> Self { Self { current_state: DigitState::Idle, value: 0, pwm_start: 0, pwm_end: 0, updated: false, } } } struct Tube { digits: [Digit; NUM_DIGITS], last_active_digit: Option, refresh_last_digit: Option, refresh_active: bool, } impl Tube { const fn default() -> Self { const DIGIT_INIT: Digit = Digit::default(); Self { digits: [DIGIT_INIT; 10], last_active_digit: None, refresh_last_digit: None, refresh_active: false, } } } struct Clock { tubes: [Tube; NUM_TUBES], dot: Digit, fade_duration: u32, } impl Clock { const fn default() -> Self { const TUBE_INIT: Tube = Tube::default(); Self { tubes: [TUBE_INIT; NUM_TUBES], dot: Digit::default(), fade_duration: 0, } } } static mut CLOCK: Clock = Clock::default(); // pub fn set_digit(tube: usize, digit: usize, pwm_start: u32, pwm_end: u32) { // assert!(pwm_end >= pwm_start); // assert!(tube < NUM_TUBES); // assert!(digit < NUM_DIGITS); // unsafe { // CLOCK.tubes[tube].digits[digit].current_state = DigitState::Incrementing; // CLOCK.tubes[tube].digits[digit].pwm_start = pwm_start; // CLOCK.tubes[tube].digits[digit].pwm_end = pwm_end; // CLOCK.tubes[tube].digits[digit].value = pwm_end - pwm_start; // CLOCK.tubes[tube].digits[digit].updated = true; // } // } pub fn fade_in_out_digit(tube: usize, digit: Option, fade_duration: u32, refresh_cmd: bool) { // assert!(tube < NUM_TUBES); // assert!(Some(digit) < NUM_DIGITS); unsafe { // If the tube is in the middle of a refresh sequence and a call comes // in to update the tube digit (for time), override the last value of // the refresh sequence with the new digit. if CLOCK.tubes[tube].refresh_active && !refresh_cmd { CLOCK.tubes[tube].refresh_last_digit = digit; } // Dont update if actively refreshing tube unless RngUpdate is set if (!CLOCK.tubes[tube].refresh_active && !refresh_cmd) || refresh_cmd { // Fade out all digits for digit in 0..NUM_DIGITS { CLOCK.tubes[tube].digits[digit].current_state = DigitState::Decrementing; } // Fade in the specified digit if let Some(digit) = digit { CLOCK.tubes[tube].digits[digit].current_state = DigitState::Incrementing; } CLOCK.tubes[tube].last_active_digit = digit; CLOCK.fade_duration = fade_duration; } } // TODO! trigger refresh timer } pub fn refresh_frame() { let mut pending_refresh: bool = false; unsafe { let ticks = CLOCK.fade_duration / REFRESH_RATE_US; for tube in 0..NUM_TUBES { let steps = ((DIGIT_MAX_BRIGHTNESS - DIGIT_MIN_BRIGHTNESS) + ticks - 1) / ticks; for digit in 0..NUM_DIGITS { let mut d = &mut CLOCK.tubes[tube].digits[digit]; match d.current_state { DigitState::Incrementing => { d.value = d.value.saturating_add(steps); if d.value >= DIGIT_MAX_BRIGHTNESS { d.value = DIGIT_MAX_BRIGHTNESS; d.current_state = DigitState::Idle; } d.updated = true; pending_refresh = true; }, DigitState::Decrementing => { d.value = d.value.saturating_sub(steps); if d.value <= DIGIT_MIN_BRIGHTNESS { d.value = DIGIT_MIN_BRIGHTNESS; d.current_state = DigitState::Idle; } d.updated = true; pending_refresh = true; }, DigitState::Idle => (), } } } // Handle dot let steps = ((DOT_MAX_BRIGHTNESS - DOT_MIN_BRIGHTNESS) + ticks - 1) / ticks; match CLOCK.dot.current_state { DigitState::Incrementing => { CLOCK.dot.value = CLOCK.dot.value.saturating_add(steps); if CLOCK.dot.value >= DIGIT_MAX_BRIGHTNESS { CLOCK.dot.value = DIGIT_MAX_BRIGHTNESS; CLOCK.dot.current_state = DigitState::Idle; } CLOCK.dot.updated = true; pending_refresh = true; }, DigitState::Decrementing => { CLOCK.dot.value = CLOCK.dot.value.saturating_sub(steps); if CLOCK.dot.value >= DIGIT_MIN_BRIGHTNESS { CLOCK.dot.value = DIGIT_MIN_BRIGHTNESS; CLOCK.dot.current_state = DigitState::Idle; } CLOCK.dot.updated = true; pending_refresh = true; }, DigitState::Idle => (), } } if pending_refresh { // TODO! trigger refresh timer } }