Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ embassy-sync = "0.7.2"
embassy-time = "0.5.0"
embassy-time-driver = "0.2.1"
embedded-batteries-async = "0.3"
cfu-service = { path = "./cfu-service" }
embedded-cfu-protocol = { git = "https://github.com/OpenDevicePartnership/embedded-cfu" }
embedded-hal = "1.0"
embedded-hal-async = "1.0"
Expand Down
88 changes: 57 additions & 31 deletions cfu-service/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@ use embassy_sync::{
};
use embassy_time::{Duration, TimeoutError, with_timeout};
use embedded_cfu_protocol::protocol_definitions::*;
use embedded_services::{
GlobalRawMutex,
cfu::{
self,
component::{CfuDevice, InternalResponseData, RequestData},
},
error, intrusive_list, trace,
};
use embedded_services::{GlobalRawMutex, error, intrusive_list, trace};

use crate::component::{CfuDevice, InternalResponseData, RequestData};

/// Internal state for [`Buffer`]
#[derive(Copy, Clone, Default)]
Expand Down Expand Up @@ -115,9 +110,11 @@ impl<'a> Buffer<'a> {
}

/// Process a fw version request
async fn process_get_fw_version(&self) -> InternalResponseData {
if let Ok(InternalResponseData::FwVersionResponse(mut response)) =
cfu::route_request(self.buffered_id, RequestData::FwVersionRequest).await
async fn process_get_fw_version(&self, cfu_client: &crate::CfuClient) -> InternalResponseData {
if let Ok(InternalResponseData::FwVersionResponse(mut response)) = cfu_client
.context
.route_request(self.buffered_id, RequestData::FwVersionRequest)
.await
{
// Update the component ID in the response to match our external ID
response.component_info[0].component_id = self.cfu_device.component_id();
Expand All @@ -128,8 +125,12 @@ impl<'a> Buffer<'a> {
}
}

async fn process_abort_update(&self) -> InternalResponseData {
match cfu::route_request(self.buffered_id, RequestData::AbortUpdate).await {
async fn process_abort_update(&self, cfu_client: &crate::CfuClient) -> InternalResponseData {
match cfu_client
.context
.route_request(self.buffered_id, RequestData::AbortUpdate)
.await
{
Ok(response) => response,
Err(e) => {
error!("Failed to abort update for device {}: {:?}", self.buffered_id, e);
Expand All @@ -139,11 +140,13 @@ impl<'a> Buffer<'a> {
}

/// Process a give offer request
async fn process_give_offer(&self, offer: &FwUpdateOffer) -> InternalResponseData {
async fn process_give_offer(&self, offer: &FwUpdateOffer, cfu_client: &crate::CfuClient) -> InternalResponseData {
let mut offer = *offer;
offer.component_info.component_id = self.buffered_id;
if let Ok(response @ InternalResponseData::OfferResponse(_)) =
cfu::route_request(self.buffered_id, RequestData::GiveOffer(offer)).await
if let Ok(response @ InternalResponseData::OfferResponse(_)) = cfu_client
.context
.route_request(self.buffered_id, RequestData::GiveOffer(offer))
.await
{
response
} else {
Expand All @@ -157,7 +160,12 @@ impl<'a> Buffer<'a> {
}

/// Process update content
async fn process_give_content(&self, state: &mut State, content: &FwUpdateContentCommand) -> InternalResponseData {
async fn process_give_content(
&self,
state: &mut State,
content: &FwUpdateContentCommand,
cfu_client: &crate::CfuClient,
) -> InternalResponseData {
// Clear out any pending response if this is a new FW update
if content.header.flags & FW_UPDATE_FLAG_FIRST_BLOCK != 0 {
state.pending_response = None;
Expand All @@ -171,7 +179,11 @@ impl<'a> Buffer<'a> {
trace!("Content successfully buffered");
} else {
// Buffered component can accept new content, send it
if let Err(e) = cfu::send_device_request(self.buffered_id, RequestData::GiveContent(*content)).await {
if let Err(e) = cfu_client
.context
.send_device_request(self.buffered_id, RequestData::GiveContent(*content))
.await
{
error!(
"Failed to send content to buffered component {:?}: {:?}",
self.buffered_id, e
Expand All @@ -181,7 +193,12 @@ impl<'a> Buffer<'a> {
}

// Wait for a response from the buffered component
match with_timeout(self.config.buffer_timeout, cfu::wait_device_response(self.buffered_id)).await {
match with_timeout(
self.config.buffer_timeout,
cfu_client.context.wait_device_response(self.buffered_id),
)
.await
{
Err(TimeoutError) => {
// Component didn't respond in time
state.component_busy = true;
Expand Down Expand Up @@ -242,15 +259,15 @@ impl<'a> Buffer<'a> {
}

/// Wait for an event
pub async fn wait_event(&self) -> Event {
pub async fn wait_event(&self, cfu_client: &crate::CfuClient) -> Event {
let is_busy = self.state.lock().await.component_busy;
match select3(
// Wait for a buffered content request
self.wait_buffered_content(is_busy),
// Wait for a request from the host
self.cfu_device.wait_request(),
// Wait for response from the buffered component
cfu::wait_device_response(self.buffered_id),
cfu_client.context.wait_device_response(self.buffered_id),
)
.await
{
Expand All @@ -275,14 +292,18 @@ impl<'a> Buffer<'a> {
}

/// Top-level event processing function
pub async fn process(&self, event: Event) -> Option<InternalResponseData> {
pub async fn process(&self, event: Event, cfu_client: &crate::CfuClient) -> Option<InternalResponseData> {
let mut state = self.state.lock().await;
match event {
Event::CfuRequest(request) => Some(self.process_request(&mut state, request).await),
Event::CfuRequest(request) => Some(self.process_request(&mut state, request, cfu_client).await),
Event::BufferedContent(content) => {
// Send the buffered content to the component
// Don't need to wait for a response here, the response will be caught later by either [`wait_event`] or [`process_give_content`]
if let Err(e) = cfu::send_device_request(self.buffered_id, RequestData::GiveContent(content)).await {
if let Err(e) = cfu_client
.context
.send_device_request(self.buffered_id, RequestData::GiveContent(content))
.await
{
error!(
"Failed to send content to buffered component {:?}: {:?}",
self.buffered_id, e
Expand All @@ -303,23 +324,28 @@ impl<'a> Buffer<'a> {
}

/// Process a CFU message and produce a response
async fn process_request(&self, state: &mut State, request: RequestData) -> InternalResponseData {
async fn process_request(
&self,
state: &mut State,
request: RequestData,
cfu_client: &crate::CfuClient,
) -> InternalResponseData {
match request {
RequestData::FwVersionRequest => {
trace!("Got FwVersionRequest");
self.process_get_fw_version().await
self.process_get_fw_version(cfu_client).await
}
RequestData::GiveOffer(offer) => {
trace!("Got GiveOffer");
self.process_give_offer(&offer).await
self.process_give_offer(&offer, cfu_client).await
}
RequestData::GiveContent(content) => {
trace!("Got GiveContent");
self.process_give_content(state, &content).await
self.process_give_content(state, &content, cfu_client).await
}
RequestData::AbortUpdate => {
trace!("Got AbortUpdate");
self.process_abort_update().await
self.process_abort_update(cfu_client).await
}
RequestData::FinalizeUpdate => {
trace!("Got FinalizeUpdate");
Expand Down Expand Up @@ -356,7 +382,7 @@ impl<'a> Buffer<'a> {
}

/// Register the buffer with all relevant services
pub async fn register(&'static self) -> Result<(), intrusive_list::Error> {
cfu::register_device(&self.cfu_device).await
pub fn register(&'static self, cfu_client: &crate::CfuClient) -> Result<(), intrusive_list::Error> {
cfu_client.context.register_device(&self.cfu_device)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ use embedded_cfu_protocol::writer::{CfuWriterAsync, CfuWriterError};
use heapless::Vec;

use super::CfuError;
use crate::GlobalRawMutex;
use crate::cfu::route_request;
use crate::intrusive_list;
use embedded_services::GlobalRawMutex;
use embedded_services::intrusive_list;

/// Component internal update state
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -222,7 +221,7 @@ impl<W: CfuWriterAsync> CfuComponentDefault<W> {
}
}
/// wait for a request and process it
pub async fn process_request(&self) -> Result<(), CfuError> {
pub async fn process_request(&self, cfu_client: &'static crate::CfuClient) -> Result<(), CfuError> {
match self.device.wait_request().await {
RequestData::FwVersionRequest => {
let fwv = self.get_fw_version().await.map_err(CfuError::ProtocolError)?;
Expand All @@ -247,8 +246,10 @@ impl<W: CfuWriterAsync> CfuComponentDefault<W> {
// panic safety: adding 1 here is safe because MAX_CMPT_COUNT is 1 more than MAX_SUBCMPT_COUNT
for (index, id) in arr.iter().enumerate() {
//info!("Forwarding GetFwVersion command to sub-component: {}", id);
if let InternalResponseData::FwVersionResponse(fwv) =
route_request(*id, RequestData::FwVersionRequest).await?
if let InternalResponseData::FwVersionResponse(fwv) = cfu_client
.context
.route_request(*id, RequestData::FwVersionRequest)
.await?
{
comp_info[index + 1] = fwv
.component_info
Expand Down
Loading