Move away from matrix-based key layout
This commit is contained in:
81
Cargo.lock
generated
81
Cargo.lock
generated
@ -70,6 +70,12 @@ dependencies = [
|
|||||||
"rustc_version 0.2.3",
|
"rustc_version 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -115,6 +121,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cobs"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -418,6 +430,16 @@ dependencies = [
|
|||||||
"usbd-hid",
|
"usbd-hid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-alloc"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8931e47e33c5d3194fbcf9cc82df0919193bd2fa40008f388eb1d28fd9c9ea6b"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
"linked_list_allocator",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal"
|
name = "embedded-hal"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -609,6 +631,7 @@ dependencies = [
|
|||||||
"atomic-polyfill 0.1.11",
|
"atomic-polyfill 0.1.11",
|
||||||
"hash32",
|
"hash32",
|
||||||
"rustc_version 0.4.0",
|
"rustc_version 0.4.0",
|
||||||
|
"serde",
|
||||||
"spin",
|
"spin",
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
@ -661,14 +684,18 @@ dependencies = [
|
|||||||
"embassy-usb",
|
"embassy-usb",
|
||||||
"embassy-usb-driver",
|
"embassy-usb-driver",
|
||||||
"embassy-usb-logger",
|
"embassy-usb-logger",
|
||||||
|
"embedded-alloc",
|
||||||
"embedded-hal 0.2.7",
|
"embedded-hal 0.2.7",
|
||||||
"embedded-io",
|
"embedded-io",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
"pio",
|
"pio",
|
||||||
"pio-proc",
|
"pio-proc",
|
||||||
|
"postcard",
|
||||||
|
"ron",
|
||||||
"smart-leds",
|
"smart-leds",
|
||||||
"static_cell",
|
"static_cell",
|
||||||
|
"tgnt",
|
||||||
"usb-device",
|
"usb-device",
|
||||||
"usbd-hid",
|
"usbd-hid",
|
||||||
]
|
]
|
||||||
@ -711,6 +738,12 @@ version = "0.2.140"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked_list_allocator"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@ -896,6 +929,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "postcard"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfa512cd0d087cc9f99ad30a1bf64795b67871edbead083ffc3a4dfafa59aa00"
|
||||||
|
dependencies = [
|
||||||
|
"cobs",
|
||||||
|
"heapless",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "precomputed-hash"
|
name = "precomputed-hash"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -996,6 +1040,17 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ron"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bitflags",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rp2040-pac2"
|
name = "rp2040-pac2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1058,9 +1113,23 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.154"
|
version = "1.0.156"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e"
|
checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.156"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
@ -1176,6 +1245,14 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tgnt"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.nubo.sh/hulthe/tgnt.git#e22588c2cb139864fcd3be1087350803343c622b"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.39"
|
version = "1.0.39"
|
||||||
|
|||||||
17
Cargo.toml
17
Cargo.toml
@ -4,17 +4,16 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
#adafruit-itsy-bitsy-rp2040 = "0.6.0"
|
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
|
||||||
cortex-m = "0.7.6"
|
cortex-m = "0.7.6"
|
||||||
cortex-m-rt = "0.7"
|
cortex-m-rt = "0.7"
|
||||||
embedded-hal ="0.2.5"
|
embedded-hal = "0.2.5"
|
||||||
#panic-halt= "0.2.0"
|
#panic-halt = "0.2.0"
|
||||||
usb-device = "*"
|
usb-device = "0.2.9"
|
||||||
usbd-hid = "0.6.1"
|
usbd-hid = "0.6.1"
|
||||||
static_cell = "1.0.0"
|
static_cell = "1.0.0"
|
||||||
embedded-io = { version = "*", features = ["async"] }
|
embedded-io = { version = "*", features = ["async"] }
|
||||||
futures = { version = "0.3", default-features = false }
|
futures = { version = "0.3", default-features = false }
|
||||||
|
|
||||||
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly", "integrated-timers" ] }
|
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly", "integrated-timers" ] }
|
||||||
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly"] }
|
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly"] }
|
||||||
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", features = ["log"] }
|
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", features = ["log"] }
|
||||||
@ -22,12 +21,18 @@ embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", features
|
|||||||
embassy-usb = { git = "https://github.com/embassy-rs/embassy.git", features = ["usbd-hid"] }
|
embassy-usb = { git = "https://github.com/embassy-rs/embassy.git", features = ["usbd-hid"] }
|
||||||
embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy.git", features = [] }
|
embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy.git", features = [] }
|
||||||
embassy-usb-driver = { git = "https://github.com/embassy-rs/embassy.git", features = [] }
|
embassy-usb-driver = { git = "https://github.com/embassy-rs/embassy.git", features = [] }
|
||||||
|
|
||||||
embassy-rp = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly", "unstable-traits", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
|
embassy-rp = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly", "unstable-traits", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
pio = "0.2.1"
|
pio = "0.2.1"
|
||||||
pio-proc = "0.2.1"
|
pio-proc = "0.2.1"
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
|
embedded-alloc = "0.5.0"
|
||||||
|
postcard = { version = "1.0.4", features = ["alloc"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
|
||||||
|
ron = "0.8.0"
|
||||||
|
postcard = { version = "1", features = ["use-std"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["n-key-rollover"]
|
default = ["n-key-rollover"]
|
||||||
|
|||||||
23
build.rs
23
build.rs
@ -8,12 +8,19 @@
|
|||||||
//! updating `memory.x` ensures a rebuild of the application with the
|
//! updating `memory.x` ensures a rebuild of the application with the
|
||||||
//! new memory settings.
|
//! new memory settings.
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use tgnt::layer::Layer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
memory();
|
||||||
|
serialize_layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory() {
|
||||||
// Put `memory.x` in our output directory and ensure it's
|
// Put `memory.x` in our output directory and ensure it's
|
||||||
// on the linker search path.
|
// on the linker search path.
|
||||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
@ -36,3 +43,17 @@ fn main() {
|
|||||||
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
|
||||||
//println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
//println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_layout() {
|
||||||
|
println!("cargo:rerun-if-changed=layers.ron");
|
||||||
|
|
||||||
|
let layers = fs::read_to_string("layers.ron").expect("Failed to read layers.ron");
|
||||||
|
let layers: Vec<Layer> = ron::from_str(&layers).expect("Failed to deserialize layers.ron");
|
||||||
|
|
||||||
|
let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers");
|
||||||
|
|
||||||
|
File::create("./src/layers.pc")
|
||||||
|
.expect("Failed to create layers.pc")
|
||||||
|
.write_all(&serialized)
|
||||||
|
.expect("Failed to write layers.pc");
|
||||||
|
}
|
||||||
|
|||||||
59
layers.ron
Normal file
59
layers.ron
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
[
|
||||||
|
Layer(
|
||||||
|
buttons: [
|
||||||
|
/* Left */
|
||||||
|
// Row 1
|
||||||
|
Key(Apostrophe),
|
||||||
|
Key(Comma),
|
||||||
|
Key(Period),
|
||||||
|
Key(P),
|
||||||
|
Key(Y),
|
||||||
|
|
||||||
|
// Row 2
|
||||||
|
Key(A),
|
||||||
|
Key(O),
|
||||||
|
Key(E),
|
||||||
|
Key(U),
|
||||||
|
Key(I),
|
||||||
|
|
||||||
|
// Row 3
|
||||||
|
Key(Colon),
|
||||||
|
Key(Q),
|
||||||
|
Key(J),
|
||||||
|
Key(K),
|
||||||
|
Key(X),
|
||||||
|
|
||||||
|
// Thumbpad
|
||||||
|
Mod(LShift),
|
||||||
|
Mod(LCtrl),
|
||||||
|
NextLayer,
|
||||||
|
|
||||||
|
/* Right */
|
||||||
|
// Row 1
|
||||||
|
Key(F),
|
||||||
|
Key(G),
|
||||||
|
Key(C),
|
||||||
|
Key(R),
|
||||||
|
Key(L),
|
||||||
|
|
||||||
|
// Row 2
|
||||||
|
Key(D),
|
||||||
|
Key(H),
|
||||||
|
Key(T),
|
||||||
|
Key(N),
|
||||||
|
Key(S),
|
||||||
|
|
||||||
|
// Row 3
|
||||||
|
Key(B),
|
||||||
|
Key(M),
|
||||||
|
Key(W),
|
||||||
|
Key(V),
|
||||||
|
Key(Z),
|
||||||
|
|
||||||
|
// Thumbpad
|
||||||
|
PrevLayer,
|
||||||
|
Mod(RAlt),
|
||||||
|
Mod(RMod),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
1
src/.gitignore
vendored
Normal file
1
src/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
layers.pc
|
||||||
14
src/allocator.rs
Normal file
14
src/allocator.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
|
use embedded_alloc::Heap;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static HEAP: Heap = Heap::empty();
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
const HEAP_SIZE: usize = 2048;
|
||||||
|
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||||
|
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
|
||||||
|
}
|
||||||
318
src/keyboard.rs
318
src/keyboard.rs
@ -1,238 +1,154 @@
|
|||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicU16, Ordering};
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::gpio::{AnyPin, Input, Pin, Pull};
|
use embassy_rp::gpio::{AnyPin, Input, Pin, Pull};
|
||||||
use embassy_time::{Duration, Timer};
|
use log::{error, warn};
|
||||||
use log::info;
|
use tgnt::{button::Button, layer::Layer};
|
||||||
|
|
||||||
pub const ROWS: usize = 3;
|
use crate::usb::keyboard::KB_REPORT;
|
||||||
pub const COLS: usize = 5;
|
|
||||||
const NEW_SWITCH: Switch = Switch::new();
|
|
||||||
const NEW_ROW: [Switch; COLS] = [NEW_SWITCH; COLS];
|
|
||||||
pub static MATRIX: [[Switch; COLS]; ROWS] = [NEW_ROW; ROWS];
|
|
||||||
|
|
||||||
pub static TEST_KEYMAP: [[Button; COLS]; ROWS] = [
|
static CURRENT_LAYER: AtomicU16 = AtomicU16::new(0);
|
||||||
[
|
|
||||||
Button::KEY_A,
|
|
||||||
Button::KEY_B,
|
|
||||||
Button::KEY_C,
|
|
||||||
Button::KEY_D,
|
|
||||||
Button::KEY_E,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Button::KEY_T,
|
|
||||||
Button::KEY_R,
|
|
||||||
Button::KEY_H,
|
|
||||||
Button::KEY_I,
|
|
||||||
Button::KEY_SPACE,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Button::KEY_O,
|
|
||||||
Button::KEY_L,
|
|
||||||
Button::KEY_LSHIFT,
|
|
||||||
Button::KEY_LCTRL,
|
|
||||||
Button::KEY_LALT,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
pub struct Switch {
|
pub struct KeyboardConfig {
|
||||||
state: AtomicBool,
|
pub pins: [AnyPin; SWITCH_COUNT],
|
||||||
|
pub layers: Vec<Layer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
impl KeyboardConfig {
|
||||||
impl Switch {
|
pub async fn create(self) {
|
||||||
pub const fn new() -> Self {
|
let spawner = Spawner::for_current_executor().await;
|
||||||
Switch {
|
|
||||||
state: AtomicBool::new(false),
|
if self.layers.is_empty() {
|
||||||
|
error!("no layers defined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let layers = Box::leak(self.layers.into_boxed_slice());
|
||||||
|
for (i, layer) in layers.iter().enumerate() {
|
||||||
|
if layer.buttons.len() != SWITCH_COUNT {
|
||||||
|
warn!(
|
||||||
|
"layer {i} defines {} buttons, but there are {SWITCH_COUNT} switches",
|
||||||
|
layer.buttons.len(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, pin) in self.pins.into_iter().enumerate() {
|
||||||
|
if spawner.spawn(switch_task(i, pin, layers)).is_err() {
|
||||||
|
error!("failed to spawn switch task, pool_size mismatch?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn press(&self) {
|
|
||||||
self.state.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release(&self) {
|
|
||||||
self.state.store(false, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_pressed(&self) -> bool {
|
|
||||||
self.state.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
const SWITCH_COUNT: usize = 18;
|
||||||
pub enum Button {
|
#[embassy_executor::task(pool_size = 18)]
|
||||||
Key { keycode: u8 },
|
async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -> ! {
|
||||||
}
|
let _pin_nr = pin.pin();
|
||||||
|
|
||||||
#[embassy_executor::task(pool_size = 20)]
|
|
||||||
pub async fn monitor_switch(pin: AnyPin) -> ! {
|
|
||||||
let pin_nr = pin.pin();
|
|
||||||
let mut pin = Input::new(pin, Pull::Up);
|
let mut pin = Input::new(pin, Pull::Up);
|
||||||
loop {
|
loop {
|
||||||
|
// pins are pull-up, so when the switch is pressed they are brought low.
|
||||||
pin.wait_for_low().await;
|
pin.wait_for_low().await;
|
||||||
info!("pin {pin_nr} low");
|
let mut current_layer = CURRENT_LAYER.load(Ordering::Relaxed);
|
||||||
|
let layer_count = 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 }) = layers.get(usize::from(current_layer)) else {
|
||||||
|
error!("current layer was out of bounds for some reason ({current_layer})");
|
||||||
|
CURRENT_LAYER.store(0, Ordering::Relaxed);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(button) = buttons.get(switch_num) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
match button {
|
||||||
|
&Button::Key(key) => {
|
||||||
|
KB_REPORT.lock().await.press_key(key);
|
||||||
|
pin.wait_for_high().await;
|
||||||
|
KB_REPORT.lock().await.release_key(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Button::Mod(modifier) => {
|
||||||
|
// TODO
|
||||||
|
//KB_REPORT.lock().await.press_mod(modifier);
|
||||||
|
//pin.wait_for_high().await;
|
||||||
|
//KB_REPORT.lock().await.release_mod(modifier);
|
||||||
|
//continue;
|
||||||
|
}
|
||||||
|
Button::ModTap { keycode, modifier } => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
Button::NextLayer => {
|
||||||
|
let next_layer = (current_layer + 1) % layer_count;
|
||||||
|
CURRENT_LAYER.store(next_layer, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
Button::PrevLayer => {
|
||||||
|
let prev_layer = current_layer.checked_sub(1).unwrap_or(layer_count - 1);
|
||||||
|
CURRENT_LAYER.store(prev_layer, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
Button::None => {}
|
||||||
|
}
|
||||||
|
|
||||||
pin.wait_for_high().await;
|
pin.wait_for_high().await;
|
||||||
info!("pin {pin_nr} high");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl Button {
|
|
||||||
pub const fn key(keycode: u8) -> Self {
|
|
||||||
Button::Key { keycode }
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://usb.org/sites/default/files/hut1_3_0.pdf
|
|
||||||
pub const KEY_A: Button = Button::key(0x04);
|
|
||||||
pub const KEY_B: Button = Button::key(0x05);
|
|
||||||
pub const KEY_C: Button = Button::key(0x06);
|
|
||||||
pub const KEY_D: Button = Button::key(0x07);
|
|
||||||
pub const KEY_E: Button = Button::key(0x08);
|
|
||||||
pub const KEY_F: Button = Button::key(0x09);
|
|
||||||
pub const KEY_G: Button = Button::key(0x0A);
|
|
||||||
pub const KEY_H: Button = Button::key(0x0B);
|
|
||||||
pub const KEY_I: Button = Button::key(0x0C);
|
|
||||||
pub const KEY_J: Button = Button::key(0x0D);
|
|
||||||
pub const KEY_K: Button = Button::key(0x0E);
|
|
||||||
pub const KEY_L: Button = Button::key(0x0F);
|
|
||||||
pub const KEY_M: Button = Button::key(0x10);
|
|
||||||
pub const KEY_N: Button = Button::key(0x11);
|
|
||||||
pub const KEY_O: Button = Button::key(0x12);
|
|
||||||
pub const KEY_P: Button = Button::key(0x13);
|
|
||||||
pub const KEY_Q: Button = Button::key(0x14);
|
|
||||||
pub const KEY_R: Button = Button::key(0x15);
|
|
||||||
pub const KEY_S: Button = Button::key(0x16);
|
|
||||||
pub const KEY_T: Button = Button::key(0x17);
|
|
||||||
pub const KEY_U: Button = Button::key(0x18);
|
|
||||||
pub const KEY_V: Button = Button::key(0x19);
|
|
||||||
pub const KEY_W: Button = Button::key(0x1A);
|
|
||||||
pub const KEY_X: Button = Button::key(0x1B);
|
|
||||||
pub const KEY_Y: Button = Button::key(0x1C);
|
|
||||||
pub const KEY_Z: Button = Button::key(0x1D);
|
|
||||||
|
|
||||||
pub const KEY_1: Button = Button::key(0x1E);
|
|
||||||
pub const KEY_2: Button = Button::key(0x1F);
|
|
||||||
pub const KEY_3: Button = Button::key(0x20);
|
|
||||||
pub const KEY_4: Button = Button::key(0x21);
|
|
||||||
pub const KEY_5: Button = Button::key(0x22);
|
|
||||||
pub const KEY_6: Button = Button::key(0x23);
|
|
||||||
pub const KEY_7: Button = Button::key(0x24);
|
|
||||||
pub const KEY_8: Button = Button::key(0x25);
|
|
||||||
pub const KEY_9: Button = Button::key(0x26);
|
|
||||||
pub const KEY_0: Button = Button::key(0x27);
|
|
||||||
|
|
||||||
pub const KEY_SPACE: Button = Button::key(0x2C);
|
|
||||||
pub const KEY_RETURN: Button = Button::key(0x28);
|
|
||||||
|
|
||||||
pub const KEY_LCTRL: Button = Button::key(0xE0);
|
|
||||||
pub const KEY_RCTRL: Button = Button::key(0xE4);
|
|
||||||
|
|
||||||
pub const KEY_LSHIFT: Button = Button::key(0xE1);
|
|
||||||
pub const KEY_RSHIFT: Button = Button::key(0xE5);
|
|
||||||
|
|
||||||
pub const KEY_LALT: Button = Button::key(0xE2);
|
|
||||||
pub const KEY_RALT: Button = Button::key(0xE6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Random functions for testing
|
/// Random functions for testing
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use tgnt::{button::Button, keys::Key};
|
||||||
|
|
||||||
pub fn letter_to_key(c: char) -> Option<Button> {
|
pub fn letter_to_key(c: char) -> Button {
|
||||||
if !c.is_ascii() {
|
if !c.is_ascii() {
|
||||||
return None;
|
return Button::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let c = c.to_ascii_uppercase();
|
let c = c.to_ascii_uppercase();
|
||||||
|
|
||||||
let key = match c {
|
let key = match c {
|
||||||
'A' => Button::KEY_A,
|
'A' => Key::A,
|
||||||
'B' => Button::KEY_B,
|
'B' => Key::B,
|
||||||
'C' => Button::KEY_C,
|
'C' => Key::C,
|
||||||
'D' => Button::KEY_D,
|
'D' => Key::D,
|
||||||
'E' => Button::KEY_E,
|
'E' => Key::E,
|
||||||
'F' => Button::KEY_F,
|
'F' => Key::F,
|
||||||
'G' => Button::KEY_G,
|
'G' => Key::G,
|
||||||
'H' => Button::KEY_H,
|
'H' => Key::H,
|
||||||
'I' => Button::KEY_I,
|
'I' => Key::I,
|
||||||
'J' => Button::KEY_J,
|
'J' => Key::J,
|
||||||
'K' => Button::KEY_K,
|
'K' => Key::K,
|
||||||
'L' => Button::KEY_L,
|
'L' => Key::L,
|
||||||
'M' => Button::KEY_M,
|
'M' => Key::M,
|
||||||
'N' => Button::KEY_N,
|
'N' => Key::N,
|
||||||
'O' => Button::KEY_O,
|
'O' => Key::O,
|
||||||
'P' => Button::KEY_P,
|
'P' => Key::P,
|
||||||
'Q' => Button::KEY_Q,
|
'Q' => Key::Q,
|
||||||
'R' => Button::KEY_R,
|
'R' => Key::R,
|
||||||
'S' => Button::KEY_S,
|
'S' => Key::S,
|
||||||
'T' => Button::KEY_T,
|
'T' => Key::T,
|
||||||
'U' => Button::KEY_U,
|
'U' => Key::U,
|
||||||
'V' => Button::KEY_V,
|
'V' => Key::V,
|
||||||
'W' => Button::KEY_W,
|
'W' => Key::W,
|
||||||
'X' => Button::KEY_X,
|
'X' => Key::X,
|
||||||
'Y' => Button::KEY_Y,
|
'Y' => Key::Y,
|
||||||
'Z' => Button::KEY_Z,
|
'Z' => Key::Z,
|
||||||
' ' => Button::KEY_SPACE,
|
' ' => Key::Space,
|
||||||
'\n' => Button::KEY_RETURN,
|
'\n' => Key::Return,
|
||||||
_ => {
|
_ => {
|
||||||
log::info!("char {c:?} -> None");
|
log::info!("char {c:?} -> None");
|
||||||
return None;
|
return Button::None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("char {c:?} -> {key:?}");
|
log::info!("char {c:?} -> {key:?}");
|
||||||
|
|
||||||
Some(key)
|
Button::Key(key)
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn type_string(s: &str) {
|
|
||||||
log::info!("typing {s:?}");
|
|
||||||
|
|
||||||
for c in s.chars() {
|
|
||||||
let Some(key) = letter_to_key(c) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
for col in 0..COLS {
|
|
||||||
for row in 0..ROWS {
|
|
||||||
if TEST_KEYMAP[row][col] == key {
|
|
||||||
MATRIX[row][col].press();
|
|
||||||
Timer::after(Duration::from_millis(20)).await;
|
|
||||||
MATRIX[row][col].release();
|
|
||||||
Timer::after(Duration::from_millis(5)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Press all keys at once
|
|
||||||
pub async fn rollover<const N: usize>(letters: [char; N]) {
|
|
||||||
log::info!("pressing all letters in {letters:?}");
|
|
||||||
|
|
||||||
let keys = letters.map(letter_to_key);
|
|
||||||
|
|
||||||
for key in &keys {
|
|
||||||
for col in 0..COLS {
|
|
||||||
for row in 0..ROWS {
|
|
||||||
if Some(&TEST_KEYMAP[row][col]) == key.as_ref() {
|
|
||||||
MATRIX[row][col].press();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(200)).await;
|
|
||||||
|
|
||||||
for key in &keys {
|
|
||||||
for col in 0..COLS {
|
|
||||||
for row in 0..ROWS {
|
|
||||||
if Some(&TEST_KEYMAP[row][col]) == key.as_ref() {
|
|
||||||
MATRIX[row][col].release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/main.rs
71
src/main.rs
@ -10,23 +10,32 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
|
||||||
|
mod allocator;
|
||||||
mod board;
|
mod board;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod neopixel;
|
mod neopixel;
|
||||||
mod panic_handler;
|
mod panic_handler;
|
||||||
mod usb;
|
mod usb;
|
||||||
|
mod util;
|
||||||
mod ws2812;
|
mod ws2812;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
use board::Board;
|
use board::Board;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::gpio::{Level, Output, Pin};
|
use embassy_rp::gpio::{Level, Output, Pin};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use tgnt::layer::Layer;
|
||||||
use ws2812::Rgb;
|
use ws2812::Rgb;
|
||||||
|
|
||||||
|
use crate::keyboard::KeyboardConfig;
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
|
allocator::init();
|
||||||
|
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
let board = Board {
|
let board = Board {
|
||||||
@ -85,27 +94,42 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
Timer::after(Duration::from_millis(3000)).await;
|
Timer::after(Duration::from_millis(3000)).await;
|
||||||
|
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.a0.degrade()));
|
let layers = include_bytes!("layers.pc");
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.a1.degrade()));
|
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.a2.degrade()));
|
log::error!("Failed to deserialize layer config");
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.a3.degrade()));
|
loop_forever().await
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d2.degrade()));
|
};
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d3.degrade()));
|
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d4.degrade()));
|
let keyboard = KeyboardConfig {
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d7.degrade()));
|
layers,
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d9.degrade()));
|
pins: [
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d10.degrade()));
|
// row 1
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d11.degrade()));
|
board.d24.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d12.degrade()));
|
board.a3.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d24.degrade()));
|
board.a2.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.d25.degrade()));
|
board.a1.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.scl.degrade()));
|
board.a0.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.sda.degrade()));
|
// row 2
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.mosi.degrade()));
|
board.d25.degrade(),
|
||||||
spawner.must_spawn(keyboard::monitor_switch(board.miso.degrade()));
|
board.sck.degrade(),
|
||||||
|
board.mosi.degrade(),
|
||||||
|
board.miso.degrade(),
|
||||||
|
board.d2.degrade(),
|
||||||
|
// row 3
|
||||||
|
board.d12.degrade(),
|
||||||
|
board.d11.degrade(),
|
||||||
|
board.d10.degrade(),
|
||||||
|
board.d9.degrade(),
|
||||||
|
board.d3.degrade(),
|
||||||
|
// thumbpad
|
||||||
|
board.d7.degrade(),
|
||||||
|
board.scl.degrade(),
|
||||||
|
board.sda.degrade(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
keyboard.create().await;
|
||||||
|
|
||||||
//keyboard::test::type_string("Hello there!\n").await;
|
|
||||||
//keyboard::test::rollover(['h', 'e', 'l', 'o', 't', 'r', 'a', 'b', 'c', 'd', 'i']).await;
|
|
||||||
for w in 0usize.. {
|
for w in 0usize.. {
|
||||||
neopixel.write(&[wheel(w as u8)]).await;
|
neopixel.write(&[wheel(w as u8)]).await;
|
||||||
neopixels_d5
|
neopixels_d5
|
||||||
@ -117,7 +141,12 @@ async fn main(spawner: Spawner) {
|
|||||||
])
|
])
|
||||||
.await;
|
.await;
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
//Timer::after(Duration::from_secs(10)).await;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn loop_forever() -> ! {
|
||||||
|
loop {
|
||||||
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ pub mod report;
|
|||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::{peripherals::USB, usb::Driver};
|
use embassy_rp::{peripherals::USB, usb::Driver};
|
||||||
|
use embassy_sync::mutex::Mutex;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embassy_usb::{
|
use embassy_usb::{
|
||||||
class::hid::{self, HidReaderWriter, ReadError, ReportId, RequestHandler},
|
class::hid::{self, HidReaderWriter, ReadError, ReportId, RequestHandler},
|
||||||
@ -13,8 +14,8 @@ use static_cell::StaticCell;
|
|||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
keyboard::{Button, COLS, MATRIX, ROWS, TEST_KEYMAP},
|
|
||||||
usb::keyboard::report::{KeyboardReport, EMPTY_KEYBOARD_REPORT},
|
usb::keyboard::report::{KeyboardReport, EMPTY_KEYBOARD_REPORT},
|
||||||
|
util::CS,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::MAX_PACKET_SIZE;
|
use super::MAX_PACKET_SIZE;
|
||||||
@ -23,6 +24,8 @@ struct Handler;
|
|||||||
|
|
||||||
static CONTEXT: StaticCell<Context> = StaticCell::new();
|
static CONTEXT: StaticCell<Context> = StaticCell::new();
|
||||||
|
|
||||||
|
pub static KB_REPORT: Mutex<CS, KeyboardReport> = Mutex::new(EMPTY_KEYBOARD_REPORT);
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
state: hid::State<'static>,
|
state: hid::State<'static>,
|
||||||
@ -94,36 +97,7 @@ async fn keyboard_test(mut stream: HidStream, _handler: &'static Handler) -> Res
|
|||||||
loop {
|
loop {
|
||||||
Timer::after(Duration::from_millis(2)).await;
|
Timer::after(Duration::from_millis(2)).await;
|
||||||
|
|
||||||
let keymap = &TEST_KEYMAP;
|
let report = KB_REPORT.lock().await.clone();
|
||||||
|
|
||||||
let mut report = EMPTY_KEYBOARD_REPORT;
|
|
||||||
#[cfg(not(feature = "n-key-rollover"))]
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
#[allow(unused_labels)]
|
|
||||||
'keyscan: for col in 0..COLS {
|
|
||||||
for row in 0..ROWS {
|
|
||||||
if !MATRIX[row][col].is_pressed() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let &Button::Key { keycode } = &keymap[row][col];
|
|
||||||
// else { continue; };
|
|
||||||
|
|
||||||
#[cfg(feature = "n-key-rollover")]
|
|
||||||
report.set_key(keycode);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "n-key-rollover"))]
|
|
||||||
{
|
|
||||||
report.keycodes[i] = keycode;
|
|
||||||
i += 1;
|
|
||||||
if i >= report.keycodes.len() {
|
|
||||||
break 'keyscan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if report.keycodes != EMPTY_KEYBOARD_REPORT.keycodes {
|
if report.keycodes != EMPTY_KEYBOARD_REPORT.keycodes {
|
||||||
log::debug!("keys: {:x?}", report.keycodes);
|
log::debug!("keys: {:x?}", report.keycodes);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
/// keyboard LEDs.
|
/// keyboard LEDs.
|
||||||
///
|
///
|
||||||
/// Unlike usbd_hids KeyboardReport, this one supports N-key rollover.
|
/// Unlike usbd_hids KeyboardReport, this one supports N-key rollover.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
#[cfg(feature = "n-key-rollover")]
|
#[cfg(feature = "n-key-rollover")]
|
||||||
pub struct KeyboardReport {
|
pub struct KeyboardReport {
|
||||||
pub modifier: u8,
|
pub modifier: u8,
|
||||||
@ -14,6 +14,7 @@ pub struct KeyboardReport {
|
|||||||
pub keycodes: [u8; 13],
|
pub keycodes: [u8; 13],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use tgnt::keys::Key;
|
||||||
#[cfg(not(feature = "n-key-rollover"))]
|
#[cfg(not(feature = "n-key-rollover"))]
|
||||||
pub use usbd_hid::descriptor::KeyboardReport;
|
pub use usbd_hid::descriptor::KeyboardReport;
|
||||||
|
|
||||||
@ -33,19 +34,32 @@ pub const EMPTY_KEYBOARD_REPORT: KeyboardReport = KeyboardReport {
|
|||||||
|
|
||||||
#[cfg(feature = "n-key-rollover")]
|
#[cfg(feature = "n-key-rollover")]
|
||||||
impl KeyboardReport {
|
impl KeyboardReport {
|
||||||
pub fn set_key(&mut self, keycode: u8) {
|
pub fn set_key(&mut self, key: Key, pressed: bool) {
|
||||||
log::info!("setting keycode: {keycode}");
|
let keycode = u8::from(key);
|
||||||
|
log::debug!("setting key: {key:?} ({keycode:x})");
|
||||||
let byte = keycode >> 3;
|
let byte = keycode >> 3;
|
||||||
let bit = keycode & 0b111;
|
let bit = keycode & 0b111;
|
||||||
let mask = 1 << bit;
|
let mask = 1 << bit;
|
||||||
|
|
||||||
if let Some(k) = self.keycodes.get_mut(byte as usize) {
|
if let Some(k) = self.keycodes.get_mut(byte as usize) {
|
||||||
*k |= mask;
|
if pressed {
|
||||||
|
*k |= mask;
|
||||||
|
} else {
|
||||||
|
*k &= !mask;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Tried to set out-of-range keycode: {keycode:x}");
|
log::warn!("Tried to set out-of-range keycode: {keycode:x}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn press_key(&mut self, key: Key) {
|
||||||
|
self.set_key(key, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release_key(&mut self, key: Key) {
|
||||||
|
self.set_key(key, false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serialized(&self) -> [u8; 14] {
|
pub fn serialized(&self) -> [u8; 14] {
|
||||||
let [a, b, c, d, e, f, g, h, i, j, k, l, m] = self.keycodes;
|
let [a, b, c, d, e, f, g, h, i, j, k, l, m] = self.keycodes;
|
||||||
[self.modifier, a, b, c, d, e, f, g, h, i, j, k, l, m]
|
[self.modifier, a, b, c, d, e, f, g, h, i, j, k, l, m]
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
use crate::util::CS;
|
||||||
|
|
||||||
use super::MAX_PACKET_SIZE;
|
use super::MAX_PACKET_SIZE;
|
||||||
use core::fmt::Write as WriteFmt;
|
use core::fmt::Write as WriteFmt;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::{peripherals::USB, usb::Driver};
|
use embassy_rp::{peripherals::USB, usb::Driver};
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe};
|
use embassy_sync::pipe::Pipe;
|
||||||
use embassy_time::Instant;
|
use embassy_time::Instant;
|
||||||
use embassy_usb::{
|
use embassy_usb::{
|
||||||
class::cdc_acm::{self, CdcAcmClass},
|
class::cdc_acm::{self, CdcAcmClass},
|
||||||
@ -12,7 +14,7 @@ use log::{Metadata, Record};
|
|||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
pub const BUFFER_SIZE: usize = 16 * 1024;
|
pub const BUFFER_SIZE: usize = 16 * 1024;
|
||||||
static BUFFER: Pipe<CriticalSectionRawMutex, BUFFER_SIZE> = Pipe::new();
|
static BUFFER: Pipe<CS, BUFFER_SIZE> = Pipe::new();
|
||||||
static STATE: StaticCell<cdc_acm::State<'static>> = StaticCell::new();
|
static STATE: StaticCell<cdc_acm::State<'static>> = StaticCell::new();
|
||||||
|
|
||||||
struct UsbLogger;
|
struct UsbLogger;
|
||||||
@ -62,7 +64,7 @@ impl log::Log for UsbLogger {
|
|||||||
let s = now.as_secs();
|
let s = now.as_secs();
|
||||||
let ms = now.as_millis() % 1000;
|
let ms = now.as_millis() % 1000;
|
||||||
let level = record.metadata().level();
|
let level = record.metadata().level();
|
||||||
let _ = write!(w, "[{s}.{ms:04}] ({level}) {}\n", record.args());
|
let _ = writeln!(w, "[{s}.{ms:04}] ({level}) {}", record.args());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
src/util.rs
Normal file
3
src/util.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
|
||||||
|
pub type CS = CriticalSectionRawMutex;
|
||||||
Reference in New Issue
Block a user