From 43eafb0784cb94a19d782b332aaab47e13afe205 Mon Sep 17 00:00:00 2001 From: Mathieu Gravel Date: Mon, 2 Jun 2025 13:30:11 -0700 Subject: [PATCH 1/2] small improvements remove send and add noop writer. revmove default impl cargo fmt cargo clippy review fix cargo +nightly fmt fix doc all features cargo fmt line with 100 Noop -> Nop fmt remove send trait, future pr add mut to self in writer trait cargo fmt cargo +nightly fmt try to make the ci fmt works :( --- src/client.rs | 34 +++----------- src/components.rs | 13 +++-- src/fmt.rs | 10 ++-- src/host.rs | 34 ++++++++------ src/lib.rs | 91 +---------------------------------- src/protocol_definitions.rs | 2 +- src/writer.rs | 94 +++++++++++++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 140 deletions(-) create mode 100644 src/writer.rs diff --git a/src/client.rs b/src/client.rs index 77a97ea..8618d2c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,6 @@ -use super::*; +use core::future::Future; + +use crate::components::CfuComponentTraits; /// CfuReceiveContent trait defines behavior needed for a Cfu client (receiver) to process CFU commands /// E is an error type that can be defined by the implementor @@ -7,37 +9,13 @@ use super::*; pub trait CfuReceiveContent { /// receives a CFU command from a Host and processes the contents /// Typestates here allow for flexible implementations - fn process_command(&self, args: Option, cmd: C) -> impl Future> { - default_process_command::(args, cmd) - } + fn process_command(&self, args: Option, cmd: C) -> impl Future>; + /// For all components, run their storage_prepare() method /// Typestates here allow for flexible implementations fn prepare_components( &self, args: Option, primary_component: impl CfuComponentTraits, - ) -> impl Future> { - default_prepare_components::(args, primary_component) - } -} - -/// Helper function to provide a default implementation for process_command -async fn default_process_command(args: Option, _cmd: C) -> Result<(), E> { - if args.is_some() { - trace!("unexpected args to default_process_command function"); - trace!("potentially missing implementation of process_command in CfuReceiveContent trait") - } - Ok(()) -} - -/// Helper function to provide a default implementation for prepare_components -async fn default_prepare_components( - args: Option, - _primary_component: impl CfuComponentTraits, -) -> Result<(), E> { - if args.is_some() { - trace!("unexpected args to default_prepare_components function"); - trace!("potentially missing implementation of prepare_components in CfuReceiveContent trait") - } - Ok(()) + ) -> impl Future>; } diff --git a/src/components.rs b/src/components.rs index 05886c8..68f53f7 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,32 +1,39 @@ use core::future::Future; -use crate::protocol_definitions::*; -use crate::{CfuWriter, CfuWriterError}; +use crate::protocol_definitions::{ + CfuProtocolError, ComponentId, FwVersion, OfferRejectReason, OfferStatus, MAX_SUBCMPT_COUNT, +}; +use crate::writer::CfuWriterError; pub trait CfuComponentInfo { /// Gets the current fw version of the component fn get_fw_version(&self) -> impl Future>; + /// Gets the component's id /// Not async as this should be an element of struct that implements this trait fn get_component_id(&self) -> ComponentId; + /// Validate the CFU offer for the component /// returns an OfferStatus with additional info on Reject Reason in the Err case. fn is_offer_valid(&self) -> impl Future>; + /// Returns whether or not this component is a primary component /// Not async as this should be an element of struct that implements this trait /// Default implementation returns false, fn is_primary_component(&self) -> bool { false } + /// Returns whether or not this component has a dual-bank memory layout /// Not async as this should be an element of struct that implements this trait fn is_dual_bank(&self) -> bool; + /// Returns sub-component ids if this component has any /// Not async as this should be an element of struct that implements this trait fn get_subcomponents(&self) -> [Option; MAX_SUBCMPT_COUNT]; } -pub trait CfuComponentStorage: CfuWriter { +pub trait CfuComponentStorage { fn storage_prepare(&self) -> impl Future>; fn storage_write(&self) -> impl Future>; fn storage_finalize(&self) -> impl Future>; diff --git a/src/fmt.rs b/src/fmt.rs index 6ef6306..03ba062 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -1,9 +1,10 @@ -//! Logging macro implementations and other formating functions +//! Logging macro implementations and other formatting functions #[cfg(all(feature = "log", feature = "defmt", not(doc)))] compile_error!("features `log` and `defmt` are mutually exclusive"); -#[cfg(all(not(doc), feature = "defmt"))] +#[cfg(all(feature = "defmt", not(doc)))] +#[doc(hidden)] mod defmt { /// Logs a trace message using the underlying logger #[macro_export] @@ -61,7 +62,8 @@ mod defmt { } } -#[cfg(all(not(doc), feature = "log"))] +#[cfg(all(feature = "log", not(doc)))] +#[doc(hidden)] mod log { /// Logs a trace message using the underlying logger #[macro_export] @@ -120,7 +122,7 @@ mod log { } // Provide this implementation for `cargo doc` -#[cfg(any(doc, not(any(feature = "defmt", feature = "log"))))] +#[cfg(any(not(any(feature = "defmt", feature = "log")), doc))] mod none { /// Logs a trace message using the underlying logger #[macro_export] diff --git a/src/host.rs b/src/host.rs index 821008f..35f9a71 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,20 +1,26 @@ -use super::*; +use core::future::Future; + +use crate::protocol_definitions::{ + CfuProtocolError, CfuUpdateContentResponseStatus, ComponentId, FwUpdateContentCommand, FwUpdateContentHeader, + FwUpdateContentResponse, FwUpdateOfferResponse, DEFAULT_DATA_LENGTH, FW_UPDATE_FLAG_FIRST_BLOCK, + FW_UPDATE_FLAG_LAST_BLOCK, +}; +use crate::writer::{CfuWriterAsync, CfuWriterError}; +use crate::{trace, CfuImage, DataChunk}; /// CfuHostStates trait defines behavior needed for a Cfu Host to process available Cfu Offers /// and send the appropriate commands to the Cfu Client to update the components -pub trait CfuHostStates { +pub trait CfuHostStates { /// Notifies that the host is now initialized and has identified the offers to send - fn start_transaction( - self, - writer: &mut W, - ) -> impl Future>; + fn start_transaction(self, writer: &mut W) + -> impl Future>; /// Notifies the primary component that the host is ready to start sending offers - fn notify_start_offer_list( + fn notify_start_offer_list( self, writer: &mut W, ) -> impl Future>; /// Notifies the primary component that the host has sent all offers - fn notify_end_offer_list( + fn notify_end_offer_list( self, writer: &mut W, ) -> impl Future>; @@ -25,10 +31,7 @@ pub trait CfuHostStates { } /// CfuUpdateContent trait defines behavior needed for a Cfu Host to send the contents of an accepted offer to a component via sending commands to a Cfu Client -pub trait CfuUpdateContent -where - W: CfuWriter, -{ +pub trait CfuUpdateContent { /// Write all chunks of an image fn write_data_chunks( &mut self, @@ -37,12 +40,14 @@ where cmpt_id: ComponentId, base_offset: usize, ) -> impl Future>; + /// Build and send UpdateOfferContent command with first block flag fn process_first_data_block( &mut self, w: &mut W, chunk: DataChunk, ) -> impl Future>; + /// Build and send UpdateOfferContent command, no special flags fn process_middle_data_block( &mut self, @@ -50,6 +55,7 @@ where chunk: DataChunk, seq_num: usize, ) -> impl Future>; + /// Build and send UpdateOfferContent command with last block flag fn process_last_data_block( &mut self, @@ -60,9 +66,9 @@ where } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct CfuUpdater {} +pub struct CfuUpdater; -impl CfuUpdateContent for CfuUpdater { +impl CfuUpdateContent for CfuUpdater { /// Write all chunks of an image async fn write_data_chunks( &mut self, diff --git a/src/lib.rs b/src/lib.rs index db7cf72..1f5a8e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ use core::future::Future; use embedded_io_async::{Read, ReadExactError, Seek, SeekFrom}; -use crate::components::*; use crate::protocol_definitions::*; pub mod client; @@ -11,6 +10,7 @@ pub mod components; pub mod fmt; pub mod host; pub mod protocol_definitions; +pub mod writer; // re-export the error enum pub use CfuProtocolError::*; @@ -42,93 +42,4 @@ pub async fn read_from_exact( image.read_exact(buf).await } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CfuWriterError { - StorageError, - ByteConversionError, - Other, -} - -/// This is a temporary change and will be revisited later -pub trait CfuWriterMut { - /// writes a chunk of data to a component and reads back to another buffer - fn cfu_write_read( - &mut self, - mem_offset: Option, - data: &[u8], - read: &mut [u8], - ) -> impl Future>; - /// Fills a given buffer with data from the component - fn cfu_read( - &mut self, - mem_offset: Option, - read: &mut [u8], - ) -> impl Future>; - /// Writes a given buffer of data to a component - /// Note: we don't need cfu_write as cfu_storage may replace it. - fn cfu_write(&mut self, mem_offset: Option, data: &[u8]) - -> impl Future>; - /// Manages erasing sectors and writing pages into flash based on the CFU offset - fn cfu_storage(&mut self, mem_offset: usize, data: &[u8]) -> impl Future>; -} - -/// Trait to define R/W behavior for driver that can talk to a CFU component or client -pub trait CfuWriter { - /// writes a chunk of data to a component and reads back to another buffer - fn cfu_write_read( - &self, - mem_offset: Option, - data: &[u8], - read: &mut [u8], - ) -> impl Future>; - /// Fills a given buffer with data from the component - fn cfu_read(&self, mem_offset: Option, read: &mut [u8]) -> impl Future>; - /// Writes a given buffer of data to a component - fn cfu_write(&self, mem_offset: Option, data: &[u8]) -> impl Future>; -} - pub type DataChunk = [u8; DEFAULT_DATA_LENGTH]; - -#[derive(Copy, Clone)] -pub struct CfuWriterDefault {} - -impl CfuWriterDefault { - /// Create new instance - pub fn new() -> Self { - Self {} - } -} - -impl Default for CfuWriterDefault { - /// Creates default instance of CfuWriterDefault - fn default() -> Self { - Self::new() - } -} - -impl CfuWriter for CfuWriterDefault { - /// writes a chunk of data to a component and reads back to another buffer - async fn cfu_write_read(&self, offset: Option, write: &[u8], read: &mut [u8]) -> Result<(), CfuWriterError> { - // TODO: add with_timeout to these calls - self.cfu_write(offset, write).await?; - self.cfu_read(offset, read).await?; - Ok(()) - } - /// Fills a given buffer with 0xBE 0xEF alternating bytes - async fn cfu_read(&self, _offset: Option, read: &mut [u8]) -> Result<(), CfuWriterError> { - info!("Fake reading from component"); - for (i, byte) in read.iter_mut().enumerate() { - if i % 2 == 0 { - *byte = 0xEF; - } else { - *byte = 0xBE; - } - } - Ok(()) - } - async fn cfu_write(&self, _offset: Option, write: &[u8]) -> Result<(), CfuWriterError> { - info!("Fake writing to component: {:?}", write); - Ok(()) - } -} diff --git a/src/protocol_definitions.rs b/src/protocol_definitions.rs index 86e5a17..18697e9 100644 --- a/src/protocol_definitions.rs +++ b/src/protocol_definitions.rs @@ -1,6 +1,6 @@ use core::convert::TryFrom; -use crate::CfuWriterError; +use crate::writer::CfuWriterError; // Max is 7 components in CfuUpdateOfferResponse, 1 primary and 6 subcomponents pub const MAX_CMPT_COUNT: usize = 7; diff --git a/src/writer.rs b/src/writer.rs new file mode 100644 index 0000000..6fd2dff --- /dev/null +++ b/src/writer.rs @@ -0,0 +1,94 @@ +//! This module defines traits use to read and write data to CFU component or client. + +use core::future::Future; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CfuWriterError { + StorageError, + ByteConversionError, + Other, +} + +/// Trait to define R/W behavior for driver that can talk to a CFU component or client +pub trait CfuWriterAsync { + /// writes a chunk of data to a component and reads back to another buffer + fn cfu_write_read( + &mut self, + mem_offset: Option, + data: &[u8], + read: &mut [u8], + ) -> impl Future>; + + /// Fills a given buffer with data from the component + fn cfu_read( + &mut self, + mem_offset: Option, + read: &mut [u8], + ) -> impl Future>; + + /// Writes a given buffer of data to a component + fn cfu_write(&mut self, mem_offset: Option, data: &[u8]) + -> impl Future>; + + /// Manages erasing sectors and writing pages into flash based on the CFU offset + fn cfu_storage(&mut self, mem_offset: usize, data: &[u8]) -> impl Future>; +} + +/// Trait to define R/W behavior for driver that can talk to a CFU component or client +pub trait CfuWriterSync { + /// writes a chunk of data to a component and reads back to another buffer + fn cfu_write_read(&self, mem_offset: Option, data: &[u8], read: &mut [u8]) -> Result<(), CfuWriterError>; + + /// Fills a given buffer with data from the component + fn cfu_read(&mut self, mem_offset: Option, read: &mut [u8]) -> Result<(), CfuWriterError>; + + /// Writes a given buffer of data to a component + fn cfu_write(&mut self, mem_offset: Option, data: &[u8]) -> Result<(), CfuWriterError>; + + /// Manages erasing sectors and writing pages into flash based on the CFU offset + fn cfu_storage(&mut self, mem_offset: usize, data: &[u8]) -> Result<(), CfuWriterError>; +} + +pub struct CfuWriterNop; + +impl CfuWriterAsync for CfuWriterNop { + async fn cfu_write_read( + &mut self, + _mem_offset: Option, + _data: &[u8], + _read: &mut [u8], + ) -> Result<(), CfuWriterError> { + Ok(()) + } + + async fn cfu_read(&mut self, _mem_offset: Option, _read: &mut [u8]) -> Result<(), CfuWriterError> { + Ok(()) + } + + async fn cfu_write(&mut self, _mem_offset: Option, _data: &[u8]) -> Result<(), CfuWriterError> { + Ok(()) + } + + async fn cfu_storage(&mut self, _mem_offset: usize, _data: &[u8]) -> Result<(), CfuWriterError> { + Ok(()) + } +} + +impl CfuWriterSync for CfuWriterNop { + fn cfu_write_read(&self, _mem_offset: Option, _data: &[u8], _read: &mut [u8]) -> Result<(), CfuWriterError> { + Ok(()) + } + + fn cfu_read(&mut self, _mem_offset: Option, _read: &mut [u8]) -> Result<(), CfuWriterError> { + Ok(()) + } + + fn cfu_write(&mut self, _mem_offset: Option, _data: &[u8]) -> Result<(), CfuWriterError> { + Ok(()) + } + + fn cfu_storage(&mut self, _mem_offset: usize, _data: &[u8]) -> Result<(), CfuWriterError> { + Ok(()) + } +} From 92da99b024864849f788685834b745e91f8dc83b Mon Sep 17 00:00:00 2001 From: Mathieu Gravel Date: Mon, 16 Jun 2025 14:22:18 -0700 Subject: [PATCH 2/2] increment version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 85b7ec9..2766d8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embedded-cfu-protocol" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies]