Switch to layer matrix instead of layer list

This commit is contained in:
2023-07-21 16:18:47 +02:00
parent 2c239b6248
commit dcf950cc66
15 changed files with 438 additions and 210 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
target target
*.pc

View File

@ -46,9 +46,10 @@ fn memory() {
fn serialize_layout(ron_path: &str, postcard_path: &str) { fn serialize_layout(ron_path: &str, postcard_path: &str) {
println!("cargo:rerun-if-changed={ron_path}"); 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 = fs::read_to_string(ron_path).expect("Failed to read .ron");
let layers: Vec<Layer> = ron::from_str(&layers).expect("Failed to deserialize .ron"); let layers: Vec<Vec<Layer>> = ron::from_str(&layers).expect("Failed to deserialize .ron");
let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers"); let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers");

View File

@ -1,4 +1,5 @@
[ [
[
Layer( Layer(
buttons: [ buttons: [
// Row 1 // Row 1
@ -25,7 +26,7 @@
// Thumbpad // Thumbpad
Key(Backspace), Key(Backspace),
Key(Space), Key(Space),
HoldLayer(1), Layer(Peek, Right, 1),
], ],
), ),
Layer( Layer(
@ -54,7 +55,7 @@
// Thumbpad // Thumbpad
Key(Backspace), Key(Backspace),
Key(Space), Key(Space),
HoldLayer(1), Layer(Peek, Right, 1),
], ],
), ),
Layer( Layer(
@ -83,7 +84,97 @@
// Thumbpad // Thumbpad
Key(Backspace), Key(Backspace),
Key(Space), Key(Space),
HoldLayer(1), 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),
],
),
],
] ]

Binary file not shown.

View File

@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) {
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await; neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
let layers = include_bytes!("layers.pc"); let layers = include_bytes!("layers.pc");
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else { let Ok(layers): Result<Vec<Vec<Layer>>, _> = postcard::from_bytes(layers) else {
log::error!("Failed to deserialize layer config"); log::error!("Failed to deserialize layer config");
stall().await stall().await
}; };

28
lib/src/atomics.rs Normal file
View File

@ -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);
}
}

View File

