From c5257dd8277ab95c60f0d152493e7db652fb6c59 Mon Sep 17 00:00:00 2001 From: Zachary Sunforge Date: Sat, 22 Jun 2024 22:49:15 -0700 Subject: [PATCH] Added node comms --- Cargo.toml | 5 ++++- README.md | 7 ++----- node/Cargo.toml | 11 +++++++++++ node/src/comms.rs | 17 +++++++++++++++++ node/src/lib.rs | 5 +++++ node/src/stm32/mod.rs | 2 ++ node/src/stm32/usb.rs | 28 ++++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 node/src/comms.rs create mode 100644 node/src/stm32/mod.rs create mode 100644 node/src/stm32/usb.rs diff --git a/Cargo.toml b/Cargo.toml index fecb0f3..2391b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.3.0" +version = "0.3.1" edition = "2021" repository = "https://git.bfpower.io/BFPOWER/physical" readme = "README.md" @@ -76,6 +76,9 @@ version = "0.1.*" [workspace.dependencies.embassy-executor] version = "0.5.*" features = ["defmt", "arch-cortex-m", "integrated-timers", "executor-interrupt", "executor-thread"] +[workspace.dependencies.embassy-usb] +version = "0.2.*" +features = ["defmt"] [workspace.dependencies.embassy-stm32] version = "0.1.*" features = ["defmt", "unstable-pac"] diff --git a/README.md b/README.md index 67a396e..5c59a00 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,5 @@ The main concepts of Physical are: * Node: A node hosts peripherals. A node can have a commander but does not need one. A node can ignore or even override commands from the commander. In a complex system, nodes are intended to be kept simple, less likely to encounter an error than the commander, and in some cases should check for obvious problems in commands from the - commander. -* Commander: A commander hosts nodes. It is possible for a device to be both a node and a commander at the same time, - although it may not be the best idea to make such a setup. There is no concept of nesting commanders built into - Physical. If some kind of abstraction for a computer that commands multiple commanders, which command nodes, is - necessary, it should be made for that specific application. \ No newline at end of file + commander. Node can also communicate with other nodes. +* Commander: A commander hosts nodes. It performs long running computations and directs nodes based on the results. \ No newline at end of file diff --git a/node/Cargo.toml b/node/Cargo.toml index 9f2d8ff..1e67d5a 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -7,6 +7,11 @@ repository.workspace = true readme.workspace = true license.workspace = true +[features] +comms = [] +usb = ["embassy-usb"] +stm32 = ["embassy-stm32", "physical/stm32"] + [dependencies.physical] path = ".." [dependencies.embedded-hal] @@ -17,3 +22,9 @@ workspace = true workspace = true [dependencies.uom] workspace = true +[dependencies.embassy-stm32] +workspace = true +optional = true +[dependencies.embassy-usb] +workspace = true +optional = true diff --git a/node/src/comms.rs b/node/src/comms.rs new file mode 100644 index 0000000..d08b29b --- /dev/null +++ b/node/src/comms.rs @@ -0,0 +1,17 @@ +pub trait Sender { + async fn send(&mut self, msg: &[u8]) -> Result<(), Reset>; +} + +pub trait Receiver { + async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Reset>; +} + +//TODO: Replace with ! +pub struct Never; + +/// Communication errors indicates either: +/// Our connection was already disconnected, in which case we should reset and wait for new connection to made. +/// or +/// There was an unexpected, irrecoverable error in communication, in which case we don't want to enter a terminal error +/// safe mode, because there is no indication the actual control is broken, so all we can really do is reset the connection. +pub struct Reset; \ No newline at end of file diff --git a/node/src/lib.rs b/node/src/lib.rs index 5439644..409644a 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -1,3 +1,8 @@ #![no_std] +#[cfg(feature = "comms")] +pub mod comms; +#[cfg(feature = "stm32")] +pub mod stm32; + pub use physical::CriticalError; \ No newline at end of file diff --git a/node/src/stm32/mod.rs b/node/src/stm32/mod.rs new file mode 100644 index 0000000..5ff0b93 --- /dev/null +++ b/node/src/stm32/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "usb")] +pub mod usb; \ No newline at end of file diff --git a/node/src/stm32/usb.rs b/node/src/stm32/usb.rs new file mode 100644 index 0000000..1099716 --- /dev/null +++ b/node/src/stm32/usb.rs @@ -0,0 +1,28 @@ +// The library will have build errors when built on its own (due to not having embassy-stm32 feature for a specific microcontroller) +// but it will work fine when used as a dependency for firmware that has the feature for a specific stm32 microcontroller. + +use crate::comms; +use embassy_stm32::peripherals::USB_OTG_FS; +use embassy_stm32::usb_otg::{Driver, Endpoint, In, Out}; +use embassy_usb::driver::{EndpointIn, EndpointOut}; +use embassy_usb::UsbDevice; + +pub type TypedUSB = UsbDevice<'static, Driver<'static, USB_OTG_FS>>; +pub type TypedInterIn = Endpoint<'static, USB_OTG_FS, In>; +pub type TypedInterOut = Endpoint<'static, USB_OTG_FS, Out>; + +impl comms::Sender for TypedInterIn { + async fn send(&mut self, msg: &[u8]) -> Result<(), comms::Reset> { + self.write(msg).await.map_err(|_| comms::Reset) + } +} + +impl comms::Receiver for TypedInterOut { + async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), comms::Reset> { + // This should be OK because all our messages are smaller than a single packet. + self.read(buffer) + .await + .map(|_| ()) + .map_err(|_| comms::Reset) + } +}