Skip to content

Commit

Permalink
Expand the capabilities of various macros (#55)
Browse files Browse the repository at this point in the history
* Hah Hah! I'm doing macros!

* Macros overwhelming!

* Remove now-incorrect message pre-check

* Implement schema querying

* Add minimal reference example

* Implement logging, fill out docs, format
  • Loading branch information
jamesmunns authored Oct 31, 2024
1 parent 0544018 commit a2808a3
Show file tree
Hide file tree
Showing 27 changed files with 2,971 additions and 314 deletions.
4 changes: 4 additions & 0 deletions example/firmware/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+

[env]
DEFMT_LOG = "debug"

[unstable]
build-std = ["core"]
build-std-features = ["panic_immediate_abort"]
19 changes: 13 additions & 6 deletions example/firmware/Cargo.lock

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

2 changes: 1 addition & 1 deletion example/firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static_cell = "2.1"
[profile.release]
debug = 2
lto = true
opt-level = 's'
opt-level = 'z'
codegen-units = 1
incremental = false

Expand Down
135 changes: 135 additions & 0 deletions example/firmware/src/bin/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#![no_std]
#![no_main]

use defmt::info;
use embassy_executor::Spawner;
use embassy_rp::{peripherals::USB, usb};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_time::{Duration, Ticker};
use embassy_usb::{Config, UsbDevice};
use postcard_rpc::{
define_dispatch, sender_fmt,
server::{
impls::embassy_usb_v0_3::{
dispatch_impl::{WireRxBuf, WireRxImpl, WireSpawnImpl, WireStorage, WireTxImpl},
PacketBuffers,
},
Dispatch, Sender, Server,
},
};
use static_cell::ConstStaticCell;
use workbook_fw::Irqs;
use workbook_icd::{ENDPOINT_LIST, TOPICS_IN_LIST, TOPICS_OUT_LIST};
use {defmt_rtt as _, panic_probe as _};

pub struct Context {}

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, MyApp>;

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_dispatch! {
app: MyApp;
spawn_fn: spawn_fn;
tx_impl: AppTx;
spawn_impl: WireSpawnImpl;
context: Context;

endpoints: {
list: ENDPOINT_LIST;

| EndpointTy | kind | handler |
| ---------- | ---- | ------- |
};
topics_in: {
list: TOPICS_IN_LIST;

| TopicTy | kind | handler |
| ---------- | ---- | ------- |
};
topics_out: {
list: TOPICS_OUT_LIST;
};
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
// SYSTEM INIT
info!("Start");
let p = embassy_rp::init(Default::default());

// USB/RPC INIT
let driver = usb::Driver::new(p.USB, Irqs);
let pbufs = PBUFS.take();
let config = usb_config();

let context = Context {};

let (device, tx_impl, rx_impl) = STORAGE.init(driver, config, pbufs.tx_buf.as_mut_slice());
let dispatcher = MyApp::new(context, spawner.into());
let vkk = dispatcher.min_key_len();
let server: AppServer = Server::new(
&tx_impl,
rx_impl,
pbufs.rx_buf.as_mut_slice(),
dispatcher,
vkk,
);
let sender = server.sender();
spawner.must_spawn(usb_task(device));
spawner.must_spawn(server_task(server));
spawner.must_spawn(logging_task(sender));
}

#[embassy_executor::task]
pub async fn logging_task(sender: Sender<AppTx>) {
let mut ticker = Ticker::every(Duration::from_millis(1000));
let mut ctr = 0u16;
loop {
ticker.next().await;
defmt::info!("logging");
if ctr & 0b1 != 0 {
let _ = sender.log_str("Hello world!").await;
} else {
let _ = sender_fmt!(sender, "formatted: {ctr}").await;
}
ctr = ctr.wrapping_add(1);
}
}

#[embassy_executor::task]
pub async fn server_task(mut server: AppServer) {
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, AppDriver>) {
usb.run().await;
}
116 changes: 116 additions & 0 deletions example/firmware/src/bin/minimal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#![no_std]
#![no_main]

use defmt::info;
use embassy_executor::Spawner;
use embassy_rp::{peripherals::USB, usb};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_usb::{Config, UsbDevice};
use postcard_rpc::{
define_dispatch,
server::{
impls::embassy_usb_v0_3::{
dispatch_impl::{WireRxBuf, WireRxImpl, WireSpawnImpl, WireStorage, WireTxImpl},
PacketBuffers,
},
Dispatch, Server,
},
};
use static_cell::ConstStaticCell;
use workbook_fw::Irqs;
use workbook_icd::{ENDPOINT_LIST, TOPICS_IN_LIST, TOPICS_OUT_LIST};
use {defmt_rtt as _, panic_probe as _};

pub struct Context {}

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, MyApp>;

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_dispatch! {
app: MyApp;
spawn_fn: spawn_fn;
tx_impl: AppTx;
spawn_impl: WireSpawnImpl;
context: Context;

endpoints: {
list: ENDPOINT_LIST;

| EndpointTy | kind | handler |
| ---------- | ---- | ------- |
};
topics_in: {
list: TOPICS_IN_LIST;

| TopicTy | kind | handler |
| ---------- | ---- | ------- |
};
topics_out: {
list: TOPICS_OUT_LIST;
};
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
// SYSTEM INIT
info!("Start");
let p = embassy_rp::init(Default::default());

// USB/RPC INIT
let driver = usb::Driver::new(p.USB, Irqs);
let pbufs = PBUFS.take();
let config = usb_config();

let context = Context {};

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

#[embassy_executor::task]
pub async fn server_task(mut server: AppServer) {
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, AppDriver>) {
usb.run().await;
}
Loading

0 comments on commit a2808a3

Please sign in to comment.