Add communication between keyboard halves
This commit is contained in:
@ -31,6 +31,9 @@ smart-leds = "0.3.0"
|
|||||||
embedded-alloc = "0.5.0"
|
embedded-alloc = "0.5.0"
|
||||||
postcard = { version = "1.0.4", features = ["alloc"] }
|
postcard = { version = "1.0.4", features = ["alloc"] }
|
||||||
|
|
||||||
|
#[patch."https://git.nubo.sh/hulthe/tgnt.git"]
|
||||||
|
#tgnt = { path = "../tgnt" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
|
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
|
||||||
ron = "0.8.0"
|
ron = "0.8.0"
|
||||||
|
|||||||
@ -11,15 +11,18 @@ use alloc::vec::Vec;
|
|||||||
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 log::error;
|
||||||
use tangentbord1::board::Board;
|
use tangentbord1::board::Board;
|
||||||
use tangentbord1::keyboard::KeyboardConfig;
|
use tangentbord1::keyboard::{Half, KeyboardConfig};
|
||||||
use tangentbord1::util::{stall, wheel};
|
use tangentbord1::util::{stall, wheel};
|
||||||
use tangentbord1::ws2812::{Rgb, Ws2812};
|
use tangentbord1::ws2812::{Rgb, Ws2812};
|
||||||
use tangentbord1::{allocator, usb};
|
use tangentbord1::{allocator, uart, usb};
|
||||||
use tgnt::layer::Layer;
|
use tgnt::layer::Layer;
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
|
let half = Half::Left;
|
||||||
|
|
||||||
allocator::init();
|
allocator::init();
|
||||||
|
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
@ -32,10 +35,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
||||||
|
|
||||||
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
||||||
usb::setup_logger_and_keyboard(board.USB).await;
|
|
||||||
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
|
||||||
|
|
||||||
//Timer::after(Duration::from_millis(3000)).await;
|
|
||||||
|
|
||||||
let layers = include_bytes!("layers-left.pc");
|
let layers = include_bytes!("layers-left.pc");
|
||||||
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
||||||
@ -44,6 +43,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let keyboard = KeyboardConfig {
|
let keyboard = KeyboardConfig {
|
||||||
|
half,
|
||||||
pins: [
|
pins: [
|
||||||
// row 1
|
// row 1
|
||||||
board.d24.degrade(),
|
board.d24.degrade(),
|
||||||
@ -75,7 +75,17 @@ async fn main(_spawner: Spawner) {
|
|||||||
layers,
|
layers,
|
||||||
};
|
};
|
||||||
|
|
||||||
keyboard.create().await;
|
let Some([events1, events2]) = keyboard.create().await else {
|
||||||
|
error!("failed to create keyboard");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart::start(board.tx, board.rx, board.UART0, half, events2).await;
|
||||||
|
|
||||||
|
neopixel.write(&[Rgb::new(0x00, 0x99, 0x99)]).await;
|
||||||
|
|
||||||
|
usb::setup_logger_and_keyboard(board.USB, events1).await;
|
||||||
|
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
||||||
|
|
||||||
for w in 0usize.. {
|
for w in 0usize.. {
|
||||||
neopixel.write(&[wheel(w as u8)]).await;
|
neopixel.write(&[wheel(w as u8)]).await;
|
||||||
|
|||||||
@ -11,15 +11,18 @@ use alloc::vec::Vec;
|
|||||||
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 log::error;
|
||||||
use tangentbord1::board::Board;
|
use tangentbord1::board::Board;
|
||||||
use tangentbord1::keyboard::KeyboardConfig;
|
use tangentbord1::keyboard::{Half, KeyboardConfig};
|
||||||
use tangentbord1::util::{stall, wheel};
|
use tangentbord1::util::{stall, wheel};
|
||||||
use tangentbord1::ws2812::{Rgb, Ws2812};
|
use tangentbord1::ws2812::{Rgb, Ws2812};
|
||||||
use tangentbord1::{allocator, usb};
|
use tangentbord1::{allocator, uart, usb};
|
||||||
use tgnt::layer::Layer;
|
use tgnt::layer::Layer;
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
|
let half = Half::Right;
|
||||||
|
|
||||||
allocator::init();
|
allocator::init();
|
||||||
|
|
||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
@ -32,8 +35,6 @@ async fn main(_spawner: Spawner) {
|
|||||||
let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
||||||
|
|
||||||
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
||||||
usb::setup_logger_and_keyboard(board.USB).await;
|
|
||||||
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
|
||||||
|
|
||||||
//Timer::after(Duration::from_millis(3000)).await;
|
//Timer::after(Duration::from_millis(3000)).await;
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let keyboard = KeyboardConfig {
|
let keyboard = KeyboardConfig {
|
||||||
|
half,
|
||||||
pins: [
|
pins: [
|
||||||
// TODO: reconfigure these for right PCB
|
// TODO: reconfigure these for right PCB
|
||||||
// row 1
|
// row 1
|
||||||
@ -74,7 +76,15 @@ async fn main(_spawner: Spawner) {
|
|||||||
layers,
|
layers,
|
||||||
};
|
};
|
||||||
|
|
||||||
keyboard.create().await;
|
let Some([events1, events2]) = keyboard.create().await else {
|
||||||
|
error!("failed to create keyboard");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart::start(board.tx, board.rx, board.UART0, half, events2).await;
|
||||||
|
|
||||||
|
usb::setup_logger_and_keyboard(board.USB, events1).await;
|
||||||
|
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
||||||
|
|
||||||
for w in 0usize.. {
|
for w in 0usize.. {
|
||||||
neopixel.write(&[wheel(w as u8)]).await;
|
neopixel.write(&[wheel(w as u8)]).await;
|
||||||
|
|||||||
141
src/keyboard.rs
141
src/keyboard.rs
@ -6,19 +6,26 @@ use embassy_rp::{
|
|||||||
gpio::{AnyPin, Input, Pin, Pull},
|
gpio::{AnyPin, Input, Pin, Pull},
|
||||||
pio::PioInstanceBase,
|
pio::PioInstanceBase,
|
||||||
};
|
};
|
||||||
|
use embassy_sync::pubsub::{ImmediatePublisher, PubSubChannel, Subscriber};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use futures::{select_biased, FutureExt};
|
use futures::{select_biased, FutureExt};
|
||||||
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, Modifier},
|
||||||
|
keys::Key,
|
||||||
|
layer::Layer,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lights::Lights,
|
lights::Lights,
|
||||||
usb::keyboard::KB_REPORT,
|
util::CS,
|
||||||
ws2812::{Rgb, Ws2812},
|
ws2812::{Rgb, Ws2812},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct KeyboardConfig {
|
pub struct KeyboardConfig {
|
||||||
|
/// Which board is this.
|
||||||
|
pub half: Half,
|
||||||
/// Array of input pins of each switch
|
/// Array of input pins of each switch
|
||||||
pub pins: [AnyPin; SWITCH_COUNT],
|
pub pins: [AnyPin; SWITCH_COUNT],
|
||||||
/// Array of LED indices of each switch
|
/// Array of LED indices of each switch
|
||||||
@ -28,6 +35,8 @@ pub struct KeyboardConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
/// Which board is this.
|
||||||
|
half: Half,
|
||||||
current_layer: AtomicU16,
|
current_layer: AtomicU16,
|
||||||
layers: &'static [Layer],
|
layers: &'static [Layer],
|
||||||
/// Array of LED indices of each switch
|
/// Array of LED indices of each switch
|
||||||
@ -35,13 +44,54 @@ struct State {
|
|||||||
lights: Lights<PioInstanceBase<1>, SWITCH_COUNT>,
|
lights: Lights<PioInstanceBase<1>, SWITCH_COUNT>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A keyboard half.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Half {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Event {
|
||||||
|
pub source: Half,
|
||||||
|
pub kind: EventKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum EventKind {
|
||||||
|
PressKey(Key),
|
||||||
|
ReleaseKey(Key),
|
||||||
|
PressModifier(Modifier),
|
||||||
|
ReleaseModifier(Modifier),
|
||||||
|
SetLayer(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const KB_SUBSCRIBERS: usize = 2;
|
||||||
|
pub const ACTUAL_KB_SUBSCRIBERS: usize = KB_SUBSCRIBERS + 1;
|
||||||
|
const KB_EVENT_CAP: usize = 128;
|
||||||
|
static KB_EVENTS: PubSubChannel<CS, Event, KB_EVENT_CAP, ACTUAL_KB_SUBSCRIBERS, 0> =
|
||||||
|
PubSubChannel::new();
|
||||||
|
pub struct KbEvents {
|
||||||
|
subscriber: Subscriber<'static, CS, Event, KB_EVENT_CAP, ACTUAL_KB_SUBSCRIBERS, 0>,
|
||||||
|
publisher: ImmediatePublisher<'static, CS, Event, KB_EVENT_CAP, ACTUAL_KB_SUBSCRIBERS, 0>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KbEventsTx<'a> {
|
||||||
|
publisher:
|
||||||
|
&'a mut ImmediatePublisher<'static, CS, Event, KB_EVENT_CAP, ACTUAL_KB_SUBSCRIBERS, 0>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KbEventsRx<'a> {
|
||||||
|
subscriber: &'a mut Subscriber<'static, CS, Event, KB_EVENT_CAP, ACTUAL_KB_SUBSCRIBERS, 0>,
|
||||||
|
}
|
||||||
|
|
||||||
impl KeyboardConfig {
|
impl KeyboardConfig {
|
||||||
pub async fn create(self) {
|
pub async fn create(self) -> Option<[KbEvents; KB_SUBSCRIBERS]> {
|
||||||
let spawner = Spawner::for_current_executor().await;
|
let spawner = Spawner::for_current_executor().await;
|
||||||
|
|
||||||
if self.layers.is_empty() {
|
if self.layers.is_empty() {
|
||||||
error!("no layers defined");
|
error!("no layers defined");
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
@ -51,6 +101,7 @@ 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,
|
||||||
current_layer: AtomicU16::new(0),
|
current_layer: AtomicU16::new(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),
|
||||||
@ -72,6 +123,51 @@ impl KeyboardConfig {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spawner.must_spawn(layer_switch_task(
|
||||||
|
KbEvents {
|
||||||
|
publisher: KB_EVENTS.immediate_publisher(),
|
||||||
|
subscriber: KB_EVENTS.subscriber().unwrap(),
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
));
|
||||||
|
|
||||||
|
Some([(); KB_SUBSCRIBERS].map(|_| KbEvents {
|
||||||
|
publisher: KB_EVENTS.immediate_publisher(),
|
||||||
|
subscriber: KB_EVENTS.subscriber().unwrap(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KbEvents {
|
||||||
|
pub async fn send(&mut self, event: Event) {
|
||||||
|
self.publisher.publish_immediate(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn recv(&mut self) -> Event {
|
||||||
|
self.subscriber.next_message_pure().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(&mut self) -> (KbEventsRx, KbEventsTx) {
|
||||||
|
let tx = KbEventsTx {
|
||||||
|
publisher: &mut self.publisher,
|
||||||
|
};
|
||||||
|
let rx = KbEventsRx {
|
||||||
|
subscriber: &mut self.subscriber,
|
||||||
|
};
|
||||||
|
(rx, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KbEventsRx<'_> {
|
||||||
|
pub async fn recv(&mut self) -> Event {
|
||||||
|
self.subscriber.next_message_pure().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KbEventsTx<'_> {
|
||||||
|
pub fn send(&mut self, event: Event) {
|
||||||
|
self.publisher.publish_immediate(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +179,7 @@ const SWITCH_COUNT: usize = 18;
|
|||||||
async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! {
|
async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> ! {
|
||||||
let _pin_nr = pin.pin();
|
let _pin_nr = pin.pin();
|
||||||
let mut pin = Input::new(pin, Pull::Up);
|
let mut pin = Input::new(pin, Pull::Up);
|
||||||
|
let events = KB_EVENTS.immediate_publisher();
|
||||||
loop {
|
loop {
|
||||||
// pins are pull-up, so when the switch is pressed they are brought low.
|
// pins are pull-up, so when the switch is pressed they are brought low.
|
||||||
pin.wait_for_low().await;
|
pin.wait_for_low().await;
|
||||||
@ -124,20 +221,26 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ev = |kind| Event {
|
||||||
|
source: state.half,
|
||||||
|
kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
use EventKind::*;
|
||||||
match button {
|
match button {
|
||||||
&Button::Key(key) => {
|
&Button::Key(key) => {
|
||||||
KB_REPORT.lock().await.press_key(key);
|
events.publish_immediate(ev(PressKey(key)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
|
||||||
wait_for_release.await;
|
wait_for_release.await;
|
||||||
KB_REPORT.lock().await.release_key(key);
|
events.publish_immediate(ev(ReleaseKey(key)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
&Button::Mod(modifier) => {
|
&Button::Mod(modifier) => {
|
||||||
KB_REPORT.lock().await.press_modifier(modifier);
|
events.publish_immediate(ev(PressModifier(modifier)));
|
||||||
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
|
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
|
||||||
wait_for_release.await;
|
wait_for_release.await;
|
||||||
KB_REPORT.lock().await.release_modifier(modifier);
|
events.publish_immediate(ev(ReleaseModifier(modifier)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -145,19 +248,19 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
|
|||||||
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
|
state.lights.update(set_led(Rgb::new(100, 100, 0))).await;
|
||||||
select_biased! {
|
select_biased! {
|
||||||
_ = Timer::after(MOD_TAP_TIME).fuse() => {
|
_ = Timer::after(MOD_TAP_TIME).fuse() => {
|
||||||
KB_REPORT.lock().await.press_modifier(modifier);
|
events.publish_immediate(ev(PressModifier(modifier)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 0, 150))).await;
|
state.lights.update(set_led(Rgb::new(0, 0, 150))).await;
|
||||||
pin.wait_for_high().await;
|
pin.wait_for_high().await;
|
||||||
KB_REPORT.lock().await.release_modifier(modifier);
|
events.publish_immediate(ev(ReleaseModifier(modifier)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
||||||
debug!("switch {switch_num} button {button:?} released");
|
debug!("switch {switch_num} button {button:?} released");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_ = wait_for_release.fuse() => {
|
_ = wait_for_release.fuse() => {
|
||||||
KB_REPORT.lock().await.press_key(key);
|
events.publish_immediate(ev(PressKey(key)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 150, 0))).await;
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
KB_REPORT.lock().await.release_key(key);
|
events.publish_immediate(ev(ReleaseKey(key)));
|
||||||
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
state.lights.update(set_led(Rgb::new(0, 0, 0))).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -165,12 +268,12 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
|
|||||||
}
|
}
|
||||||
Button::NextLayer => {
|
Button::NextLayer => {
|
||||||
let next_layer = (current_layer + 1) % layer_count;
|
let next_layer = (current_layer + 1) % layer_count;
|
||||||
state.current_layer.store(next_layer, Ordering::Relaxed);
|
events.publish_immediate(ev(SetLayer(next_layer)));
|
||||||
debug!("switched to layer {next_layer}");
|
debug!("switched to layer {next_layer}");
|
||||||
}
|
}
|
||||||
Button::PrevLayer => {
|
Button::PrevLayer => {
|
||||||
let prev_layer = current_layer.checked_sub(1).unwrap_or(layer_count - 1);
|
let prev_layer = current_layer.checked_sub(1).unwrap_or(layer_count - 1);
|
||||||
state.current_layer.store(prev_layer, Ordering::Relaxed);
|
events.publish_immediate(ev(SetLayer(prev_layer)));
|
||||||
debug!("switched to layer {prev_layer}");
|
debug!("switched to layer {prev_layer}");
|
||||||
}
|
}
|
||||||
Button::None => {}
|
Button::None => {}
|
||||||
@ -181,6 +284,16 @@ 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) {
|
||||||
|
loop {
|
||||||
|
let event = events.recv().await;
|
||||||
|
if let EventKind::SetLayer(new_layer) = event.kind {
|
||||||
|
state.current_layer.store(new_layer, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Random functions for testing
|
/// Random functions for testing
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub mod keyboard;
|
|||||||
pub mod lights;
|
pub mod lights;
|
||||||
pub mod neopixel;
|
pub mod neopixel;
|
||||||
pub mod panic_handler;
|
pub mod panic_handler;
|
||||||
|
pub mod uart;
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod ws2812;
|
pub mod ws2812;
|
||||||
|
|||||||
88
src/uart.rs
Normal file
88
src/uart.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use core::mem::{size_of, transmute};
|
||||||
|
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::interrupt;
|
||||||
|
use embassy_rp::peripherals::{PIN_0, PIN_1, UART0};
|
||||||
|
use embassy_rp::uart::{self, BufferedUart, DataBits, Parity, StopBits};
|
||||||
|
use embassy_time::{with_timeout, Duration, TimeoutError};
|
||||||
|
use embedded_io::asynch::{Read, Write};
|
||||||
|
use futures::{select_biased, FutureExt};
|
||||||
|
use log::{error, info};
|
||||||
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
|
use crate::keyboard::{self, Half, KbEvents};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum Message {
|
||||||
|
KeyboardEvent(keyboard::Event),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start(tx: PIN_0, rx: PIN_1, uart: UART0, board: Half, events: KbEvents) {
|
||||||
|
static TX_BUF: StaticCell<[u8; 1024]> = StaticCell::new();
|
||||||
|
static RX_BUF: StaticCell<[u8; 1024]> = StaticCell::new();
|
||||||
|
|
||||||
|
let mut config = uart::Config::default();
|
||||||
|
config.baudrate = 115200;
|
||||||
|
config.data_bits = DataBits::DataBits8;
|
||||||
|
config.stop_bits = StopBits::STOP1;
|
||||||
|
config.parity = Parity::ParityNone;
|
||||||
|
|
||||||
|
let uart = embassy_rp::uart::BufferedUart::new(
|
||||||
|
uart,
|
||||||
|
interrupt::take!(UART0_IRQ),
|
||||||
|
tx,
|
||||||
|
rx,
|
||||||
|
TX_BUF.init_with(|| [0u8; 1024]),
|
||||||
|
RX_BUF.init_with(|| [0u8; 1024]),
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
|
||||||
|
Spawner::for_current_executor()
|
||||||
|
.await
|
||||||
|
.must_spawn(uart_task(uart, board, events))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn uart_task(uart: BufferedUart<'static, UART0>, this_half: Half, mut events: KbEvents) {
|
||||||
|
let (mut rx, mut tx) = uart.split();
|
||||||
|
let (mut events_rx, mut events_tx) = events.split();
|
||||||
|
|
||||||
|
let rx_task = async {
|
||||||
|
loop {
|
||||||
|
let mut buf = [0u8; size_of::<Message>()];
|
||||||
|
// TODO: this timout thing seems sketchy
|
||||||
|
match with_timeout(Duration::from_millis(5), rx.read_exact(&mut buf)).await {
|
||||||
|
Ok(Ok(_)) => {}
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
error!("uart error: {:?}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(TimeoutError) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let message: Message = unsafe { transmute(buf) }; // crimes :)
|
||||||
|
info!("got msg: {:?}", message);
|
||||||
|
match message {
|
||||||
|
Message::KeyboardEvent(event) => events_tx.send(event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tx_task = async {
|
||||||
|
loop {
|
||||||
|
// forward messages to the other keyboard half
|
||||||
|
let event = events_rx.recv().await;
|
||||||
|
if event.source != this_half {
|
||||||
|
continue; // do not forward messages from the other half back to it
|
||||||
|
}
|
||||||
|
let message = Message::KeyboardEvent(event);
|
||||||
|
let message: [u8; size_of::<Message>()] = unsafe { transmute(message) }; // crimes :)
|
||||||
|
tx.write_all(&message).await.ok();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
select_biased! {
|
||||||
|
_ = tx_task.fuse() => error!("uart tx_task exited"),
|
||||||
|
_ = rx_task.fuse() => error!("eart rx_task exited"),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,8 @@ use embassy_rp::{interrupt, peripherals::USB, usb::Driver};
|
|||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
|
use crate::keyboard::KbEvents;
|
||||||
|
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ struct State {
|
|||||||
|
|
||||||
static STATE: StaticCell<State> = StaticCell::new();
|
static STATE: StaticCell<State> = StaticCell::new();
|
||||||
|
|
||||||
pub async fn setup_logger_and_keyboard(usb: USB) {
|
pub async fn setup_logger_and_keyboard(usb: USB, events: KbEvents) {
|
||||||
let mut builder = builder(usb);
|
let mut builder = builder(usb);
|
||||||
logger::setup(&mut builder).await;
|
logger::setup(&mut builder).await;
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ pub async fn setup_logger_and_keyboard(usb: USB) {
|
|||||||
log::debug!("log_level: debug");
|
log::debug!("log_level: debug");
|
||||||
log::trace!("log_level: trace");
|
log::trace!("log_level: trace");
|
||||||
|
|
||||||
keyboard::setup(&mut builder).await;
|
keyboard::setup(&mut builder, events).await;
|
||||||
let usb = builder.build();
|
let usb = builder.build();
|
||||||
Spawner::for_current_executor().await.must_spawn(run(usb));
|
Spawner::for_current_executor().await.must_spawn(run(usb));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use static_cell::StaticCell;
|
|||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
keyboard::{Event, EventKind, KbEvents},
|
||||||
usb::keyboard::report::{KeyboardReport, EMPTY_KEYBOARD_REPORT},
|
usb::keyboard::report::{KeyboardReport, EMPTY_KEYBOARD_REPORT},
|
||||||
util::CS,
|
util::CS,
|
||||||
};
|
};
|
||||||
@ -31,7 +32,7 @@ struct Context {
|
|||||||
state: hid::State<'static>,
|
state: hid::State<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn setup(builder: &mut Builder<'static, Driver<'static, USB>>) {
|
pub async fn setup(builder: &mut Builder<'static, Driver<'static, USB>>, events: KbEvents) {
|
||||||
log::info!("setting up usb hid");
|
log::info!("setting up usb hid");
|
||||||
|
|
||||||
let context = CONTEXT.init(Context {
|
let context = CONTEXT.init(Context {
|
||||||
@ -52,6 +53,7 @@ pub async fn setup(builder: &mut Builder<'static, Driver<'static, USB>>) {
|
|||||||
let spawner = Spawner::for_current_executor().await;
|
let spawner = Spawner::for_current_executor().await;
|
||||||
|
|
||||||
spawner.must_spawn(task(stream, &context.handler));
|
spawner.must_spawn(task(stream, &context.handler));
|
||||||
|
spawner.must_spawn(listen_to_events(events));
|
||||||
|
|
||||||
log::info!("done setting up usb keyboard");
|
log::info!("done setting up usb keyboard");
|
||||||
}
|
}
|
||||||
@ -82,9 +84,27 @@ impl RequestHandler for Handler {
|
|||||||
}
|
}
|
||||||
type HidStream = HidReaderWriter<'static, Driver<'static, USB>, 256, 256>;
|
type HidStream = HidReaderWriter<'static, Driver<'static, USB>, 256, 256>;
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn listen_to_events(mut events: KbEvents) {
|
||||||
|
loop {
|
||||||
|
let event = events.recv().await;
|
||||||
|
report_event(event).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn report_event(event: Event) {
|
||||||
|
match event.kind {
|
||||||
|
EventKind::PressKey(key) => KB_REPORT.lock().await.press_key(key),
|
||||||
|
EventKind::ReleaseKey(key) => KB_REPORT.lock().await.release_key(key),
|
||||||
|
EventKind::PressModifier(modifier) => KB_REPORT.lock().await.press_modifier(modifier),
|
||||||
|
EventKind::ReleaseModifier(modifier) => KB_REPORT.lock().await.release_modifier(modifier),
|
||||||
|
EventKind::SetLayer(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn task(stream: HidStream, handler: &'static Handler) {
|
async fn task(stream: HidStream, handler: &'static Handler) {
|
||||||
if let Err(e) = keyboard_test(stream, handler).await {
|
if let Err(e) = keyboard_report(stream, handler).await {
|
||||||
log::error!("keyboard error: {e:?}");
|
log::error!("keyboard error: {e:?}");
|
||||||
}
|
}
|
||||||
//if let Err(e) = mouse_wiggler(stream).await {
|
//if let Err(e) = mouse_wiggler(stream).await {
|
||||||
@ -92,7 +112,7 @@ async fn task(stream: HidStream, handler: &'static Handler) {
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn keyboard_test(mut stream: HidStream, _handler: &'static Handler) -> Result<(), Error> {
|
async fn keyboard_report(mut stream: HidStream, _handler: &'static Handler) -> Result<(), Error> {
|
||||||
stream.ready().await;
|
stream.ready().await;
|
||||||
loop {
|
loop {
|
||||||
Timer::after(Duration::from_millis(2)).await;
|
Timer::after(Duration::from_millis(2)).await;
|
||||||
|
|||||||
Reference in New Issue
Block a user