From 5c68b483af2f64d63bfc84733b92324c37f4665c Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sun, 21 May 2023 11:11:28 +0200 Subject: [PATCH] Use postcard to serialize uart messages --- Cargo.lock | 2 + Cargo.toml | 3 +- src/keyboard.rs | 7 +-- src/uart.rs | 110 +++++++++++++++++++++++++++++++++++++----------- 4 files changed, 93 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8573492..5cf1dd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,6 +1333,7 @@ dependencies = [ "atomic-polyfill 1.0.2", "cortex-m", "cortex-m-rt", + "crc-any", "critical-section", "embassy-executor", "embassy-futures", @@ -1355,6 +1356,7 @@ dependencies = [ "postcard", "ron", "rtt-target", + "serde", "smart-leds", "static_cell", "tgnt", diff --git a/Cargo.toml b/Cargo.toml index a3e484d..eec657a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false } cortex-m = "0.7.6" cortex-m-rt = "0.7" embedded-hal = "0.2.5" -#panic-halt = "0.2.0" usb-device = "0.2.9" usbd-hid = "0.6.1" static_cell = "1.0.0" @@ -36,6 +35,8 @@ heapless = "0.7.16" once_cell = { version = "1.17.1", default-features = false } atomic-polyfill = "1.0.2" 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"] #tgnt = { path = "../tgnt" } diff --git a/src/keyboard.rs b/src/keyboard.rs index b078c76..87ff0fb 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -12,6 +12,7 @@ use embassy_sync::pubsub::{ImmediatePublisher, PubSubChannel, Subscriber}; use embassy_time::{Duration, Timer}; use futures::{select_biased, FutureExt}; use log::{debug, error, info, warn}; +use serde::{Deserialize, Serialize}; use static_cell::StaticCell; use tgnt::{ button::{Button, Modifier}, @@ -43,13 +44,13 @@ struct State { } /// A keyboard half. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Half { Left, Right, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Event { /// The keyboard half that triggered the event. pub source: Half, @@ -60,7 +61,7 @@ pub struct Event { pub kind: EventKind, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum EventKind { PressKey(Key), ReleaseKey(Key), diff --git a/src/uart.rs b/src/uart.rs index f1faf0c..cfefe3b 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -1,25 +1,24 @@ -use core::mem::{size_of, transmute}; - +use crc_any::CRCu16; use embassy_executor::Spawner; 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 heapless::Vec; +use serde::{Deserialize, Serialize}; use static_cell::StaticCell; use crate::keyboard::{self, Half, KbEvents}; use crate::Irqs; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] 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(); + static TX_BUF: StaticCell<[u8; 256]> = StaticCell::new(); + static RX_BUF: StaticCell<[u8; 256]> = StaticCell::new(); let mut config = uart::Config::default(); config.baudrate = 115200; @@ -32,8 +31,8 @@ pub async fn start(tx: PIN_0, rx: PIN_1, uart: UART0, board: Half, events: KbEve Irqs, tx, rx, - TX_BUF.init_with(|| [0u8; 1024]), - RX_BUF.init_with(|| [0u8; 1024]), + TX_BUF.init_with(|| [0u8; 256]), + RX_BUF.init_with(|| [0u8; 256]), 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 events_rx, mut events_tx) = events.split(); + const HEADER_LEN: usize = 4; + let rx_task = async { + let mut buf: heapless::Vec = Vec::new(); loop { - let mut buf = [0u8; size_of::()]; - // 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); + if let &[len, random, crc1, crc2, ref rest @ ..] = buf.as_slice() { + let crc = u16::from_le_bytes([crc1, crc2]); + let mut calculated_crc = CRCu16::crc16(); + calculated_crc.digest(&[len, random]); + let calculated_crc = calculated_crc.get_crc(); + + 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; } - Err(TimeoutError) => continue, - }; - let message: Message = unsafe { transmute(buf) }; // crimes :) - match &message { - Message::KeyboardEvent(event) => events_tx.send(event.clone()), + log::debug!("got uart header {:x?}", &buf[..HEADER_LEN]); + + 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 mut buf = [0u8; 256 + HEADER_LEN]; + let mut counter = 1; 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::()] = unsafe { transmute(message) }; // crimes :) - tx.write_all(&message).await.ok(); + let (header, body) = buf.split_at_mut(HEADER_LEN); + 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! { - _ = tx_task.fuse() => error!("uart tx_task exited"), - _ = rx_task.fuse() => error!("eart rx_task exited"), + _ = tx_task.fuse() => log::error!("uart tx_task exited"), + _ = rx_task.fuse() => log::error!("eart rx_task exited"), } }