From 527d34840e87c11bbcdad6887bdf986229b853e4 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Wed, 17 Sep 2025 23:00:23 +0200 Subject: [PATCH] Code cleanup --- .gitignore | 1 + README.md | 29 +++++++++++------------------ rp2040/firmware.uf2 | Bin 47616 -> 0 bytes rp2040/src/hardware.rs | 2 +- rp2040/src/status.rs | 2 +- 5 files changed, 14 insertions(+), 20 deletions(-) delete mode 100644 rp2040/firmware.uf2 diff --git a/.gitignore b/.gitignore index 7145b50..23ec5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ rp2040_42/Cargo.lock rp2040_51/Cargo.lock *.FCBak rp2040/target +rp2040/firmware.uf2 diff --git a/README.md b/README.md index c9c137d..e168f02 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ - 42 keys "Split" keyboard layout. 36 finger buttons and 6 thumb buttons. - Extreme low profile (only one pcb). - Cost efficient solution with one pcb and one 3D printed cover. -- Function keys with total of three layer support (Primary + 2fn layers). -- Status indication - - - LED green = Normal mode - - LED green flashing = waiting for USB enumeration - - LED blue on = sticky lock initiated - - LED blue flashing = sticky lock activated - - LED red = error - - LED red flashing = Caps Lock activated +- Function layers provide three active maps (primary + two Fn layers) with sticky-lock support. +- High-speed key scanning: 250 µs cadence with 2-scan press / 3-scan release debounce for sub-millisecond latency and immediate USB reporting. +- Status indication driven by the joystick-style heartbeat model: + - Heartbeat green while waiting for USB enumeration. + - Solid green during normal operation; automatic heartbeat idle animation after 5 s inactivity. + - Blue solid / flashing when sticky lock is armed / latched. + - Red solid on firmware error, red flashing for Caps Lock. + ## Build environment rp2040 Zero @@ -101,17 +101,11 @@ Rust embedded, rp2040 HAL ## Features -- 51 keys "Split" keyboard layout. 36 finger buttons and 9 thumb buttons and 6 function buttons. +- 51 keys "Split" keyboard layout. 36 finger buttons, 9 thumb buttons and 6 function buttons. - Extreme low profile (only one pcb). - Cost efficient solution with one pcb and one 3D printed cover. -- Function keys with total of three layer support (Primary + 2fn layers). -- Status indication - - - LED green = Normal mode - - LED green flashing = waiting for USB enumeration - - LED blue on = sticky lock initiated - - LED blue flashing = sticky lock activated - - LED red = error - - LED red flashing = Caps Lock activated +- Function layers with the same immediate-report, low-latency scanning pipeline as the 42-key variant (primary + two Fn layers with sticky lock). +- Status LED behaviour mirrors the joystick/42-key firmware: heartbeat during boot, idle animation after 5 s inactivity, blue indicators for sticky lock, and red for caps/error conditions. ## Build environment rp2040 Zero @@ -135,4 +129,3 @@ Rust embedded, rp2040 HAL - 1x PCB [Gerber files](eCAD/cmdr_mainboard_51_gerber_v1.zip) - 1x MCU cover (TBD) - 1x 6x3 Cherry MX mounting jig (optional) [STL file](mCAD/cmdr_mounting_jig-MountingJig.stl) - diff --git a/rp2040/firmware.uf2 b/rp2040/firmware.uf2 deleted file mode 100644 index 747db56f65dcd5ec9b016c8d2cb94bfd0623762a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47616 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 0, LedEffect::Blink { period_ms } => period_ms / 2, - LedEffect::Heartbeat { .. } => 4, + LedEffect::Heartbeat { .. } => 10, } }