@ -1,6 +1,6 @@
mod lights; mod lights;
use core::sync::atomic::{AtomicU16, Ordering}; use core::sync::atomic::Ordering;
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use embassy_executor::Spawner; use embassy_executor::Spawner;
@ -12,9 +12,13 @@ use embassy_sync::pubsub::{ImmediatePublisher, PubSubChannel, Subscriber};
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use static_cell::StaticCell; use static_cell::StaticCell;
use tgnt::{button::Button, layer::Layer}; use tgnt::{
button::{Button, LayerDir, LayerShift},
layer::Layer,
};
use crate::{ use crate::{
atomics::AtomicCoord,
event::{ event::{
switch::{Event, EventKind}, switch::{Event, EventKind},
Half, Half,
@ -32,14 +36,16 @@ pub struct KeyboardConfig {
/// Array of LED indices of each switch /// Array of LED indices of each switch
pub led_map: [usize; SWITCH_COUNT], pub led_map: [usize; SWITCH_COUNT],
pub led_driver: Ws2812<PIO1>, pub led_driver: Ws2812<PIO1>,
pub layers: Vec<Layer>, /// Matrix of layers. Stored as rows of columns.
pub layers: Vec<Vec<Layer>>,
} }
struct State { struct State {
/// Which board is this. /// Which board is this.
half: Half, half: Half,
current_layer: AtomicU16, current_layer: AtomicCoord,
layers: &'static [Layer], layer_cols: usize,
layers: &'static [Vec<Layer>],
/// Array of LED indices of each switch /// Array of LED indices of each switch
led_map: [usize; SWITCH_COUNT], led_map: [usize; SWITCH_COUNT],
lights: Lights<PIO1, SWITCH_COUNT>, lights: Lights<PIO1, SWITCH_COUNT>,
@ -81,20 +87,23 @@ impl KeyboardConfig {
static STATE: StaticCell<State> = StaticCell::new(); static STATE: StaticCell<State> = StaticCell::new();
let state = STATE.init_with(|| State { let state = STATE.init_with(|| State {
half: self.half, 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()), layers: Box::leak(self.layers.into_boxed_slice()),
lights: Lights::new(self.led_driver), lights: Lights::new(self.led_driver),
led_map: self.led_map, led_map: self.led_map,
}); });
for (i, layer) in state.layers.iter().enumerate() { for (y, row) in state.layers.iter().enumerate() {
for (x, layer) in row.iter().enumerate() {
if layer.buttons.len() != SWITCH_COUNT { if layer.buttons.len() != SWITCH_COUNT {
warn!( warn!(
"layer {i} defines {} buttons, but there are {SWITCH_COUNT} switches", "layer ({x}, {y}) defines {} buttons, but there are {SWITCH_COUNT} switches",
layer.buttons.len(), layer.buttons.len(),
) )
} }
} }
}
for (i, pin) in self.pins.into_iter().enumerate() { for (i, pin) in self.pins.into_iter().enumerate() {
if spawner.spawn(switch_task(i, pin, state)).is_err() { if spawner.spawn(switch_task(i, pin, state)).is_err() {
@ -176,21 +185,19 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
// TODO: do we need debouncing? // TODO: do we need debouncing?
// get current layer // get current layer
let mut current_layer = state.current_layer.load(Ordering::Relaxed); let (x, y) = state.current_layer.load(Ordering::Relaxed);
let layer_count = state.layers.len() as u16;
if current_layer >= layer_count { let Some(Layer { buttons }) = state.layers.get(usize::from(y))
error!("current layer was out of bounds for some reason ({current_layer})"); .and_then(|row| row.get(usize::from(x))) else {
current_layer = 0; // currently layer is null, do nothing
} pin.wait_for_high().await;
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);
continue; continue;
}; };
// and current button // and current button
let Some(button) = buttons.get(switch_num) else { let Some(button) = buttons.get(switch_num) else {
warn!("no button defined for switch {switch_num}"); warn!("no button defined for switch {switch_num}");
pin.wait_for_high().await;
continue; continue;
}; };
@ -223,30 +230,43 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
#[embassy_executor::task] #[embassy_executor::task]
async fn layer_switch_task(mut events: KbEvents, state: &'static State) { async fn layer_switch_task(mut events: KbEvents, state: &'static State) {
let layer_count = state.layers.len() as u16; let col_count = state.layer_cols as u16;
let Some(last_layer) = layer_count.checked_sub(1) else { 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"); error!("no layers specified");
return; return;
}; };
loop { loop {
use LayerDir::*;
use LayerShift::*;
let event = events.recv().await; let event = events.recv().await;
let layer = state.current_layer.load(Ordering::Relaxed); let (x, y) = state.current_layer.load(Ordering::Relaxed);
let new_layer = match event.kind { let (nx, ny) = match event.kind {
EventKind::Press { button } => match button { EventKind::Press { button } => match button {
Button::NextLayer => layer.wrapping_add(1) % layer_count, Button::Layer(_, Up, n) => (x, y.checked_sub(n).unwrap_or(last_row)),
Button::PrevLayer => layer.checked_sub(1).unwrap_or(last_layer), Button::Layer(_, Down, n) => (x, y.wrapping_add(n) % row_count),
Button::HoldLayer(l) => layer.wrapping_add(l) % layer_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, _ => continue,
}, },
EventKind::Release { button, .. } => match button { 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, _ => continue,
}, },
}; };
state.current_layer.store(new_layer, Ordering::Relaxed); state.current_layer.store(nx, ny, Ordering::Relaxed);
debug!("switched to layer {new_layer}"); debug!("switched to layer ({nx}, {ny})");
} }
} }

View File

@ -1,7 +1,3 @@
use core::cmp::min;
use atomic_polyfill::Ordering;
use embassy_futures::yield_now;
use embassy_time::{Duration, Instant, Timer}; use embassy_time::{Duration, Instant, Timer};
use futures::{select_biased, FutureExt}; use futures::{select_biased, FutureExt};
use tgnt::button::Button; use tgnt::button::Button;
@ -149,6 +145,8 @@ async fn handle_event(
Button::Mod(..) => LightState::Solid(Rgb::new(0, 0, 150)), Button::Mod(..) => LightState::Solid(Rgb::new(0, 0, 150)),
Button::ModTap(..) => 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::Compose(..) => LightState::Solid(Rgb::new(0, 100, 100)),
Button::Layer(..) => LightState::Solid(Rgb::new(120, 0, 120)),
/*
Button::NextLayer | Button::PrevLayer => { Button::NextLayer | Button::PrevLayer => {
yield_now().await; // dirty hack to make sure layer_switch_task gets to run first yield_now().await; // dirty hack to make sure layer_switch_task gets to run first
let layer = state.current_layer.load(Ordering::Relaxed); 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(100, 0, 100))
} }
*/
_ => LightState::Solid(Rgb::new(150, 0, 0)), _ => LightState::Solid(Rgb::new(150, 0, 0)),
}, },
EventKind::Release { .. } => LightState::FadeBy(0.85), EventKind::Release { .. } => LightState::FadeBy(0.85),

View File

@ -134,16 +134,12 @@ pub async fn keypress_handler(
}; };
match button { match button {
Button::ModTap(_, _) => { Button::ModTap(..) => {
debug!("adding modtap to queue"); debug!("adding modtap to queue");
// add event to queue // add event to queue
insert(queue, button); insert(queue, button);
} }
Button::Mod(m) => { Button::Mod(..) | Button::Key(..) => {
// if events in queue, also add to queue maybe?
// TODO
}
Button::Key(_) => {
if queue.is_empty() { if queue.is_empty() {
debug!("sending key now"); debug!("sending key now");
// otherwise, send immediately // otherwise, send immediately
@ -195,11 +191,7 @@ pub async fn keypress_handler(
slow_release(output, &button).await; slow_release(output, &button).await;
}; };
} }
Button::Mod(m) => { Button::Mod(..) | Button::Key(..) => {
debug!("mod not implemented yet");
// TODO
}
Button::Key(_) => {
// if this press event was in queue, resolve all ModTaps before in queue as Mods // if this press event was in queue, resolve all ModTaps before in queue as Mods
// otherwise, just resolve this // otherwise, just resolve this
if let Some(position_in_queue) = position_in_queue { if let Some(position_in_queue) = position_in_queue {

View File

@ -23,10 +23,11 @@ pub mod usb;
#[cfg(target_arch = "arm")] #[cfg(target_arch = "arm")]
pub mod ws2812; pub mod ws2812;
pub mod atomics;
pub mod event; pub mod event;
pub mod keypress_handler;
pub mod logger; pub mod logger;
pub mod neopixel; pub mod neopixel;
pub mod rgb; pub mod rgb;
pub mod rtt; pub mod rtt;
pub mod util; pub mod util;
pub mod keypress_handler;

View File

@ -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 rx, mut tx) = uart.split();
let (mut events_rx, mut events_tx) = events.split(); let (mut events_rx, mut events_tx) = events.split();
/// The header of a UART packet.
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug, NoUninit, AnyBitPattern)] #[derive(Clone, Copy, Debug, NoUninit, AnyBitPattern)]
struct Header { struct Header {
@ -78,11 +79,14 @@ async fn uart_task(uart: BufferedUart<'static, UART0>, this_half: Half, mut even
if calculated_crc != crc { if calculated_crc != crc {
log::error!("invalid uart header crc: {header:x?}"); 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; 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); let len = usize::from(header.len);
if rest.len() >= len { if rest.len() >= len {

View File

@ -48,7 +48,7 @@ fn serialize_layout(ron_path: &str, postcard_path: &str) {
println!("cargo:rerun-if-changed={ron_path}"); println!("cargo:rerun-if-changed={ron_path}");
let layers = fs::read_to_string(ron_path).expect("Failed to read .ron"); let layers = fs::read_to_string(ron_path).expect("Failed to read .ron");
let layers: Vec<Layer> = ron::from_str(&layers).expect("Failed to deserialize .ron"); let layers: Vec<Vec<Layer>> = ron::from_str(&layers).expect("Failed to deserialize .ron");
let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers"); let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers");

View File

@ -1,4 +1,5 @@
[ [
[
Layer( Layer(
buttons: [ buttons: [
// Row 1 // Row 1
@ -23,7 +24,7 @@
Key(Z), Key(Z),
// Thumbpad // Thumbpad
HoldLayer(1), Layer(Peek, Right, 1),
Key(Return), Key(Return),
Key(Delete), Key(Delete),
], ],
@ -31,14 +32,14 @@
Layer( Layer(
buttons: [ buttons: [
// Row 1 // Row 1
Key(PrintScreen), Compose(O, A, None), // å
Key(D7), Key(D7),
Key(D8), Key(D8),
Key(D9), Key(D9),
Key(D0), Key(D0),
// Row 2 // Row 2
None, Compose(Apostrophe, A, None), // ä
ModTap(D4, RCtrl), ModTap(D4, RCtrl),
ModTap(D5, RShift), ModTap(D5, RShift),
ModTap(D6, RAlt), ModTap(D6, RAlt),
@ -46,14 +47,74 @@
Mod(RMod), Mod(RMod),
// Row 3 // Row 3
None, Compose(Apostrophe, A, None), // ö
Key(D1), Key(D1),
Key(D2), Key(D2),
Key(D3), Key(D3),
None, None,
// Thumbpad // Thumbpad
HoldLayer(1), 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
Key(F2),
ModTap(F5, RCtrl),
ModTap(F8, RShift),
ModTap(F11, RAlt),
Mod(RMod),
// Row 3
Key(F3),
Key(F6),
Key(F9),
Key(F12),
None,
// 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(Return),
Key(Delete), Key(Delete),
], ],
@ -69,10 +130,10 @@
// Row 2 // Row 2
None, None,
Mod(RCtrl), None,
Mod(RShift), None,
Mod(RAlt), None,
Mod(RMod), None,
// Row 3 // Row 3
None, None,
@ -82,9 +143,39 @@
None, None,
// Thumbpad // Thumbpad
HoldLayer(1), Layer(Peek, Right, 1),
Key(Return), Key(Return),
Key(Delete), 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),
],
),
],
] ]

Binary file not shown.

View File

@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
//Timer::after(Duration::from_millis(3000)).await; //Timer::after(Duration::from_millis(3000)).await;
let layers = include_bytes!("layers.pc"); let layers = include_bytes!("layers.pc");
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else { let Ok(layers): Result<Vec<Vec<Layer>>, _> = postcard::from_bytes(layers) else {
log::error!("Failed to deserialize layer config"); log::error!("Failed to deserialize layer config");
stall().await stall().await
}; };