Use postcard to serialize uart messages
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1333,6 +1333,7 @@ dependencies = [
|
|||||||
"atomic-polyfill 1.0.2",
|
"atomic-polyfill 1.0.2",
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
|
"crc-any",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
@ -1355,6 +1356,7 @@ dependencies = [
|
|||||||
"postcard",
|
"postcard",
|
||||||
"ron",
|
"ron",
|
||||||
"rtt-target",
|
"rtt-target",
|
||||||
|
"serde",
|
||||||
"smart-leds",
|
"smart-leds",
|
||||||
"static_cell",
|
"static_cell",
|
||||||
"tgnt",
|
"tgnt",
|
||||||
|
|||||||
@ -10,7 +10,6 @@ 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"
|
|
||||||
usb-device = "0.2.9"
|
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"
|
||||||
@ -36,6 +35,8 @@ heapless = "0.7.16"
|
|||||||
once_cell = { version = "1.17.1", default-features = false }
|
once_cell = { version = "1.17.1", default-features = false }
|
||||||
atomic-polyfill = "1.0.2"
|
atomic-polyfill = "1.0.2"
|
||||||
critical-section = "1.1.1"
|
critical-section = "1.1.1"
|
||||||
|
crc-any = "2.4.3"
|
||||||
|
serde = { version = "1.0.163", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
#[patch."https://git.nubo.sh/hulthe/tgnt.git"]
|
#[patch."https://git.nubo.sh/hulthe/tgnt.git"]
|
||||||
#tgnt = { path = "../tgnt" }
|
#tgnt = { path = "../tgnt" }
|
||||||
|
|||||||
@ -12,6 +12,7 @@ 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 serde::{Deserialize, Serialize};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use tgnt::{
|
use tgnt::{
|
||||||
button::{Button, Modifier},
|
button::{Button, Modifier},
|
||||||
@ -43,13 +44,13 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A keyboard half.
|
/// A keyboard half.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum Half {
|
pub enum Half {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
/// The keyboard half that triggered the event.
|
/// The keyboard half that triggered the event.
|
||||||
pub source: Half,
|
pub source: Half,
|
||||||
@ -60,7 +61,7 @@ pub struct Event {
|
|||||||
pub kind: EventKind,
|
pub kind: EventKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum EventKind {
|
pub enum EventKind {
|
||||||
PressKey(Key),
|
PressKey(Key),
|
||||||
ReleaseKey(Key),
|
ReleaseKey(Key),
|
||||||
|
|||||||
110
src/uart.rs
110
src/uart.rs
@ -1,25 +1,24 @@
|
|||||||
use core::mem::{size_of, transmute};
|
use crc_any::CRCu16;
|
||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::peripherals::{PIN_0, PIN_1, UART0};
|
use embassy_rp::peripherals::{PIN_0, PIN_1, UART0};
|
||||||
use embassy_rp::uart::{self, BufferedUart, DataBits, Parity, StopBits};
|
use embassy_rp::uart::{self, BufferedUart, DataBits, Parity, StopBits};
|
||||||
use embassy_time::{with_timeout, Duration, TimeoutError};
|
|
||||||
use embedded_io::asynch::{Read, Write};
|
use embedded_io::asynch::{Read, Write};
|
||||||
use futures::{select_biased, FutureExt};
|
use futures::{select_biased, FutureExt};
|
||||||
use log::{error, info};
|
use heapless::Vec;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
use crate::keyboard::{self, Half, KbEvents};
|
use crate::keyboard::{self, Half, KbEvents};
|
||||||
use crate::Irqs;
|
use crate::Irqs;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
enum Message {
|
enum Message {
|
||||||
KeyboardEvent(keyboard::Event),
|
KeyboardEvent(keyboard::Event),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(tx: PIN_0, rx: PIN_1, uart: UART0, board: Half, events: KbEvents) {
|
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 TX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
|
||||||
static RX_BUF: StaticCell<[u8; 1024]> = StaticCell::new();
|
static RX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
|
||||||
|
|
||||||
let mut config = uart::Config::default();
|
let mut config = uart::Config::default();
|
||||||
config.baudrate = 115200;
|
config.baudrate = 115200;
|
||||||
@ -32,8 +31,8 @@ pub async fn start(tx: PIN_0, rx: PIN_1, uart: UART0, board: Half, events: KbEve
|
|||||||
Irqs,
|
Irqs,
|
||||||
tx,
|
tx,
|
||||||
rx,
|
rx,
|
||||||
TX_BUF.init_with(|| [0u8; 1024]),
|
TX_BUF.init_with(|| [0u8; 256]),
|
||||||
RX_BUF.init_with(|| [0u8; 1024]),
|
RX_BUF.init_with(|| [0u8; 256]),
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -47,42 +46,103 @@ 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();
|
||||||
|
|
||||||
|
const HEADER_LEN: usize = 4;
|
||||||
|
|
||||||
let rx_task = async {
|
let rx_task = async {
|
||||||
|
let mut buf: heapless::Vec<u8, 1024> = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let mut buf = [0u8; size_of::<Message>()];
|
if let &[len, random, crc1, crc2, ref rest @ ..] = buf.as_slice() {
|
||||||
// TODO: this timout thing seems sketchy
|
let crc = u16::from_le_bytes([crc1, crc2]);
|
||||||
match with_timeout(Duration::from_millis(5), rx.read_exact(&mut buf)).await {
|
let mut calculated_crc = CRCu16::crc16();
|
||||||
Ok(Ok(_)) => {}
|
calculated_crc.digest(&[len, random]);
|
||||||
Ok(Err(e)) => {
|
let calculated_crc = calculated_crc.get_crc();
|
||||||
error!("uart error: {:?}", e);
|
|
||||||
|
if calculated_crc != crc {
|
||||||
|
log::error!("invalid uart package crc: {:x?}", &buf[..HEADER_LEN]);
|
||||||
|
buf.remove(0); // pop the first byte and hope we find a good packet header
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(TimeoutError) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let message: Message = unsafe { transmute(buf) }; // crimes :)
|
log::debug!("got uart header {:x?}", &buf[..HEADER_LEN]);
|
||||||
match &message {
|
|
||||||
Message::KeyboardEvent(event) => events_tx.send(event.clone()),
|
let len = usize::from(len);
|
||||||
|
if rest.len() >= len {
|
||||||
|
let r = postcard::from_bytes(&rest[..len]);
|
||||||
|
|
||||||
|
// drop packet from buffer
|
||||||
|
buf.rotate_left(len + HEADER_LEN);
|
||||||
|
buf.truncate(buf.len() - len - HEADER_LEN);
|
||||||
|
|
||||||
|
let message: Message = match r {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("failed to deserialize message: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &message {
|
||||||
|
Message::KeyboardEvent(event) => events_tx.send(event.clone()),
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!("got msg: {:?}", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut chunk = [0u8; 128];
|
||||||
|
let n = match rx.read(&mut chunk).await {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("uart error: {:?}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if buf.extend_from_slice(&chunk[..n]).is_err() {
|
||||||
|
log::error!("uart buffer full");
|
||||||
|
buf.clear();
|
||||||
}
|
}
|
||||||
info!("got msg: {:?}", message);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let tx_task = async {
|
let tx_task = async {
|
||||||
|
let mut buf = [0u8; 256 + HEADER_LEN];
|
||||||
|
let mut counter = 1;
|
||||||
loop {
|
loop {
|
||||||
// forward messages to the other keyboard half
|
// forward messages to the other keyboard half
|
||||||
let event = events_rx.recv().await;
|
let event = events_rx.recv().await;
|
||||||
if event.source != this_half {
|
if event.source != this_half {
|
||||||
continue; // do not forward messages from the other half back to it
|
continue; // do not forward messages from the other half back to it
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = Message::KeyboardEvent(event);
|
let message = Message::KeyboardEvent(event);
|
||||||
let message: [u8; size_of::<Message>()] = unsafe { transmute(message) }; // crimes :)
|
let (header, body) = buf.split_at_mut(HEADER_LEN);
|
||||||
tx.write_all(&message).await.ok();
|
let serialized = match postcard::to_slice(&message, body) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("failed to serialize uart message: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// add a "random" value to feed the crc
|
||||||
|
let random = counter;
|
||||||
|
counter += 1;
|
||||||
|
|
||||||
|
let len = serialized.len() as u8;
|
||||||
|
|
||||||
|
let mut crc = CRCu16::crc16();
|
||||||
|
crc.digest(&[len, random]);
|
||||||
|
let [crc1, crc2] = crc.get_crc().to_le_bytes();
|
||||||
|
|
||||||
|
header.copy_from_slice(&[len, random, crc1, crc2]);
|
||||||
|
|
||||||
|
let package = &buf[..HEADER_LEN + usize::from(len)];
|
||||||
|
tx.write_all(package).await.ok();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
select_biased! {
|
select_biased! {
|
||||||
_ = tx_task.fuse() => error!("uart tx_task exited"),
|
_ = tx_task.fuse() => log::error!("uart tx_task exited"),
|
||||||
_ = rx_task.fuse() => error!("eart rx_task exited"),
|
_ = rx_task.fuse() => log::error!("eart rx_task exited"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user