Add communication between keyboard halves

This commit is contained in:
2023-05-09 18:10:43 +02:00
parent 2b66c022f7
commit c39893a067
8 changed files with 278 additions and 31 deletions

View File

@ -11,15 +11,18 @@ use alloc::vec::Vec;
use embassy_executor::Spawner;
use embassy_rp::gpio::{Level, Output, Pin};
use embassy_time::{Duration, Timer};
use log::error;
use tangentbord1::board::Board;
use tangentbord1::keyboard::KeyboardConfig;
use tangentbord1::keyboard::{Half, KeyboardConfig};
use tangentbord1::util::{stall, wheel};
use tangentbord1::ws2812::{Rgb, Ws2812};
use tangentbord1::{allocator, usb};
use tangentbord1::{allocator, uart, usb};
use tgnt::layer::Layer;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let half = Half::Left;
allocator::init();
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());
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 Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
@ -44,6 +43,7 @@ async fn main(_spawner: Spawner) {
};
let keyboard = KeyboardConfig {
half,
pins: [
// row 1
board.d24.degrade(),
@ -75,7 +75,17 @@ async fn main(_spawner: Spawner) {
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.. {
neopixel.write(&[wheel(w as u8)]).await;

View File

@ -11,15 +11,18 @@ use alloc::vec::Vec;
use embassy_executor::Spawner;
use embassy_rp::gpio::{Level, Output, Pin};
use embassy_time::{Duration, Timer};
use log::error;
use tangentbord1::board::Board;
use tangentbord1::keyboard::KeyboardConfig;
use tangentbord1::keyboard::{Half, KeyboardConfig};
use tangentbord1::util::{stall, wheel};
use tangentbord1::ws2812::{Rgb, Ws2812};
use tangentbord1::{allocator, usb};
use tangentbord1::{allocator, uart, usb};
use tgnt::layer::Layer;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let half = Half::Right;
allocator::init();
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());
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;
@ -44,6 +45,7 @@ async fn main(_spawner: Spawner) {
};
let keyboard = KeyboardConfig {
half,
pins: [
// TODO: reconfigure these for right PCB
// row 1
@ -74,7 +76,15 @@ async fn main(_spawner: Spawner) {
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.. {
neopixel.write(&[wheel(w as u8)]).await;

View File

@ -6,19 +6,26 @@ use embassy_rp::{
gpio::{AnyPin, Input, Pin, Pull},
pio::PioInstanceBase,
};
use embassy_sync::pubsub::{ImmediatePublisher, PubSubChannel, Subscriber};
use embassy_time::{Duration, Timer};
use futures::{select_biased, FutureExt};
use log::{debug, error, info, warn};
use static_cell::StaticCell;
use tgnt::{button::Button, layer::Layer};
use tgnt::{
button::{Button, Modifier},
keys::Key,
layer::Layer,
};
use crate::{
lights::Lights,
usb::keyboard::KB_REPORT,
util::CS,
ws2812::{Rgb, Ws2812},
};
pub struct KeyboardConfig {
/// Which board is this.
pub half: Half,
/// Array of input pins of each switch
pub pins: [AnyPin; SWITCH_COUNT],
/// Array of LED indices of each switch
@ -28,6 +35,8 @@ pub struct KeyboardConfig {
}
struct State {
/// Which board is this.
half: Half,
current_layer: AtomicU16,
layers: &'static [Layer],
/// Array of LED indices of each switch
@ -35,13 +44,54 @@ struct State {
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 {
pub async fn create(self) {
pub async fn create(self) -> Option<[KbEvents; KB_SUBSCRIBERS]> {
let spawner = Spawner::for_current_executor().await;
if self.layers.is_empty() {
error!("no layers defined");
return;
return None;
}
info!(
@ -51,6 +101,7 @@ impl KeyboardConfig {
static STATE: StaticCell<State> = StaticCell::new();
let state = STATE.init_with(|| State {
half: self.half,
current_layer: AtomicU16::new(0),
layers: Box::leak(self.layers.into_boxed_slice()),
lights: Lights::new(self.led_driver),
@ -72,6 +123,51 @@ impl KeyboardConfig {
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) -> ! {
let _pin_nr = pin.pin();
let mut pin = Input::new(pin, Pull::Up);
let events = KB_EVENTS.immediate_publisher();
loop {
// pins are pull-up, so when the switch is pressed they are brought low.
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 {
&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;
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;
continue;
}
&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;
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;
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;
select_biased! {
_ = 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;
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;
debug!("switch {switch_num} button {button:?} released");
continue;
}
_ = 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;
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;
continue;
}
@ -165,12 +268,12 @@ async fn switch_task(switch_num: usize, pin: AnyPin, state: &'static State) -> !
}
Button::NextLayer => {
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}");
}
Button::PrevLayer => {
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}");
}
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
#[allow(dead_code)]
pub mod test {

View File

@ -9,6 +9,7 @@ pub mod keyboard;
pub mod lights;
pub mod neopixel;
pub mod panic_handler;
pub mod uart;
pub mod usb;
pub mod util;
pub mod ws2812;

88
src/uart.rs Normal file
View 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"),
}
}

View File

@ -3,6 +3,8 @@ use embassy_rp::{interrupt, peripherals::USB, usb::Driver};
use embassy_usb::{Builder, Config, UsbDevice};
use static_cell::StaticCell;
use crate::keyboard::KbEvents;
pub mod keyboard;
pub mod logger;
@ -17,7 +19,7 @@ struct State {
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);
logger::setup(&mut builder).await;
@ -27,7 +29,7 @@ pub async fn setup_logger_and_keyboard(usb: USB) {
log::debug!("log_level: debug");
log::trace!("log_level: trace");
keyboard::setup(&mut builder).await;
keyboard::setup(&mut builder, events).await;
let usb = builder.build();
Spawner::for_current_executor().await.must_spawn(run(usb));
}

View File

@ -14,6 +14,7 @@ use static_cell::StaticCell;
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
use crate::{
keyboard::{Event, EventKind, KbEvents},
usb::keyboard::report::{KeyboardReport, EMPTY_KEYBOARD_REPORT},
util::CS,
};
@ -31,7 +32,7 @@ struct Context {
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");
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;
spawner.must_spawn(task(stream, &context.handler));
spawner.must_spawn(listen_to_events(events));
log::info!("done setting up usb keyboard");
}
@ -82,9 +84,27 @@ impl RequestHandler for Handler {
}
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]
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:?}");
}
//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;
loop {
Timer::after(Duration::from_millis(2)).await;