diff --git a/.gitignore b/.gitignore index eb5a316..27ecd6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +*.pc diff --git a/left/build.rs b/left/build.rs index 43337e4..454c784 100644 --- a/left/build.rs +++ b/left/build.rs @@ -46,9 +46,10 @@ fn memory() { fn serialize_layout(ron_path: &str, postcard_path: &str) { println!("cargo:rerun-if-changed={ron_path}"); + println!("cargo:rerun-if-changed={postcard_path}"); let layers = fs::read_to_string(ron_path).expect("Failed to read .ron"); - let layers: Vec = ron::from_str(&layers).expect("Failed to deserialize .ron"); + let layers: Vec> = ron::from_str(&layers).expect("Failed to deserialize .ron"); let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers"); diff --git a/left/layers.ron b/left/layers.ron index c28fca1..b469718 100644 --- a/left/layers.ron +++ b/left/layers.ron @@ -1,89 +1,180 @@ [ - Layer( - buttons: [ - // Row 1 - Key(Escape), - Key(Comma), - Key(Period), - Key(P), - Key(Y), + [ + Layer( + buttons: [ + // Row 1 + Key(Escape), + Key(Comma), + Key(Period), + Key(P), + Key(Y), - // Row 2 - ModTap(A, LMod), - ModTap(O, LAlt), - ModTap(E, LShift), - ModTap(U, LCtrl), - Key(I), + // Row 2 + ModTap(A, LMod), + ModTap(O, LAlt), + ModTap(E, LShift), + ModTap(U, LCtrl), + Key(I), - // Row 3 - Key(Colon), - Key(Q), - Key(J), - Key(K), - Key(X), + // Row 3 + Key(Colon), + Key(Q), + Key(J), + Key(K), + Key(X), - // Thumbpad - Key(Backspace), - Key(Space), - HoldLayer(1), - ], - ), - Layer( - buttons: [ - // Row 1 - Key(Escape), - Key(Slash), - Key(Equal), - Key(Accent), - Key(Period), + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + Layer( + buttons: [ + // Row 1 + Key(Escape), + Key(Slash), + Key(Equal), + Key(Accent), + Key(Period), - // Row 2 - ModTap(BackslashPipe, LMod), - ModTap(Dash, LAlt), - ModTap(LBracket, LShift), - ModTap(RBracket, LCtrl), - Key(Tab), + // Row 2 + ModTap(BackslashPipe, LMod), + ModTap(Dash, LAlt), + ModTap(LBracket, LShift), + ModTap(RBracket, LCtrl), + Key(Tab), - // Row 3 - None, - None, - None, - Key(Apostrophe), - None, + // Row 3 + None, + None, + None, + Key(Apostrophe), + None, - // Thumbpad - Key(Backspace), - Key(Space), - HoldLayer(1), - ], - ), - Layer( - buttons: [ - // Row 1 - Key(Escape), - Key(Mute), - Key(VolumeDown), - Key(VolumeUp), - None, + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + Layer( + buttons: [ + // Row 1 + Key(Escape), + Key(Mute), + Key(VolumeDown), + Key(VolumeUp), + None, - // Row 2 - Mod(LMod), - Mod(LAlt), - Mod(LShift), - Mod(LCtrl), - None, + // Row 2 + Mod(LMod), + Mod(LAlt), + Mod(LShift), + Mod(LCtrl), + None, - // Row 3 - None, - None, - None, - None, - None, + // Row 3 + None, + None, + None, + None, + None, - // Thumbpad - Key(Backspace), - Key(Space), - HoldLayer(1), - ], - ), + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + ], + [ // gaming row + Layer( + buttons: [ + // Row 1 + Key(Escape), + Key(Q), + Key(W), + Key(E), + Key(R), + + // Row 2 + Mod(LShift), + Key(A), + Key(S), + Key(D), + Key(F), + + // Row 3 + Mod(LCtrl), + Key(Z), + Key(X), + Key(C), + Key(V), + + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + Layer( + buttons: [ + // Row 1 + Key(D1), + Key(D2), + Key(D3), + Key(D4), + Key(D5), + + // Row 2 + Key(D6), + Key(D7), + Key(D8), + Key(D9), + Key(D0), + + // Row 3 + None, + None, + None, + None, + None, + + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + Layer( + buttons: [ + // Row 1 + None, + None, + None, + None, + None, + + // Row 2 + None, + None, + None, + None, + None, + + // Row 3 + None, + None, + None, + None, + None, + + // Thumbpad + Key(Backspace), + Key(Space), + Layer(Peek, Right, 1), + ], + ), + ], ] diff --git a/left/src/layers.pc b/left/src/layers.pc deleted file mode 100644 index 5f29769..0000000 Binary files a/left/src/layers.pc and /dev/null differ diff --git a/left/src/main.rs b/left/src/main.rs index 6c820fc..758ec9a 100644 --- a/left/src/main.rs +++ b/left/src/main.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await; let layers = include_bytes!("layers.pc"); - let Ok(layers): Result, _> = postcard::from_bytes(layers) else { + let Ok(layers): Result>, _> = postcard::from_bytes(layers) else { log::error!("Failed to deserialize layer config"); stall().await }; diff --git a/lib/src/atomics.rs b/lib/src/atomics.rs new file mode 100644 index 0000000..8d368ac --- /dev/null +++ b/lib/src/atomics.rs @@ -0,0 +1,28 @@ +use atomic_polyfill::{AtomicU32, Ordering}; + +pub struct AtomicCoord { + inner: AtomicU32, +} + +impl AtomicCoord { + pub const fn new() -> Self { + AtomicCoord { + inner: AtomicU32::new(0), + } + } + + pub fn load(&self, ordering: Ordering) -> (u16, u16) { + let [a, b, c, d] = self.inner.load(ordering).to_ne_bytes(); + let x = u16::from_ne_bytes([a, b]); + let y = u16::from_ne_bytes([c, d]); + + (x, y) + } + + pub fn store(&self, x: u16, y: u16, ordering: Ordering) { + let [a, b] = x.to_ne_bytes(); + let [c, d] = y.to_ne_bytes(); + let xy = u32::from_ne_bytes([a, b, c, d]); + self.inner.store(xy, ordering); + } +} diff --git a/lib/src/keyboard.rs b/lib/src/keyboard.rs index de9d90d..6207184 100644 --- a/lib/src/keyboard.rs +++ b/lib/src/keyboard.rs @@ -1,6 +1,6 @@ mod lights; -use core::sync::atomic::{AtomicU16, Ordering}; +use core::sync::atomic::Ordering; use alloc::{boxed::Box, vec::Vec}; use embassy_executor::Spawner; @@ -12,9 +12,13 @@ use embassy_sync::pubsub::{ImmediatePublisher, PubSubChannel, Subscriber}; use embassy_time::{Duration, Instant, Timer}; use log::{debug, error, info, warn}; use static_cell::StaticCell; -use tgnt::{button::Button, layer::Layer}; +use tgnt::{ + button::{Button, LayerDir, LayerShift}, + layer::Layer, +}; use crate::{ + atomics::AtomicCoord, event::{ switch::{Event, EventKind}, Half, @@ -32,14 +36,16 @@ pub struct KeyboardConfig { /// Array of LED indices of each switch pub led_map: [usize; SWITCH_COUNT], pub led_driver: Ws2812, - pub layers: Vec, + /// Matrix of layers. Stored as rows of columns. + pub layers: Vec>, } struct State { /// Which board is this. half: Half, - current_layer: AtomicU16, - layers: &'static [Layer], + current_layer: AtomicCoord, + layer_cols: usize, + layers: &'static [Vec], /// Array of LED indices of each switch led_map: [usize; SWITCH_COUNT], lights: Lights, @@ -81,18 +87,21 @@ impl KeyboardConfig { static STATE: StaticCell = StaticCell::new(); let state = STATE.init_with(|| State { half: self.half, - current_layer: AtomicU16::new(0), + current_layer: AtomicCoord::new(), + layer_cols: self.layers.iter().map(|row| row.len()).max().unwrap_or(0), layers: Box::leak(self.layers.into_boxed_slice()), lights: Lights::new(self.led_driver), led_map: self.led_map, }); - for (i, layer) in state.layers.iter().enumerate() { - if layer.buttons.len() != SWITCH_COUNT { - warn!( - "layer {i} defines {} buttons, but there are {SWITCH_COUNT} switches", - layer.buttons.len(), - ) + for (y, row) in state.layers.iter().enumerate() { + for (x, layer) in row.iter().enumerate() { + if layer.buttons.len() != SWITCH_COUNT { + warn!( + "layer ({x}, {y}) defines {} buttons, but there are {SWITCH_COUNT} switches", + layer.buttons.len(), + ) + } } } @@ -176,21 +185,19 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! // TODO: do we need debouncing? // get current layer - let mut current_layer = state.current_layer.load(Ordering::Relaxed); - let layer_count = state.layers.len() as u16; - if current_layer >= layer_count { - error!("current layer was out of bounds for some reason ({current_layer})"); - current_layer = 0; - } - let Some(Layer { buttons }) = state.layers.get(usize::from(current_layer)) else { - error!("current layer was out of bounds for some reason ({current_layer})"); - state.current_layer.store(0, Ordering::Relaxed); + let (x, y) = state.current_layer.load(Ordering::Relaxed); + + let Some(Layer { buttons }) = state.layers.get(usize::from(y)) + .and_then(|row| row.get(usize::from(x))) else { + // currently layer is null, do nothing + pin.wait_for_high().await; continue; }; // and current button let Some(button) = buttons.get(switch_num) else { warn!("no button defined for switch {switch_num}"); + pin.wait_for_high().await; continue; }; @@ -223,30 +230,43 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! #[embassy_executor::task] async fn layer_switch_task(mut events: KbEvents, state: &'static State) { - let layer_count = state.layers.len() as u16; - let Some(last_layer) = layer_count.checked_sub(1) else { + let col_count = state.layer_cols as u16; + let row_count = state.layers.len() as u16; + let Some(last_row) = row_count.checked_sub(1) else { + error!("no layers specified"); + return; + }; + + let Some(last_col) = col_count.checked_sub(1) else { error!("no layers specified"); return; }; loop { + use LayerDir::*; + use LayerShift::*; + let event = events.recv().await; - let layer = state.current_layer.load(Ordering::Relaxed); - let new_layer = match event.kind { + let (x, y) = state.current_layer.load(Ordering::Relaxed); + let (nx, ny) = match event.kind { EventKind::Press { button } => match button { - Button::NextLayer => layer.wrapping_add(1) % layer_count, - Button::PrevLayer => layer.checked_sub(1).unwrap_or(last_layer), - Button::HoldLayer(l) => layer.wrapping_add(l) % layer_count, + Button::Layer(_, Up, n) => (x, y.checked_sub(n).unwrap_or(last_row)), + Button::Layer(_, Down, n) => (x, y.wrapping_add(n) % row_count), + Button::Layer(_, Left, n) => (x.checked_sub(n).unwrap_or(last_col), y), + Button::Layer(_, Right, n) => (x.wrapping_add(n) % col_count, y), _ => continue, }, EventKind::Release { button, .. } => match button { - Button::HoldLayer(l) => layer.checked_sub(l).unwrap_or(last_layer), + Button::Layer(Peek, Up, n) => (x, y.wrapping_add(n) % row_count), + Button::Layer(Peek, Down, n) => (x, y.checked_sub(n).unwrap_or(last_row)), + Button::Layer(Peek, Left, n) => (x.wrapping_add(n) % col_count, y), + Button::Layer(Peek, Right, n) => (x.checked_sub(n).unwrap_or(last_col), y), _ => continue, }, }; - state.current_layer.store(new_layer, Ordering::Relaxed); - debug!("switched to layer {new_layer}"); + state.current_layer.store(nx, ny, Ordering::Relaxed); + debug!("switched to layer ({nx}, {ny})"); } } diff --git a/lib/src/keyboard/lights.rs b/lib/src/keyboard/lights.rs index 3a0f9e9..66490b0 100644 --- a/lib/src/keyboard/lights.rs +++ b/lib/src/keyboard/lights.rs @@ -1,7 +1,3 @@ -use core::cmp::min; - -use atomic_polyfill::Ordering; -use embassy_futures::yield_now; use embassy_time::{Duration, Instant, Timer}; use futures::{select_biased, FutureExt}; use tgnt::button::Button; @@ -149,6 +145,8 @@ async fn handle_event( Button::Mod(..) => LightState::Solid(Rgb::new(0, 0, 150)), Button::ModTap(..) => LightState::Solid(Rgb::new(0, 0, 150)), Button::Compose(..) => LightState::Solid(Rgb::new(0, 100, 100)), + Button::Layer(..) => LightState::Solid(Rgb::new(120, 0, 120)), + /* Button::NextLayer | Button::PrevLayer => { yield_now().await; // dirty hack to make sure layer_switch_task gets to run first let layer = state.current_layer.load(Ordering::Relaxed); @@ -182,6 +180,7 @@ async fn handle_event( } LightState::Solid(Rgb::new(100, 0, 100)) } + */ _ => LightState::Solid(Rgb::new(150, 0, 0)), }, EventKind::Release { .. } => LightState::FadeBy(0.85), diff --git a/lib/src/keypress_handler.rs b/lib/src/keypress_handler.rs index 8dd4312..21f4356 100644 --- a/lib/src/keypress_handler.rs +++ b/lib/src/keypress_handler.rs @@ -134,16 +134,12 @@ pub async fn keypress_handler( }; match button { - Button::ModTap(_, _) => { + Button::ModTap(..) => { debug!("adding modtap to queue"); // add event to queue insert(queue, button); } - Button::Mod(m) => { - // if events in queue, also add to queue maybe? - // TODO - } - Button::Key(_) => { + Button::Mod(..) | Button::Key(..) => { if queue.is_empty() { debug!("sending key now"); // otherwise, send immediately @@ -195,11 +191,7 @@ pub async fn keypress_handler( slow_release(output, &button).await; }; } - Button::Mod(m) => { - debug!("mod not implemented yet"); - // TODO - } - Button::Key(_) => { + Button::Mod(..) | Button::Key(..) => { // if this press event was in queue, resolve all ModTaps before in queue as Mods // otherwise, just resolve this if let Some(position_in_queue) = position_in_queue { diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 0dcb571..f61164f 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -23,10 +23,11 @@ pub mod usb; #[cfg(target_arch = "arm")] pub mod ws2812; +pub mod atomics; pub mod event; +pub mod keypress_handler; pub mod logger; pub mod neopixel; pub mod rgb; pub mod rtt; pub mod util; -pub mod keypress_handler; diff --git a/lib/src/uart.rs b/lib/src/uart.rs index 14aa159..e5119e7 100644 --- a/lib/src/uart.rs +++ b/lib/src/uart.rs @@ -50,6 +50,7 @@ async fn uart_task(uart: BufferedUart<'static, UART0>, this_half: Half, mut even let (mut rx, mut tx) = uart.split(); let (mut events_rx, mut events_tx) = events.split(); + /// The header of a UART packet. #[repr(C)] #[derive(Clone, Copy, Debug, NoUninit, AnyBitPattern)] struct Header { @@ -78,11 +79,14 @@ async fn uart_task(uart: BufferedUart<'static, UART0>, this_half: Half, mut even if calculated_crc != crc { log::error!("invalid uart header crc: {header:x?}"); - buf.remove(0); // pop the first byte and hope we find a good packet header + buf.remove(0); // drop the first byte and hope we find a good packet header continue; } - log::debug!("got uart header {header:x?}"); + log::trace!( + "reading from uart, header={header:?}, bytes_received={}", + rest.len() + ); let len = usize::from(header.len); if rest.len() >= len { diff --git a/right/build.rs b/right/build.rs index 43337e4..c578912 100644 --- a/right/build.rs +++ b/right/build.rs @@ -48,7 +48,7 @@ fn serialize_layout(ron_path: &str, postcard_path: &str) { println!("cargo:rerun-if-changed={ron_path}"); let layers = fs::read_to_string(ron_path).expect("Failed to read .ron"); - let layers: Vec = ron::from_str(&layers).expect("Failed to deserialize .ron"); + let layers: Vec> = ron::from_str(&layers).expect("Failed to deserialize .ron"); let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers"); diff --git a/right/layers.ron b/right/layers.ron index 3407648..19d0875 100644 --- a/right/layers.ron +++ b/right/layers.ron @@ -1,90 +1,181 @@ [ - Layer( - buttons: [ - // Row 1 - Key(F), - Key(G), - Key(C), - Key(R), - Key(L), + [ + Layer( + buttons: [ + // Row 1 + Key(F), + Key(G), + Key(C), + Key(R), + Key(L), - // Row 2 - Key(D), - ModTap(H, RCtrl), - ModTap(T, RShift), - ModTap(N, RAlt), - ModTap(S, RMod), + // Row 2 + Key(D), + ModTap(H, RCtrl), + ModTap(T, RShift), + ModTap(N, RAlt), + ModTap(S, RMod), - // Row 3 - Key(B), - Key(M), - Key(W), - Key(V), - Key(Z), + // Row 3 + Key(B), + Key(M), + Key(W), + Key(V), + Key(Z), - // Thumbpad - HoldLayer(1), - Key(Return), - Key(Delete), - ], - ), - Layer( - buttons: [ - // Row 1 - Key(PrintScreen), - Key(D7), - Key(D8), - Key(D9), - Key(D0), + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + Layer( + buttons: [ + // Row 1 + Compose(O, A, None), // å + Key(D7), + Key(D8), + Key(D9), + Key(D0), - // Row 2 - None, - ModTap(D4, RCtrl), - ModTap(D5, RShift), - ModTap(D6, RAlt), - //ModTap(, RMod), - Mod(RMod), + // Row 2 + Compose(Apostrophe, A, None), // ä + ModTap(D4, RCtrl), + ModTap(D5, RShift), + ModTap(D6, RAlt), + //ModTap(, RMod), + Mod(RMod), - // Row 3 - None, - Key(D1), - Key(D2), - Key(D3), - None, + // Row 3 + Compose(Apostrophe, A, None), // ö + Key(D1), + Key(D2), + Key(D3), + None, - // Thumbpad - HoldLayer(1), - Key(Return), - Key(Delete), - ], - ), - Layer( - buttons: [ - // Row 1 - None, - None, - None, - None, - None, + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + Layer( + buttons: [ + // Row 1 + Key(F1), + Key(F4), + Key(F7), + Key(F10), + Layer(Move, Down, 1), - // Row 2 - None, - Mod(RCtrl), - Mod(RShift), - Mod(RAlt), - Mod(RMod), + // Row 2 + Key(F2), + ModTap(F5, RCtrl), + ModTap(F8, RShift), + ModTap(F11, RAlt), + Mod(RMod), - // Row 3 - None, - None, - None, - None, - None, + // Row 3 + Key(F3), + Key(F6), + Key(F9), + Key(F12), + None, - // Thumbpad - HoldLayer(1), - Key(Return), - Key(Delete), - ], - ), + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + ], + [ // gaming row + Layer( + buttons: [ + // Row 1 + None, + None, + None, + None, + None, + + // Row 2 + None, + None, + None, + None, + None, + + // Row 3 + None, + None, + None, + None, + None, + + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + Layer( + buttons: [ + // Row 1 + None, + None, + None, + None, + None, + + // Row 2 + None, + None, + None, + None, + None, + + // Row 3 + None, + None, + None, + None, + None, + + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + Layer( + buttons: [ + // Row 1 + None, + None, + None, + None, + Layer(Move, Up, 1), + + // Row 2 + None, + None, + None, + None, + None, + + // Row 3 + None, + None, + None, + None, + None, + + // Thumbpad + Layer(Peek, Right, 1), + Key(Return), + Key(Delete), + ], + ), + ], ] diff --git a/right/src/layers.pc b/right/src/layers.pc deleted file mode 100644 index 9238c38..0000000 Binary files a/right/src/layers.pc and /dev/null differ diff --git a/right/src/main.rs b/right/src/main.rs index 02489a7..4fd3edd 100644 --- a/right/src/main.rs +++ b/right/src/main.rs @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { //Timer::after(Duration::from_millis(3000)).await; let layers = include_bytes!("layers.pc"); - let Ok(layers): Result, _> = postcard::from_bytes(layers) else { + let Ok(layers): Result>, _> = postcard::from_bytes(layers) else { log::error!("Failed to deserialize layer config"); stall().await };