Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Rework basically the entire protocol #53

Merged
merged 32 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b350f15
I think this is a good direction
jamesmunns Oct 17, 2024
f3c0b15
I think this shape might work
jamesmunns Oct 18, 2024
ee9f52d
Implement test channel impl for server2
jamesmunns Oct 18, 2024
6c8c23d
cargo fmt
jamesmunns Oct 18, 2024
6bf0f4d
Pretty close to complete?
jamesmunns Oct 18, 2024
6cc3426
Work towards design
jamesmunns Oct 21, 2024
959d092
I need to back out the module stuff
jamesmunns Oct 21, 2024
5d2aebe
Comms-02 appears to work
jamesmunns Oct 21, 2024
e74280d
lol, lmao
jamesmunns Oct 21, 2024
bc03326
Button it up for the day
jamesmunns Oct 21, 2024
8ee9d97
Cargo fmt
jamesmunns Oct 21, 2024
1ee0c35
Add some accessors
jamesmunns Oct 21, 2024
8834b42
Basic e2e works
jamesmunns Oct 22, 2024
56d912f
Update sequence number, update embassy code
jamesmunns Oct 22, 2024
577de2c
Fix comms-02
jamesmunns Oct 22, 2024
8d64404
Remove old target_server
jamesmunns Oct 22, 2024
eb0525f
Cargo fmt
jamesmunns Oct 22, 2024
6104d02
Remove old headered module
jamesmunns Oct 22, 2024
d677a4a
Move key resizing to Server instead of WireTx impls
jamesmunns Oct 22, 2024
1b7c3b5
Rename server2 -> server
jamesmunns Oct 22, 2024
18f1475
Unique schema calculation
jamesmunns Oct 24, 2024
7a58031
Write docs for `uniques`
jamesmunns Oct 24, 2024
fadff79
Fix switchover to mutex for subscriptions
jamesmunns Oct 24, 2024
89c6d50
Rework perfect hash function
jamesmunns Oct 25, 2024
0d26fcc
Whoops hit save
jamesmunns Oct 25, 2024
c7f7c29
Consider the whole in/out endpoint/topic lists for perfect hashing
jamesmunns Oct 25, 2024
cd402e2
Fix tests
jamesmunns Oct 27, 2024
45278a7
Cargo fmt
jamesmunns Oct 27, 2024
071eceb
Remove direct paste dep
jamesmunns Oct 27, 2024
c1acb02
Remove some temp toml
jamesmunns Oct 27, 2024
d2e3f24
Write all the docs
jamesmunns Oct 27, 2024
e83cb86
Fix example, upgrade missing docs to an error
jamesmunns Oct 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 5 additions & 26 deletions example/firmware/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions example/firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pio = "0.2.1"
pio-proc = "0.2"
smart-leds = "0.3.0"
static_cell = "2.1"
paste = "1.0.15"
jamesmunns marked this conversation as resolved.
Show resolved Hide resolved

