Skip to content

Commit 0520b39

Browse files
Merge pull request #69 from FrameworkComputer/ledmatrix-dipswitch
2 parents 2ca3fb7 + 3f26e44 commit 0520b39

File tree

10 files changed

+200
-28
lines changed

10 files changed

+200
-28
lines changed

fl16-inputmodules/src/control.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub enum CommandVals {
6969
SetPowerMode = 0x1B,
7070
AnimationPeriod = 0x1C,
7171
PwmFreq = 0x1E,
72+
DebugMode = 0x1F,
7273
Version = 0x20,
7374
}
7475

@@ -205,6 +206,8 @@ pub enum Command {
205206
#[cfg(feature = "ledmatrix")]
206207
SetPwmFreq(PwmFreqArg),
207208
GetPwmFreq,
209+
SetDebugMode(bool),
210+
GetDebugMode,
208211
_Unknown,
209212
}
210213

@@ -385,6 +388,11 @@ pub fn parse_module_command(count: usize, buf: &[u8]) -> Option<Command> {
385388
Some(Command::GetPwmFreq)
386389
}
387390
}
391+
Some(CommandVals::DebugMode) => Some(if let Some(debug_mode) = arg {
392+
Command::SetDebugMode(debug_mode == 1)
393+
} else {
394+
Command::GetDebugMode
395+
}),
388396
_ => None,
389397
}
390398
} else {
@@ -614,6 +622,15 @@ pub fn handle_command(
614622
response[0] = state.pwm_freq as u8;
615623
Some(response)
616624
}
625+
Command::SetDebugMode(arg) => {
626+
state.debug_mode = *arg;
627+
None
628+
}
629+
Command::GetDebugMode => {
630+
let mut response: [u8; 32] = [0; 32];
631+
response[0] = state.debug_mode as u8;
632+
Some(response)
633+
}
617634
_ => handle_generic_command(command),
618635
}
619636
}

