diff --git a/flow3-rs-rt/src/flow3r.rs b/flow3-rs-rt/src/flow3r.rs index 6a425fefef29de5d23c02eb0e736480807de66fd..aad306250463edc0641d93e1f967599c94846fa8 100644 --- a/flow3-rs-rt/src/flow3r.rs +++ b/flow3-rs-rt/src/flow3r.rs @@ -14,17 +14,17 @@ use static_cell::StaticCell; use flow3_rs::{ // badgelink::BadgeLink, - captouch::{Captouch, CaptouchRunner}, + captouch::CaptouchRunner, display::Display, // imu::ImuHandler, - input::{Inputs, InputRunner}, + input::InputRunner, leds::init_leds, Flow3r, }; static CLOCKS: StaticCell<Clocks> = StaticCell::new(); -pub async fn init_flow3r() -> (Flow3r, InputRunner, CaptouchRunner) { +pub(crate) async fn init_flow3r() -> (Flow3r, InputRunner, CaptouchRunner) { let peripherals = Peripherals::take(); let mut system = peripherals.SYSTEM.split(); let clocks = CLOCKS.init(ClockControl::boot_defaults(system.clock_control).freeze()); @@ -179,11 +179,9 @@ pub async fn init_flow3r() -> (Flow3r, InputRunner, CaptouchRunner) { //let badgelink = BadgeLink::new(i2c_busmanager.acquire_i2c()); //let imu = ImuHandler::new(i2c_busmanager.acquire_i2c()); - let inputs = Inputs; - let captouch = Captouch; let leds = init_leds(rmt, io.pins.gpio14); - let flow3r = Flow3r::new(None, Some(captouch), Some(display), None, Some(inputs), Some(leds), Some(uart0), Some(uart1), Some(rng)); + let flow3r = Flow3r::new(None, Some(display), None, Some(leds), Some(uart0), Some(uart1), Some(rng)); (flow3r, input_runner, captouch_runner) } \ No newline at end of file diff --git a/flow3-rs-rt/src/lib.rs b/flow3-rs-rt/src/lib.rs index af2e7bdc6623cf9a06b003c147b4241b2dadb93d..709127de6772cec54e7b60a1ca2f94a34799e8bf 100644 --- a/flow3-rs-rt/src/lib.rs +++ b/flow3-rs-rt/src/lib.rs @@ -1,6 +1,17 @@ #![no_std] #![feature(type_alias_impl_trait)] +//! This crate provides a runtime implementation for the [`Flow3r`] based on [`embassy`] as the async runtime. +//! It takes care of initializing the hardware and starting the async runtime and all necessary background tasks. +//! +//! If you want to get started quickly, use the [`flow3-rs-template`] to set up a minimal `flow3-rs-rt` project, by running: +//! ``` +//! cargo generate --git https://git.flow3r.garden/flow3r/flow3-rs +//! ``` +//! +//! [`Flow3r`]: https://flow3r.garden +//! [`embassy`]: https://embassy.dev + mod runtime; mod flow3r; pub use runtime::start_runtime; \ No newline at end of file diff --git a/flow3-rs-rt/src/runtime.rs b/flow3-rs-rt/src/runtime.rs index 31b21055eba13508dad97aa058494b2bb5b1f01e..d2b5370bb6d312cab2a081f16bb0dea857405d03 100644 --- a/flow3-rs-rt/src/runtime.rs +++ b/flow3-rs-rt/src/runtime.rs @@ -10,6 +10,21 @@ use crate::flow3r::init_flow3r; pub static EXECUTOR: StaticCell<Executor> = StaticCell::new(); + +/// This function starts the async runtime, initializes the hardware and then starts the provided `main` function. +/// The function passed as an argument must be an embassy-task. +/// +/// ```rust +/// #[entry] +/// fn runtime() -> ! { +/// start_runtime(main) +/// } +/// +/// #[embassy_runtime::task] +/// async fn main(flow3r: Flow3r) { +/// // do something +/// } +/// ``` pub fn start_runtime<S>(main: fn(Flow3r) -> SpawnToken<S>) -> ! { println!("starting runtime"); @@ -39,12 +54,12 @@ async fn init_runtime(main: fn(Flow3r) -> SpawnToken<*mut ()>) { } #[embassy_executor::task] -pub async fn input_task(runner: InputRunner) -> ! { +async fn input_task(runner: InputRunner) -> ! { runner.run().await } #[embassy_executor::task] -pub async fn captouch_task(runner: CaptouchRunner) -> ! { +async fn captouch_task(runner: CaptouchRunner) -> ! { runner.run().await } diff --git a/flow3-rs-template/src/main.rs b/flow3-rs-template/src/main.rs index 2544fd37d05aadcf92f1fab46471c57fccdc9685..b1c78c46dd241683371eb5b47358b0c951a91c57 100644 --- a/flow3-rs-template/src/main.rs +++ b/flow3-rs-template/src/main.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![feature(type_alias_impl_trait)] -#![feature(async_fn_in_trait)] use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; @@ -19,7 +18,7 @@ fn runtime() -> ! { } #[embassy_executor::task] -async fn main(mut flow3r: Flow3r) { +async fn main(_flow3r: Flow3r) { let spawner = Spawner::for_current_executor().await; spawner.spawn(task()).unwrap(); } diff --git a/flow3-rs/src/captouch.rs b/flow3-rs/src/captouch.rs index 894e00bac670156b29449d2dea13ce2333009861..6a9850d0483fe48c85b6a0ac081d5eae5be671cd 100644 --- a/flow3-rs/src/captouch.rs +++ b/flow3-rs/src/captouch.rs @@ -1,3 +1,30 @@ +//! The Flow3r has a total of 10 captouch surfaces, five top petals on the upper pcb, and five bottom petals on the lower pcb. +//! Those petals are each divided into three touch surfaces for the top petals, and two for the bottom petals, allowing for 2/1 axis position resolution. +//! +//! The petals are numbered clockwise starting from petal 0 above the USB-C port, leading to even-numbered top petals 0,2,4,6,8 and odd-numbered bottom petals 1,3,5,7,9. +//! +//! The captouch as a whole can be accessed via the [`Captouch`] struct, which can be split into individual top and bottom petals. +//! +//! ```rust +//! let captouch = Captouch; +//! +//! // split into top and bottom petals; +//! let top_petals = captouch.top_petals(); +//! let bottom_petals = captouch.bottom_petals(); +//! +//! // check if Petal 7 is pressed +//! if bottom_petals.petal7.pressed() { +//! // do something +//! } +//! ``` +//! +//! ## Runner +//! ### Usage with `flow3-rs-rt` +//! If you use the `flow3-rs` runtime, the runner is automatically set up and started for you. +//! ### Without `flow3-rs` runtime +//! If you don't use the `flow3-rs-rt`, you have to start the captouch runner before you can recieve any captouch events. +//! In a seperate async task, execute the `run` function of the `CaptouchRunner`. + use ad7147::{ device::DecimationFactor, stage::{CapInput, CdcInput, InputConnection, StageSensitivity, ThresholdSensitivity, PeakDetect}, @@ -31,6 +58,7 @@ static PETALS: Mutex<CriticalSectionRawMutex, [Flow3rPetal; 10]> = Mutex::new([ Flow3rPetal::new(Flow3rCaptouchController::BOTTOM), ]); +#[derive(Copy, Clone)] pub struct Captouch; impl Captouch { diff --git a/flow3-rs/src/lib.rs b/flow3-rs/src/lib.rs index f0eb5f1c307f3ea6b61ff123ca9fd85bd8d3fa4a..f3ebbbb7b823a3aa3fa4fc63ede4c85fdcf6ad2b 100644 --- a/flow3-rs/src/lib.rs +++ b/flow3-rs/src/lib.rs @@ -1,6 +1,14 @@ #![no_std] #![feature(type_alias_impl_trait, async_fn_in_trait)] +//! This crate contains the board support for the [`Flow3r`]. It provides higher-level +//! abstractions for the hardware components of the flower. +//! +//! This crate is written for an async runtime. There are some tasks that need to be running in the +//! background for all functionality to work. It was tested with embassy and the flow3-rs-rt, however +//! it _should_ be agnostic over the async runtime used. + + use hal::Rng; use self::badgelink::BadgeLink; @@ -21,12 +29,14 @@ pub mod sdcard; unsafe impl Sync for Flow3r {} +/// This struct contains all the high-level peripherals of the board. +/// To use a peripheral, call the respective `take` or `get` function. This returns an owned version of that peripheral. +/// Each `take` function can only be called once, and will panic if called twice. +/// The peripherals behind a `get` function can exist multiple times. pub struct Flow3r { badgelink: Option<BadgeLink>, - captouch: Option<Captouch>, display: Option<Display>, imu: Option<ImuHandler>, - inputs: Option<Inputs>, leds: Option<Leds>, uart0: Option<BadgenetUartLeft>, uart1: Option<BadgenetUartRight>, @@ -36,10 +46,8 @@ pub struct Flow3r { impl Flow3r { pub fn new( badgelink: Option<BadgeLink>, - captouch: Option<Captouch>, display: Option<Display>, imu: Option<ImuHandler>, - inputs: Option<Inputs>, leds: Option<Leds>, uart0: Option<BadgenetUartLeft>, uart1: Option<BadgenetUartRight>, @@ -47,10 +55,8 @@ impl Flow3r { ) -> Self { Self { badgelink, - captouch, display, imu, - inputs, leds, uart0, uart1, @@ -62,16 +68,16 @@ impl Flow3r { self.badgelink.take().expect("can only take badgelink once!") } - pub fn take_captouch(&mut self) -> Captouch { - self.captouch.take().expect("can only take captouch once!") + pub fn get_captouch(&mut self) -> Captouch { + Captouch } pub fn take_display(&mut self) -> Display { self.display.take().expect("can only take display once!") } - pub fn take_inputs(&mut self) -> Inputs { - self.inputs.take().expect("can only take inputs once!") + pub fn get_inputs(&mut self) -> Inputs { + Inputs } pub fn take_imu(&mut self) -> ImuHandler {