[profile.release]
debug = 2
Expand Down
163 changes: 99 additions & 64 deletions example/firmware/src/bin/comms-02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,45 @@ use embassy_rp::{
peripherals::{PIO0, SPI0, USB},
pio::Pio,
spi::{self, Spi},
usb::{self, Driver, Endpoint, Out},
usb,
};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, mutex::Mutex};
use embassy_time::{Delay, Duration, Ticker};
use embassy_usb::UsbDevice;
use embassy_usb::{Config, UsbDevice};
use embedded_hal_bus::spi::ExclusiveDevice;
use lis3dh_async::{Lis3dh, Lis3dhSPI};
use portable_atomic::{AtomicBool, Ordering};
use postcard_rpc::{
define_dispatch,
target_server::{
buffers::AllBuffers, configure_usb, example_config, rpc_dispatch, sender::Sender,
SpawnContext,
define_dispatch2,
server2::{
impls::embassy_usb_v0_3::{
dispatch_impl::{
spawn_fn, WireRxBuf, WireRxImpl, WireSpawnImpl, WireStorage, WireTxImpl,
},
PacketBuffers,
},
Sender, Server, SpawnContext,
},
WireHeader,
header::VarHeader,
};
use smart_leds::{colors::BLACK, RGB8};
use static_cell::{ConstStaticCell, StaticCell};
use workbook_fw::{
get_unique_id, ws2812::{self, Ws2812}, Irqs
get_unique_id,
ws2812::{self, Ws2812},
Irqs,
};
use workbook_icd::{
AccelTopic, Acceleration, BadPositionError, GetUniqueIdEndpoint, PingEndpoint, Rgb8,
SetAllLedEndpoint, SetSingleLedEndpoint, SingleLed, StartAccel, StartAccelerationEndpoint,
StopAccelerationEndpoint,
StopAccelerationEndpoint, ENDPOINT_LIST, TOPICS_IN_LIST,
};
use {defmt_rtt as _, panic_probe as _};

pub type Accel =
Lis3dh<Lis3dhSPI<ExclusiveDevice<Spi<'static, SPI0, spi::Async>, Output<'static>, Delay>>>;
static ACCEL: StaticCell<Mutex<ThreadModeRawMutex, Accel>> = StaticCell::new();

static ALL_BUFFERS: ConstStaticCell<AllBuffers<256, 256, 256>> =
ConstStaticCell::new(AllBuffers::new());

pub struct Context {
pub unique_id: u64,
pub ws2812: Ws2812<'static, PIO0, 0, 24>,
Expand All @@ -61,18 +65,57 @@ impl SpawnContext for Context {
}
}

define_dispatch! {
dispatcher: Dispatcher<
Mutex = ThreadModeRawMutex,
Driver = usb::Driver<'static, USB>,
Context = Context,
>;
PingEndpoint => blocking ping_handler,
GetUniqueIdEndpoint => blocking unique_id_handler,
SetSingleLedEndpoint => async set_led_handler,
SetAllLedEndpoint => async set_all_led_handler,
StartAccelerationEndpoint => spawn accelerometer_handler,
StopAccelerationEndpoint => blocking accelerometer_stop_handler,
type AppDriver = usb::Driver<'static, USB>;
type AppStorage = WireStorage<ThreadModeRawMutex, AppDriver, 256, 256, 64, 256>;
type BufStorage = PacketBuffers<1024, 1024>;
type AppTx = WireTxImpl<ThreadModeRawMutex, AppDriver>;
type AppRx = WireRxImpl<AppDriver>;
type AppServer = Server<AppTx, AppRx, WireRxBuf, Dispatcher>;

static PBUFS: ConstStaticCell<BufStorage> = ConstStaticCell::new(BufStorage::new());
static STORAGE: AppStorage = AppStorage::new();

fn usb_config() -> Config<'static> {
let mut config = Config::new(0x16c0, 0x27DD);
config.manufacturer = Some("OneVariable");
config.product = Some("ov-twin");
config.serial_number = Some("12345678");

// Required for windows compatibility.
// https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
config.device_class = 0xEF;
config.device_sub_class = 0x02;
config.device_protocol = 0x01;
config.composite_with_iads = true;

config
}

define_dispatch2! {
app: Dispatcher;
spawn_fn: spawn_fn;
tx_impl: AppTx;
spawn_impl: WireSpawnImpl;
context: Context;

endpoints: {
list: ENDPOINT_LIST;

| EndpointTy | kind | handler |
| ---------- | ---- | ------- |
| PingEndpoint | blocking | ping_handler |
| GetUniqueIdEndpoint | blocking | unique_id_handler |
| SetSingleLedEndpoint | async | set_led_handler |
| SetAllLedEndpoint | async | set_all_led_handler |
| StartAccelerationEndpoint | spawn | accelerometer_handler |
| StopAccelerationEndpoint | blocking | accelerometer_stop_handler |
};
topics_in: {
list: TOPICS_IN_LIST;

| TopicTy | kind | handler |
| ---------- | ---- | ------- |
};
}

#[embassy_executor::main]
Expand Down Expand Up @@ -106,60 +149,52 @@ async fn main(spawner: Spawner) {

// USB/RPC INIT
let driver = usb::Driver::new(p.USB, Irqs);
let mut config = example_config();
config.manufacturer = Some("OneVariable");
config.product = Some("ov-twin");
let buffers = ALL_BUFFERS.take();
let (device, ep_in, ep_out) = configure_usb(driver, &mut buffers.usb_device, config);
let dispatch = Dispatcher::new(
&mut buffers.tx_buf,
ep_in,
Context {
unique_id,
ws2812,
ws2812_state: [BLACK; 24],
accel: accel_ref,
},
);
let pbufs = PBUFS.take();
let config = usb_config();

spawner.must_spawn(dispatch_task(ep_out, dispatch, &mut buffers.rx_buf));
let context = Context {
unique_id,
ws2812,
ws2812_state: [BLACK; 24],
accel: accel_ref,
};

let (device, tx_impl, rx_impl) = STORAGE.init(driver, config, pbufs.tx_buf.as_mut_slice());
let dispatcher = Dispatcher::new(context, spawner.into());
let mut server: AppServer = Server::new(&tx_impl, rx_impl, pbufs.rx_buf.as_mut_slice(), dispatcher);
spawner.must_spawn(usb_task(device));
}

/// This actually runs the dispatcher
#[embassy_executor::task]
async fn dispatch_task(
ep_out: Endpoint<'static, USB, Out>,
dispatch: Dispatcher,
rx_buf: &'static mut [u8],
) {
rpc_dispatch(ep_out, dispatch, rx_buf).await;
loop {
// If the host disconnects, we'll return an error here.
// If this happens, just wait until the host reconnects
let _ = server.run().await;
}
}

/// This handles the low level USB management
#[embassy_executor::task]
pub async fn usb_task(mut usb: UsbDevice<'static, Driver<'static, USB>>) {
pub async fn usb_task(mut usb: UsbDevice<'static, AppDriver>) {
usb.run().await;
}

// ---

fn ping_handler(_context: &mut Context, header: WireHeader, rqst: u32) -> u32 {
info!("ping: seq - {=u32}", header.seq_no);
fn ping_handler(_context: &mut Context, _header: VarHeader, rqst: u32) -> u32 {
info!("ping");
rqst
}

fn unique_id_handler(context: &mut Context, header: WireHeader, _rqst: ()) -> u64 {
info!("unique_id: seq - {=u32}", header.seq_no);
fn unique_id_handler(context: &mut Context, _header: VarHeader, _rqst: ()) -> u64 {
info!("unique_id");
context.unique_id
}

async fn set_led_handler(
context: &mut Context,
header: WireHeader,
_header: VarHeader,
rqst: SingleLed,
) -> Result<(), BadPositionError> {
info!("set_led: seq - {=u32}", header.seq_no);
info!("set_led");
if rqst.position >= 24 {
return Err(BadPositionError);
}
Expand All @@ -173,8 +208,8 @@ async fn set_led_handler(
Ok(())
}

async fn set_all_led_handler(context: &mut Context, header: WireHeader, rqst: [Rgb8; 24]) {
info!("set_all_led: seq - {=u32}", header.seq_no);
async fn set_all_led_handler(context: &mut Context, _header: VarHeader, rqst: [Rgb8; 24]) {
info!("set_all_led");
context
.ws2812_state
.iter_mut()
Expand All @@ -192,9 +227,9 @@ static STOP: AtomicBool = AtomicBool::new(false);
#[embassy_executor::task]
async fn accelerometer_handler(
context: SpawnCtx,
header: WireHeader,
header: VarHeader,
rqst: StartAccel,
sender: Sender<ThreadModeRawMutex, usb::Driver<'static, USB>>,
sender: Sender<AppTx>,
) {
let mut accel = context.accel.lock().await;
if sender
Expand All @@ -209,7 +244,7 @@ async fn accelerometer_handler(
defmt::unwrap!(accel.set_range(lis3dh_async::Range::G8).await.map_err(drop));

let mut ticker = Ticker::every(Duration::from_millis(rqst.interval_ms.into()));
let mut seq = 0;
let mut seq = 0u8;
while !STOP.load(Ordering::Acquire) {
ticker.next().await;
let acc = defmt::unwrap!(accel.accel_raw().await.map_err(drop));
Expand All @@ -219,7 +254,7 @@ async fn accelerometer_handler(
y: acc.y,
z: acc.z,
};
if sender.publish::<AccelTopic>(seq, &msg).await.is_err() {
if sender.publish::<AccelTopic>(seq.into(), &msg).await.is_err() {
defmt::error!("Send error!");
break;
}
Expand All @@ -229,8 +264,8 @@ async fn accelerometer_handler(
STOP.store(false, Ordering::Release);
}

fn accelerometer_stop_handler(context: &mut Context, header: WireHeader, _rqst: ()) -> bool {
info!("accel_stop: seq - {=u32}", header.seq_no);
fn accelerometer_stop_handler(context: &mut Context, _header: VarHeader, _rqst: ()) -> bool {
info!("accel_stop");
let was_busy = context.accel.try_lock().is_err();
if was_busy {
STOP.store(true, Ordering::Release);
Expand Down
9 changes: 8 additions & 1 deletion example/workbook-icd/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading