micro-rust/src/leds.rs

85 lines
2.2 KiB
Rust
Raw Normal View History

2024-10-17 10:02:00 +00:00
//! Driver for the micro:bit led display.
use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive};
use embassy_time::Timer;
use crate::{patterns::PATTERN_START, state};
pub const ROWS: usize = 5;
pub const COLS: usize = 5;
pub type Matrix = [[u8; COLS]; ROWS];
pub struct Display<'a> {
rows: [Output<'a>; ROWS],
cols: [Output<'a>; COLS],
matrix: Matrix,
}
/// Create a low Output from an AnyPin instance.
fn pin_to_output<'a>(x: AnyPin) -> Output<'a> {
Output::new(x, Level::Low, OutputDrive::Standard)
}
impl<'a> Display<'a> {
/// Initialize the display with the provided pins.
pub fn new(rows: [AnyPin; ROWS], cols: [AnyPin; COLS]) -> Self {
let rows = rows.map(pin_to_output);
let cols = cols.map(pin_to_output);
Self {
rows,
cols,
matrix: [[0; COLS]; ROWS],
}
}
/// Set which leds are active.
pub fn set(&mut self, matrix: Matrix) {
self.matrix = matrix;
}
/// Show the defined pattern on the leds.
pub async fn show(&mut self) {
for (i, row) in self.matrix.iter().enumerate() {
self.rows[i].set_high();
for (j, cell) in row.iter().enumerate() {
if *cell > 0 {
self.cols[j].set_low();
}
}
// TODO: instead of waiting for a set time, try
// implementing some kind of constant refresh rate
Timer::after_micros(10).await;
for col in &mut self.cols {
col.set_high();
}
self.rows[i].set_low();
}
}
}
/// Show the active pattern on the led screen.
/// React on new pattern messages by showing the new pattern.
#[embassy_executor::task]
pub async fn task(rows: [AnyPin; ROWS], cols: [AnyPin; COLS]) {
let mut state_sub = state::STATE.subscriber().unwrap();
let mut display = Display::new(rows, cols);
display.set(PATTERN_START);
loop {
if let Some(msg) = state_sub.try_next_message_pure() {
if let state::StateChange::Pattern(new_pattern) = msg {
display.set(new_pattern);
}
}
display.show().await;
Timer::after_micros(10).await;
}
}