Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions fl16-inputmodules/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ use crate::games::snake;
#[cfg(feature = "ledmatrix")]
use crate::matrix::*;
#[cfg(feature = "ledmatrix")]
use crate::matrix_sync::*;
#[cfg(feature = "ledmatrix")]
use crate::patterns::*;
#[cfg(feature = "ledmatrix")]
use is31fl3741::PwmFreq;
Expand Down Expand Up @@ -515,7 +517,7 @@ pub fn handle_generic_command(command: &Command) -> Option<[u8; 32]> {
pub fn handle_command(
command: &Command,
state: &mut LedmatrixState,
matrix: &mut Foo,
display: &mut MatrixSync,
random: u8,
) -> Option<[u8; 32]> {
use crate::games::game_of_life;
Expand All @@ -528,7 +530,7 @@ pub fn handle_command(
}
Command::SetBrightness(br) => {
//let _ = serial.write("Brightness".as_bytes());
set_brightness(state, *br, matrix);
state.brightness = *br;
None
}
Command::Percentage(p) => {
Expand All @@ -545,7 +547,7 @@ pub fn handle_command(
PatternVals::ZigZag => state.grid = zigzag(),
PatternVals::FullBrightness => {
state.grid = percentage(100);
set_brightness(state, BRIGHTNESS_LEVELS, matrix);
state.brightness = BRIGHTNESS_LEVELS;
}
PatternVals::DisplayPanic => state.grid = display_panic(),
PatternVals::DisplayLotus2 => state.grid = display_lotus2(),
Expand Down Expand Up @@ -618,7 +620,7 @@ pub fn handle_command(
}
Command::SetPwmFreq(arg) => {
state.pwm_freq = *arg;
matrix.device.set_pwm_freq(state.pwm_freq.into()).unwrap();
display.set_pwm_freq(state.pwm_freq);
None
}
Command::GetPwmFreq => {
Expand Down
2 changes: 2 additions & 0 deletions fl16-inputmodules/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub mod animations;
#[cfg(feature = "ledmatrix")]
pub mod matrix;
#[cfg(feature = "ledmatrix")]
pub mod matrix_sync;
#[cfg(feature = "ledmatrix")]
pub mod patterns;

#[cfg(feature = "b1display")]
Expand Down
2 changes: 1 addition & 1 deletion fl16-inputmodules/src/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub const WIDTH: usize = 9;
pub const HEIGHT: usize = 34;
pub const LEDS: usize = WIDTH * HEIGHT;

#[derive(Clone)]
#[derive(Clone, PartialEq)]
pub struct Grid(pub [[u8; HEIGHT]; WIDTH]);
impl Default for Grid {
fn default() -> Self {
Expand Down
84 changes: 84 additions & 0 deletions fl16-inputmodules/src/matrix_sync.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use crate::control::PwmFreqArg;
use crate::led_hal as bsp;
use crate::matrix::{Grid, LedmatrixState, HEIGHT, WIDTH};
use crate::patterns::BRIGHTNESS_LEVELS;
use is31fl3741::devices::LedMatrix;
use rp2040_hal::{
gpio::{
bank0::{Gpio26, Gpio27},
FunctionI2C, PullUp,
},
pac::I2C1,
};

pub type Foo = LedMatrix<
bsp::hal::I2C<
I2C1,
(
bsp::hal::gpio::Pin<Gpio26, FunctionI2C, PullUp>,
bsp::hal::gpio::Pin<Gpio27, FunctionI2C, PullUp>,
),
>,
>;

pub struct MatrixSync {
matrix: Foo,
sent_grid: Grid,
sent_brightness: u8,
}

impl MatrixSync {
pub fn new(matrix: Foo) -> Self {
Self {
matrix,
sent_grid: Grid::default(),
sent_brightness: 0,
}
}

/// Fills the grid pixels but only sends the I2C commands if we expect it to update displayed state
pub fn flush_if_dirty(&mut self, state: &LedmatrixState) {
if state.grid != self.sent_grid || state.brightness != self.sent_brightness {
fill_grid_pixels(state, &mut self.matrix);
self.sent_grid = state.grid.clone();
self.sent_brightness = state.brightness;
}
}

pub fn set_pwm_freq(&mut self, freq: PwmFreqArg) {
self.matrix.device.set_pwm_freq(freq.into()).unwrap();
}
}

/// Just sends two I2C commands for the entire grid
fn fill_grid_pixels(state: &LedmatrixState, matrix: &mut Foo) {
// 0xB4 LEDs on the first page, 0xAB on the second page
let mut brightnesses = [0x00; 0xB4 + 0xAB];
for y in 0..HEIGHT {
for x in 0..WIDTH {
let (register, page) = (matrix.device.calc_pixel)(x as u8, y as u8);
brightnesses[(page as usize) * 0xB4 + (register as usize)] =
((state.grid.0[x][y] as u64) * (state.brightness as u64)
/ (BRIGHTNESS_LEVELS as u64)) as u8;
}
}
matrix.device.fill_matrix(&brightnesses).unwrap();
}

/// Same as fill_grid_pixels but does each pixel individually
/// So it's much slower because it has to send 306 I2C commands
pub fn _fill_grid(grid: &Grid, matrix: &mut Foo) {
for y in 0..HEIGHT {
for x in 0..WIDTH {
matrix.device.pixel(x as u8, y as u8, grid.0[x][y]).unwrap();
}
}
}

pub fn full_brightness(matrix: &mut Foo) {
// Fills every pixel individually
//matrix.fill_brightness(0xFF).unwrap();

// Fills full page at once
matrix.device.fill(0xFF).unwrap();
}
58 changes: 0 additions & 58 deletions fl16-inputmodules/src/patterns.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
use rp2040_hal::{
gpio::{
bank0::{Gpio26, Gpio27},
FunctionI2C, PullUp,
},
pac::I2C1,
};

use crate::led_hal as bsp;
use crate::mapping::*;
use crate::matrix::*;
use is31fl3741::devices::LedMatrix;

/// Bytes needed to represent all LEDs with a single bit
/// math.ceil(WIDTH * HEIGHT / 8)
Expand All @@ -18,16 +8,6 @@ pub const DRAW_BYTES: usize = 39;
/// Maximum number of brightneses levels
pub const BRIGHTNESS_LEVELS: u8 = 255;

pub type Foo = LedMatrix<
bsp::hal::I2C<
I2C1,
(
bsp::hal::gpio::Pin<Gpio26, FunctionI2C, PullUp>,
bsp::hal::gpio::Pin<Gpio27, FunctionI2C, PullUp>,
),
>,
>;

pub fn draw(bytes: &[u8; DRAW_BYTES]) -> Grid {
let mut grid = Grid::default();

Expand Down Expand Up @@ -308,44 +288,6 @@ pub fn double_gradient() -> Grid {
grid
}

/// Same as fill_grid_pixels but does each pixel individually
/// So it's much slower because it has to send 306 I2C commands
pub fn _fill_grid(grid: &Grid, matrix: &mut Foo) {
for y in 0..HEIGHT {
for x in 0..WIDTH {
matrix.device.pixel(x as u8, y as u8, grid.0[x][y]).unwrap();
}
}
}

pub fn set_brightness(state: &mut LedmatrixState, brightness: u8, matrix: &mut Foo) {
state.brightness = brightness;
fill_grid_pixels(state, matrix);
}

/// Just sends two I2C commands for the entire grid
pub fn fill_grid_pixels(state: &LedmatrixState, matrix: &mut Foo) {
// 0xB4 LEDs on the first page, 0xAB on the second page
let mut brightnesses = [0x00; 0xB4 + 0xAB];
for y in 0..HEIGHT {
for x in 0..WIDTH {
let (register, page) = (matrix.device.calc_pixel)(x as u8, y as u8);
brightnesses[(page as usize) * 0xB4 + (register as usize)] =
((state.grid.0[x][y] as u64) * (state.brightness as u64)
/ (BRIGHTNESS_LEVELS as u64)) as u8;
}
}
matrix.device.fill_matrix(&brightnesses).unwrap();
}

pub fn full_brightness(matrix: &mut Foo) {
// Fills every pixel individually
//matrix.fill_brightness(0xFF).unwrap();

// Fills full page at once
matrix.device.fill(0xFF).unwrap();
}

pub fn zigzag() -> Grid {
let mut grid = Grid::default();

Expand Down
30 changes: 17 additions & 13 deletions ledmatrix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ use heapless::String;
use fl16_inputmodules::control::*;
use fl16_inputmodules::games::{pong, snake};
use fl16_inputmodules::matrix::*;
use fl16_inputmodules::matrix_sync::*;
use fl16_inputmodules::patterns::*;
use fl16_inputmodules::serialnum::{device_release, get_serialnum};

Expand Down Expand Up @@ -298,7 +299,8 @@ fn main() -> ! {

matrix.device.set_pwm_freq(state.pwm_freq.into()).unwrap();

fill_grid_pixels(&state, &mut matrix);
let mut display = MatrixSync::new(matrix);
display.flush_if_dirty(&state);

let mut animation_timer = timer.get_counter().ticks();
let mut game_timer = timer.get_counter().ticks();
Expand Down Expand Up @@ -385,7 +387,7 @@ fn main() -> ! {
handle_sleep(
sleep_reason,
&mut state,
&mut matrix,
&mut display,
&mut delay,
&mut led_enable,
);
Expand All @@ -402,7 +404,7 @@ fn main() -> ! {
}
}

fill_grid_pixels(&state, &mut matrix);
display.flush_if_dirty(&state);
if state.animate {
for x in 0..WIDTH {
state.grid.0[x].rotate_right(1);
Expand Down Expand Up @@ -445,7 +447,7 @@ fn main() -> ! {
// Handle bootloader command without any delay
// No need, it'll reset the device anyways
(Some(c @ Command::BootloaderReset), _) => {
handle_command(&c, &mut state, &mut matrix, random);
handle_command(&c, &mut state, &mut display, random);
}
(Some(command), _) => {
if let Command::Sleep(go_sleeping) = command {
Expand Down Expand Up @@ -473,7 +475,7 @@ fn main() -> ! {
handle_sleep(
sleep_reason,
&mut state,
&mut matrix,
&mut display,
&mut delay,
&mut led_enable,
);
Expand All @@ -486,7 +488,7 @@ fn main() -> ! {
sleep_timer = timer.get_counter().ticks();

if let Some(response) =
handle_command(&command, &mut state, &mut matrix, random)
handle_command(&command, &mut state, &mut display, random)
{
let _ = serial.write(&response);
};
Expand All @@ -501,7 +503,7 @@ fn main() -> ! {
.unwrap();
// let _ = serial.write(text.as_bytes());

fill_grid_pixels(&state, &mut matrix);
display.flush_if_dirty(&state);
}
(None, _) => {}
}
Expand Down Expand Up @@ -613,7 +615,7 @@ fn assign_sleep_reason(
fn handle_sleep(
sleep_reason: Option<SleepReason>,
state: &mut LedmatrixState,
matrix: &mut Foo,
display: &mut MatrixSync,
delay: &mut Delay,
led_enable: &mut gpio::Pin<Gpio29, gpio::FunctionSioOutput, gpio::PullDown>,
) {
Expand All @@ -628,7 +630,8 @@ fn handle_sleep(
loop {
delay.delay_ms(100);
brightness = brightness.saturating_sub(5);
set_brightness(state, brightness, matrix);
state.brightness = brightness;
display.flush_if_dirty(state);
if brightness == 0 {
break;
}
Expand All @@ -637,7 +640,7 @@ fn handle_sleep(

if debug_mode(state) {
state.grid = display_sleep_reason(sleep_reason);
fill_grid_pixels(state, matrix);
display.flush_if_dirty(state);
} else {
// Turn LED controller off to save power
led_enable.set_low().unwrap();
Expand All @@ -651,15 +654,15 @@ fn handle_sleep(
// If debug mode is enabled, then make sure the latest sleep reason is displayed
if debug_mode(state) {
state.grid = display_sleep_reason(sleep_reason);
fill_grid_pixels(state, matrix);
display.flush_if_dirty(state);
}
}
// Sleeping and need to wake up
(SleepState::Sleeping((old_grid, old_brightness)), None) => {
// Restore back grid before sleeping
state.sleeping = SleepState::Awake;
state.grid = old_grid;
fill_grid_pixels(state, matrix);
display.flush_if_dirty(state);

// Power LED controller back on
if !debug_mode(state) {
Expand All @@ -676,7 +679,8 @@ fn handle_sleep(
} else {
brightness + 5
};
set_brightness(state, brightness, matrix);
state.brightness = brightness;
display.flush_if_dirty(state);
if brightness == old_brightness {
break;
}
Expand Down