176 lines
5.6 KiB
Rust
176 lines
5.6 KiB
Rust
use core::mem::size_of;
|
|
|
|
use bytemuck::{cast, AnyBitPattern, NoUninit};
|
|
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 embedded_io::asynch::{Read, Write};
|
|
use futures::{select_biased, FutureExt};
|
|
use heapless::Vec;
|
|
use serde::{Deserialize, Serialize};
|
|
use static_cell::StaticCell;
|
|
|
|
use crate::event::{switch, Half};
|
|
use crate::interrupts::Irqs;
|
|
use crate::keyboard::KbEvents;
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
enum Message {
|
|
KeyboardEvent(switch::Event),
|
|
}
|
|
|
|
pub async fn start(tx: PIN_0, rx: PIN_1, uart: UART0, board: Half, events: KbEvents) {
|
|
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;
|
|
config.data_bits = DataBits::DataBits8;
|
|
config.stop_bits = StopBits::STOP1;
|
|
config.parity = Parity::ParityNone;
|
|
|
|
let uart = embassy_rp::uart::BufferedUart::new(
|
|
uart,
|
|
Irqs,
|
|
tx,
|
|
rx,
|
|
TX_BUF.init_with(|| [0u8; 256]),
|
|
RX_BUF.init_with(|| [0u8; 256]),
|
|
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();
|
|
|
|
/// The header of a UART packet.
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug, NoUninit, AnyBitPattern)]
|
|
struct Header {
|
|
/// The length of the payload.
|
|
len: u8,
|
|
|
|
/// An arbitrary value to feed the crc, should be different for each message.
|
|
random: u8,
|
|
|
|
/// A little-endian crc16.
|
|
crc: [u8; 2],
|
|
}
|
|
|
|
const HEADER_LEN: usize = size_of::<Header>();
|
|
|
|
let rx_task = async {
|
|
let mut buf: heapless::Vec<u8, 1024> = Vec::new();
|
|
loop {
|
|
if buf.len() >= HEADER_LEN {
|
|
let (&header, rest) = buf.split_array_ref::<HEADER_LEN>();
|
|
let header: Header = cast(header);
|
|
let crc = u16::from_le_bytes(header.crc);
|
|
let mut calculated_crc = CRCu16::crc16();
|
|
calculated_crc.digest(&[header.len, header.random]);
|
|
let calculated_crc = calculated_crc.get_crc();
|
|
|
|
if calculated_crc != crc {
|
|
log::error!("invalid uart header crc: {header:x?}");
|
|
buf.remove(0); // drop the first byte and hope we find a good packet header
|
|
continue;
|
|
}
|
|
|
|
log::trace!(
|
|
"reading from uart, header={header:?}, bytes_received={}",
|
|
rest.len()
|
|
);
|
|
|
|
let len = usize::from(header.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();
|
|
}
|
|
}
|
|
};
|
|
|
|
let tx_task = async {
|
|
let mut buf = [0u8; 256 + HEADER_LEN];
|
|
let mut counter = 0u8;
|
|
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 (buf_header, body) = buf.split_array_mut();
|
|
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
|
|
counter = counter.wrapping_add(1);
|
|
let random = counter;
|
|
|
|
let len = serialized.len() as u8;
|
|
|
|
let mut crc = CRCu16::crc16();
|
|
crc.digest(&[len, random]);
|
|
let header = Header {
|
|
len: serialized.len() as u8,
|
|
random,
|
|
crc: crc.get_crc().to_le_bytes(),
|
|
};
|
|
let header: [u8; HEADER_LEN] = cast(header);
|
|
*buf_header = header;
|
|
|
|
let package = &buf[..HEADER_LEN + usize::from(len)];
|
|
tx.write_all(package).await.ok();
|
|
}
|
|
};
|
|
|
|
select_biased! {
|
|
_ = tx_task.fuse() => log::error!("uart tx_task exited"),
|
|
_ = rx_task.fuse() => log::error!("eart rx_task exited"),
|
|
}
|
|
}
|