Skip to content

Commit

Permalink
Documentation pass
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertZ2011 committed Feb 4, 2025
1 parent d0f4b1e commit c110769
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 6 deletions.
19 changes: 17 additions & 2 deletions src/asynchronous/embassy/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! This module contains a high-level API uses embassy synchronization types
use core::iter::zip;
use core::sync::atomic::AtomicBool;

Expand Down Expand Up @@ -26,14 +27,20 @@ pub mod controller {

use super::*;

/// Controller struct. This struct is meant to be created and then immediately broken into its parts
pub struct Controller<M: RawMutex, B: I2c> {
/// Low-level TPS6699x driver
pub(super) inner: Mutex<M, internal::Tps6699x<B>>,
/// Signal for awaiting an interrupt
pub(super) interrupt_waker: Signal<M, [IntEventBus1; MAX_SUPPORTED_PORTS]>,
/// Current interrupt state
pub(super) interrupts_enabled: [AtomicBool; MAX_SUPPORTED_PORTS],
/// Number of active ports
pub(super) num_ports: usize,
}

impl<M: RawMutex, B: I2c> Controller<M, B> {
/// Private constructor
pub fn new(bus: B, addr: [u8; MAX_SUPPORTED_PORTS], num_ports: usize) -> Result<Self, Error<B::Error>> {
Ok(Self {
inner: Mutex::new(internal::Tps6699x::new(bus, addr, num_ports)),
Expand All @@ -43,26 +50,31 @@ pub mod controller {
})
}

/// Create a new controller for the TPS66993
pub fn new_tps66993(bus: B, addr: u8) -> Result<Self, Error<B::Error>> {
Self::new(bus, [addr, 0], TPS66993_NUM_PORTS)
}

/// Create a new controller for the TPS66994
pub fn new_tps66994(bus: B, addr: [u8; TPS66994_NUM_PORTS]) -> Result<Self, Error<B::Error>> {
Self::new(bus, addr, TPS66994_NUM_PORTS)
}

/// Breaks the controller into its parts
pub fn make_parts(&mut self) -> (Tps6699x<'_, M, B>, Interrupt<'_, M, B>) {
let tps = Tps6699x { controller: self };
let interrupt = Interrupt { controller: self };
(tps, interrupt)
}

/// Enable or disable interrupts for the given ports
pub(super) fn enable_interrupts(&self, enabled: [bool; MAX_SUPPORTED_PORTS]) {
for (enabled, s) in zip(enabled.iter(), self.interrupts_enabled.iter()) {
s.store(*enabled, core::sync::atomic::Ordering::SeqCst);
}
}

/// Returns current interrupt state
pub(super) fn interrupts_enabled(&self) -> [bool; MAX_SUPPORTED_PORTS] {
let mut interrupts_enabled = [false; MAX_SUPPORTED_PORTS];
for (copy, enabled) in zip(interrupts_enabled.iter_mut(), self.interrupts_enabled.iter()) {
Expand All @@ -74,11 +86,13 @@ pub mod controller {
}
}

/// Struct for controlling a TP6699x device
pub struct Tps6699x<'a, M: RawMutex, B: I2c> {
controller: &'a controller::Controller<M, B>,
}

impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> {
/// Locks the inner device
async fn lock_inner(&mut self) -> MutexGuard<'_, M, internal::Tps6699x<B>> {
self.controller.inner.lock().await
}
Expand Down Expand Up @@ -119,6 +133,7 @@ impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> {
self.lock_inner().await.get_customer_use().await
}

/// Returns the number of ports
pub fn num_ports(&self) -> usize {
self.controller.num_ports
}
Expand Down Expand Up @@ -166,7 +181,6 @@ impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> {
}

/// Execute the given command with a timeout
#[allow(dead_code)]
async fn execute_command(
&mut self,
port: PortId,
Expand Down Expand Up @@ -224,6 +238,7 @@ impl<'a, M: RawMutex, B: I2c> Interrupt<'a, M, B> {
self.controller.inner.lock().await
}

/// Process interrupts
pub async fn process_interrupt(
&mut self,
int: &mut impl InputPin,
Expand All @@ -240,13 +255,13 @@ impl<'a, M: RawMutex, B: I2c> Interrupt<'a, M, B> {
continue;
}

// Early exit if checking the last port cleared the interrupt
let result = int.is_high();
if result.is_err() {
error!("Failed to read interrupt line");
return PdError::Failed.into();
}

// Early exit if checking the last port cleared the interrupt
if result.unwrap() {
continue;
}
Expand Down
1 change: 1 addition & 0 deletions src/asynchronous/embassy/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use embedded_hal_async::i2c::I2c;
use super::Interrupt;
use crate::{error, warn};

/// Task to process all given interrupts
pub async fn interrupt_task<const N: usize, M: RawMutex, B: I2c, INT: Wait + InputPin>(
int: &mut INT,
mut interrupts: [&mut Interrupt<'_, M, B>; N],
Expand Down
25 changes: 24 additions & 1 deletion src/asynchronous/fw_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,46 @@ use crate::{error, info, warn, PORT0};

/// Trait for updating the firmware of a target device
pub trait UpdateTarget: InterruptController {
/// Enter FW update mode
fn fw_update_mode_enter(
&mut self,
delay: &mut impl DelayNs,
) -> impl Future<Output = Result<(), DeviceError<Self::BusError>>>;

/// Start FW update
fn fw_update_init(
&mut self,
delay: &mut impl DelayNs,
args: &TfuiArgs,
) -> impl Future<Output = Result<ReturnValue, DeviceError<Self::BusError>>>;

/// Abort FW update
fn fw_update_mode_exit(
&mut self,
delay: &mut impl DelayNs,
) -> impl Future<Output = Result<(), DeviceError<Self::BusError>>>;

/// Validate the most recent block supplied to the device
fn fw_update_validate_stream(
&mut self,
delay: &mut impl DelayNs,
block_index: usize,
) -> impl Future<Output = Result<TfuqBlockStatus, DeviceError<Self::BusError>>>;

/// Stream a block to the device
fn fw_update_stream_data(
&mut self,
delay: &mut impl DelayNs,
args: &TfudArgs,
) -> impl Future<Output = Result<(), DeviceError<Self::BusError>>>;

/// Complete the FW update process
fn fw_update_complete(
&mut self,
delay: &mut impl DelayNs,
) -> impl Future<Output = Result<(), DeviceError<Self::BusError>>>;

/// Write data to all supplied devices
fn fw_update_burst_write(
&mut self,
address: u8,
Expand All @@ -50,6 +63,7 @@ pub trait UpdateTarget: InterruptController {
/// Trait for anything that can be used as an image for firmware update
pub trait Image: Read + Seek {}

/// Error type for the firmware update process
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error<T: UpdateTarget, I: Image> {
Expand Down Expand Up @@ -134,6 +148,7 @@ async fn fw_update_init<T: UpdateTarget, I: Image>(
let (args, _) = bincode::decode_from_slice(&arg_bytes, config::standard().with_fixed_int_encoding())
.map_err(|_| Error::Pd(PdError::Serialize))?;

// Initialize FW update on all controllers
for (i, controller) in controllers.iter_mut().enumerate() {
info!("Controller {}: Initializing FW update", i);

Expand All @@ -158,6 +173,7 @@ async fn fw_update_init<T: UpdateTarget, I: Image>(
.await
.map_err(Error::Io)?;

// Supply the header block to all controllers
info!("Broadcasting header block");
for _ in 0..HEADER_BLOCK_LEN / BURST_WRITE_SIZE {
image.read_exact(&mut buf).await.map_err(Error::ReadExact)?;
Expand All @@ -169,6 +185,7 @@ async fn fw_update_init<T: UpdateTarget, I: Image>(

delay.delay_ms(TFUI_BURST_WRITE_DELAY_MS).await;

// Validate the block on all controllers
for (i, controller) in controllers.iter_mut().enumerate() {
info!("Controller {}: Validating header block", i);
match controller.fw_update_validate_stream(delay, HEADER_BLOCK_INDEX).await {
Expand All @@ -189,25 +206,29 @@ async fn fw_update_init<T: UpdateTarget, I: Image>(
Ok(args)
}

/// Computes the offset of a data block's metadata
const fn data_block_metadata_offset(block: usize) -> usize {
HEADER_BLOCK_OFFSET + HEADER_BLOCK_LEN + (block * (DATA_BLOCK_LEN + DATA_BLOCK_METADATA_LEN))
}

/// Computes the offset of a data block's data
const fn block_offset(metadata_offset: usize) -> usize {
metadata_offset + DATA_BLOCK_METADATA_LEN
}

/// Computes the offset of the app config block's metadata
const fn app_config_block_metadata_offset(num_data_blocks: usize, app_size: usize) -> usize {
app_size + IMAGE_ID_LEN + HEADER_METADATA_LEN + HEADER_BLOCK_LEN + num_data_blocks * DATA_BLOCK_METADATA_LEN
}

/// Get the size of the image
async fn get_image_size<I: Image>(image: &mut I) -> Result<usize, ReadExactError<I::Error>> {
let mut image_size_data = [0; 4];
read_from_exact(image, APP_IMAGE_SIZE_OFFSET, &mut image_size_data).await?;
Ok(u32::from_le_bytes(image_size_data) as usize)
}

// Data block indices start at 1
/// Converts a data block into a block index
fn data_block_index_to_block_index(block_index: usize) -> usize {
block_index + DATA_BLOCK_START_INDEX
}
Expand All @@ -227,6 +248,7 @@ async fn fw_update_stream_data<T: UpdateTarget, I: Image>(

let mut arg_bytes = [0u8; MAX_METADATA_LEN];

// Get TFUd args from image
read_from_exact(image, metadata_offset, &mut arg_bytes[..metadata_size])
.await
.map_err(Error::ReadExact)?;
Expand Down Expand Up @@ -262,6 +284,7 @@ async fn fw_update_stream_data<T: UpdateTarget, I: Image>(

delay.delay_ms(TFUD_BURST_WRITE_DELAY_MS).await;

// Validate the block on all controllers
for (i, controller) in controllers.iter_mut().enumerate() {
info!("Controller {}: Validating block {}", i, block_index);
match controller.fw_update_validate_stream(delay, block_index).await {
Expand Down
2 changes: 2 additions & 0 deletions src/asynchronous/internal/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ impl<B: I2c> Tps6699x<B> {
Ok(())
}

/// Check if the command has completed
pub async fn check_command_complete(&mut self, port: PortId) -> Result<bool, Error<B::Error>> {
let mut registers = self.borrow_port(port)?.into_registers();
let status = registers.cmd_1().read_async().await?.command();

Ok(Command::Success == status)
}

/// Read the result of a command
pub async fn read_command_result(
&mut self,
port: PortId,
Expand Down
2 changes: 1 addition & 1 deletion src/asynchronous/internal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Asynchronous TPS6699x driver
//! Asynchronous, low-level TPS6699x driver. This module provides a low-level interface
use embedded_hal_async::i2c::I2c;
use embedded_usb_pd::{Error, PdError, PortId};

Expand Down
24 changes: 22 additions & 2 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use bincode::error::{DecodeError, EncodeError};
use bincode::{Decode, Encode};
use embedded_usb_pd::PdError;

/// Length of a command
const CMD_LEN: usize = 4;

/// Converts a 4-byte string into a u32
Expand Down Expand Up @@ -132,15 +133,20 @@ impl Into<Result<(), PdError>> for ReturnValue {
}
}

/// Delay to wait for the device to restart
pub(crate) const RESET_DELAY_MS: u32 = 1600;
/// Length of arguments for the reset command
pub(crate) const RESET_ARGS_LEN: usize = 2;
/// Constant to enable a feature in the command args
pub(crate) const RESET_FEATURE_ENABLE: u8 = 0xAC;

/// Arugments to reset-like commands
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ResetArgs {
/// True to swap banks on reset
pub switch_banks: bool,
/// True to copy the backup bank to the active bank
pub copy_bank: bool,
}
impl Encode for ResetArgs {
Expand All @@ -157,20 +163,26 @@ pub(crate) const TFUS_DELAY_MS: u32 = 500;
/// Timeout for completion of TFUs command
#[allow(dead_code)]
pub(crate) const TFUS_TIMEOUT_MS: u32 = TFUS_DELAY_MS + 100;
/// Timeout for completion of TFUi command
#[allow(dead_code)]
pub(crate) const TFUI_TIMEOUT_MS: u32 = 100;
/// Timeout for completion of TFUe command
#[allow(dead_code)]
pub(crate) const TFUE_TIMEOUT_MS: u32 = 100;
/// Timeout for completion of TFUd command
#[allow(dead_code)]
pub(crate) const TFUD_TIMEOUT_MS: u32 = 100;
/// Timeout for completion of TFUq command
#[allow(dead_code)]
pub(crate) const TFUQ_TIMEOUT_MS: u32 = 100;
/// Timeout for completion of reset
#[allow(dead_code)]
pub(crate) const RESET_TIMEOUT_MS: u32 = RESET_DELAY_MS + 100;

/// Length of TFUi arguments
#[allow(dead_code)]
pub(crate) const TFUI_ARGS_LEN: usize = 8;

/// Arguments for TFUi command
#[derive(Debug, Clone, Copy, Decode, Encode, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TfuiArgs {
Expand All @@ -180,6 +192,7 @@ pub struct TfuiArgs {
pub broadcast_u16_address: u16,
}

/// Command type for TFUq command
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
Expand All @@ -194,6 +207,7 @@ impl Encode for TfuqCommandType {
}
}

/// Status we're checking for in the TFUq command
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
Expand All @@ -211,6 +225,7 @@ impl Encode for TfuqStatusQuery {
}
}

/// Status of a block supplied to device
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
Expand Down Expand Up @@ -288,21 +303,26 @@ impl Decode for TfuqBlockStatus {
}
}

/// Length of TFUq args
#[allow(dead_code)]
pub(crate) const TFUQ_ARGS_LEN: usize = 2;

/// Arguments for TFUq command
#[derive(Debug, Encode, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TfuqArgs {
pub status_query: TfuqStatusQuery,
pub command: TfuqCommandType,
}

/// Length of return data from TFUq command
#[allow(dead_code)]
pub(crate) const TFUQ_RETURN_LEN: usize = 40;
/// Number of block statuses present in TFUq return data
#[allow(dead_code)]
pub(crate) const TFUQ_RETURN_BLOCK_STATUS_LEN: usize = 13;

/// Return data from TFUq command
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TfuqReturnValue {
Expand Down Expand Up @@ -346,7 +366,7 @@ impl Decode for TfuqReturnValue {
}
}

#[allow(dead_code)]
/// Arguments for TFUd command
pub(crate) const TFUD_ARGS_LEN: usize = 8;
#[derive(Debug, Decode, Encode, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down
Loading

0 comments on commit c110769

Please sign in to comment.