fl16-inputmodules/src/led_hal.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub use hal::pac;
1717
hal::bsp_pins!(
1818
/// GPIO 0 is connected to the SLEEP# pin of the EC
1919
Gpio0 { name: sleep },
20+
/// GPIO 25 is connected to the DIP Switch #1
21+
Gpio25 { name: dip1 },
2022
/// GPIO 26 is connected to I2C SDA of the LED controller
2123
Gpio26 {
2224
name: gpio26,

fl16-inputmodules/src/mapping.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,13 @@ pub const EXCLAMATION_MARK: SingleDisplayData = [
328328
0b00000000,
329329
0b00010000,
330330
];
331+
pub const HASH: SingleDisplayData = [
332+
0b00100100,
333+
0b00100111,
334+
0b00111100,
335+
0b11100100,
336+
0b00100111,
337+
0b00111100,
338+
0b11100100,
339+
0b00100100,
340+
];

fl16-inputmodules/src/matrix.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,49 @@ impl Default for Grid {
1616
}
1717

1818
pub struct LedmatrixState {
19+
/// Currently displayed grid
1920
pub grid: Grid,
21+
/// Temporary buffer for building a new grid
2022
pub col_buffer: Grid,
23+
/// Whether the grid is currently being animated
2124
pub animate: bool,
25+
/// LED brightness out of 255
2226
pub brightness: u8,
27+
/// Current sleep state
2328
pub sleeping: SleepState,
29+
/// State of the current game, if any
2430
pub game: Option<GameState>,
2531
pub animation_period: u64,
32+
/// Current LED PWM frequency
2633
pub pwm_freq: PwmFreqArg,
34+
/// Whether debug mode is active
35+
///
36+
/// In debug mode:
37+
/// - Startup is instant, no animation
38+
/// - Sleep/wake transition is instant, no animation/fading
39+
/// - No automatic sleeping
40+
pub debug_mode: bool,
2741
}
2842

2943
#[allow(clippy::large_enum_variant)]
3044
#[derive(Clone)]
45+
/// Whether asleep or not, if asleep contains data to restore previous LED grid
3146
pub enum SleepState {
3247
Awake,
3348
Sleeping((Grid, u8)),
3449
}
3550

51+
#[derive(Copy, Clone, Debug)]
52+
pub enum SleepReason {
53+
Command,
54+
SleepPin,
55+
Timeout,
56+
UsbSuspend,
57+
}
58+
3659
#[allow(clippy::large_enum_variant)]
3760
#[derive(Clone)]
61+
/// State that's used for each game
3862
pub enum GameState {
3963
Snake(SnakeState),
4064
Pong(PongState),

fl16-inputmodules/src/patterns.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,37 @@ pub fn draw_grey_col(grid: &mut Grid, col: u8, levels: &[u8; HEIGHT]) {
5050
grid.0[8 - col as usize][..HEIGHT].copy_from_slice(&levels[..HEIGHT]);
5151
}
5252

53+
pub fn display_sleep_reason(sleep_reason: SleepReason) -> Grid {
54+
let mut grid = Grid::default();
55+
56+
match sleep_reason {
57+
SleepReason::Command => {
58+
display_letter(20, &mut grid, CAP_C);
59+
display_letter(10, &mut grid, CAP_M);
60+
display_letter(0, &mut grid, CAP_D);
61+
}
62+
SleepReason::SleepPin => {
63+
display_letter(23, &mut grid, CAP_S);
64+
display_letter(13, &mut grid, CAP_L);
65+
display_letter(7, &mut grid, CAP_P);
66+
display_letter(0, &mut grid, HASH);
67+
}
68+
SleepReason::Timeout => {
69+
display_letter(24, &mut grid, CAP_T);
70+
display_letter(16, &mut grid, CAP_I);
71+
display_letter(8, &mut grid, CAP_M);
72+
display_letter(0, &mut grid, CAP_E);
73+
}
74+
SleepReason::UsbSuspend => {
75+
display_letter(17, &mut grid, CAP_U);
76+
display_letter(10, &mut grid, CAP_S);
77+
display_letter(0, &mut grid, CAP_B);
78+
}
79+
};
80+
81+
grid
82+
}
83+
5384
pub fn display_sleep() -> Grid {
5485
Grid([
5586
[

inputmodule-control/src/inputmodule.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum Command {
4848
PowerMode = 0x1B,
4949
AnimationPeriod = 0x1C,
5050
PwmFreq = 0x1E,
51+
DebugMode = 0x1F,
5152
Version = 0x20,
5253
}
5354

@@ -225,6 +226,9 @@ pub fn serial_commands(args: &crate::ClapCli) {
225226
if let Some(freq) = ledmatrix_args.pwm_freq {
226227
pwm_freq_cmd(serialdev, freq);
227228
}
229+
if let Some(debug_mode) = ledmatrix_args.debug_mode {
230+
debug_mode_cmd(serialdev, debug_mode);
231+
}
228232

229233
if ledmatrix_args.stop_game {
230234
simple_cmd(
@@ -446,6 +450,26 @@ fn sleeping_cmd(serialdev: &str, arg: Option<bool>) {
446450
}
447451
}
448452

453+
fn debug_mode_cmd(serialdev: &str, arg: Option<bool>) {
454+
let mut port = serialport::new(serialdev, 115_200)
455+
.timeout(SERIAL_TIMEOUT)
456+
.open()
457+
.expect("Failed to open port");
458+
459+
if let Some(enable_debug) = arg {
460+
simple_cmd_port(&mut port, Command::DebugMode, &[u8::from(enable_debug)]);
461+
} else {
462+
simple_cmd_port(&mut port, Command::DebugMode, &[]);
463+
464+
let mut response: Vec<u8> = vec![0; 32];
465+
port.read_exact(response.as_mut_slice())
466+
.expect("Found no data!");
467+
468+
let debug_mode: bool = response[0] == 1;
469+
println!("Debug Mode enabled: {debug_mode}");
470+
}
471+
}
472+
449473
fn brightness_cmd(serialdev: &str, arg: Option<u8>) {
450474
let mut port = serialport::new(serialdev, 115_200)
451475
.timeout(SERIAL_TIMEOUT)

inputmodule-control/src/ledmatrix.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ pub struct LedMatrixSubcommand {
131131
#[clap(value_enum)]
132132
pub pwm_freq: Option<Option<u16>>,
133133

134+
/// Set debug mode or get current mode, if no value provided
135+
#[arg(long)]
136+
pub debug_mode: Option<Option<bool>>,
137+
134138
/// Crash the firmware (TESTING ONLY!)
135139
#[arg(long)]
136140
pub panic: bool,

ledmatrix/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,31 @@ Any other command will also wake up the device.
217217

218218
The idle timer will send the device to sleep after a configured timeout (default 60 seconds).
219219
The idle timer is reset once the device wakes up or once it receives a command.
220+
221+
## DIP Switch
222+
223+
LED Matrix hardware since DVT2 (September 2023) has a DIP switch with two
224+
switches, let's call them DIP1 and DIP2.
225+
226+
###### DIP2 (Bootloader)
227+
228+
DIP2 is the bootloader switch. To enter bootloader mode follow these steps:
229+
230+
1. Unplug module and flip the switch to ON
231+
2. Plug module back in, it will appear as a flash drive with the name `RPI-RP2`
232+
3. Copy the firmware `.uf2` file onto that drive, it will automatically flash and reappear as a flash drive
233+
4. To exit bootloader mode, unplug the module to flip the switch back, and plug it back in
234+
5. Now the new firmware should be running
235+
236+
###### DIP1 (General Purpose)
237+
238+
DIP1 could serve many purposes. Currently it is configured to enable the debug mode.
239+
When debug mode is enabled and the module goes to sleep, it will not turn the LEDs off to save power.
240+
Instead it will display the reason why it went to sleep. This is useful for debugging module and host system behavior.
241+
242+
Sleep Reasons can be:
243+
244+
- `SLEEP#` pin: `SLP#`
245+
- USB Suspend: `USB`
246+
- Command: `CMD`
247+
- Idle timer: `TIME`

0 commit comments

Comments
 (0)