From b092362720c8d95a516473633914032804bb018f Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 10:01:41 -0700 Subject: [PATCH 1/9] type-c-interface: Move controller trait into own module, clean-up types Move the `Controller` trait into its own module, and create a dedicated module for types used as arguments/return values for various PD functions. --- examples/rt685s-evk/src/bin/type_c.rs | 3 +- examples/rt685s-evk/src/bin/type_c_cfu.rs | 3 +- examples/std/src/bin/type_c/basic.rs | 5 +- examples/std/src/bin/type_c/service.rs | 3 +- examples/std/src/bin/type_c/ucsi.rs | 3 +- examples/std/src/bin/type_c/unconstrained.rs | 2 +- .../std/src/lib/type_c/mock_controller.rs | 17 +- type-c-interface/src/control/dp.rs | 32 ++ type-c-interface/src/control/mod.rs | 9 + type-c-interface/src/control/pd.rs | 84 ++++ type-c-interface/src/control/power.rs | 20 + type-c-interface/src/control/retimer.rs | 11 + type-c-interface/src/control/tbt.rs | 9 + type-c-interface/src/control/type_c.rs | 15 + type-c-interface/src/control/usb.rs | 23 + type-c-interface/src/control/vdm.rs | 93 ++++ type-c-interface/src/controller/mod.rs | 172 +++++++ type-c-interface/src/lib.rs | 2 + type-c-interface/src/port/mod.rs | 449 +----------------- type-c-interface/src/service/context.rs | 14 +- type-c-interface/src/service/event.rs | 6 +- type-c-service/src/bridge/mod.rs | 7 +- type-c-service/src/controller/mod.rs | 7 +- type-c-service/src/controller/pd.rs | 5 +- type-c-service/src/controller/power.rs | 1 - type-c-service/src/driver/tps6699x.rs | 16 +- type-c-service/src/service/mod.rs | 3 +- type-c-service/src/service/vdm.rs | 2 +- 28 files changed, 535 insertions(+), 481 deletions(-) create mode 100644 type-c-interface/src/control/dp.rs create mode 100644 type-c-interface/src/control/mod.rs create mode 100644 type-c-interface/src/control/pd.rs create mode 100644 type-c-interface/src/control/power.rs create mode 100644 type-c-interface/src/control/retimer.rs create mode 100644 type-c-interface/src/control/tbt.rs create mode 100644 type-c-interface/src/control/type_c.rs create mode 100644 type-c-interface/src/control/usb.rs create mode 100644 type-c-interface/src/control/vdm.rs create mode 100644 type-c-interface/src/controller/mod.rs diff --git a/examples/rt685s-evk/src/bin/type_c.rs b/examples/rt685s-evk/src/bin/type_c.rs index cba3c6c60..755124076 100644 --- a/examples/rt685s-evk/src/bin/type_c.rs +++ b/examples/rt685s-evk/src/bin/type_c.rs @@ -21,9 +21,10 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; +use type_c_interface::controller::ControllerId; +use type_c_interface::port::Device; use type_c_interface::port::PortRegistration; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::bridge::Bridge; use type_c_service::bridge::event_receiver::EventReceiver as BridgeEventReceiver; diff --git a/examples/rt685s-evk/src/bin/type_c_cfu.rs b/examples/rt685s-evk/src/bin/type_c_cfu.rs index 1a9355bf4..622336de8 100644 --- a/examples/rt685s-evk/src/bin/type_c_cfu.rs +++ b/examples/rt685s-evk/src/bin/type_c_cfu.rs @@ -28,8 +28,9 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::bridge::Bridge; use type_c_service::bridge::event_receiver::EventReceiver as BridgeEventReceiver; diff --git a/examples/std/src/bin/type_c/basic.rs b/examples/std/src/bin/type_c/basic.rs index 69f811316..9422bb2de 100644 --- a/examples/std/src/bin/type_c/basic.rs +++ b/examples/std/src/bin/type_c/basic.rs @@ -6,7 +6,8 @@ use embedded_services::GlobalRawMutex; use embedded_usb_pd::{GlobalPortId, PdError as Error}; use log::*; use static_cell::StaticCell; -use type_c_interface::port::{self, ControllerId, PortRegistration}; +use type_c_interface::controller::{ControllerId, ControllerStatus}; +use type_c_interface::port::{self, PortRegistration}; use type_c_interface::service::context::{Context, DeviceContainer}; use type_c_interface::service::event::PortEvent as ServicePortEvent; @@ -16,7 +17,7 @@ const PORT1_ID: GlobalPortId = GlobalPortId(1); const CHANNEL_CAPACITY: usize = 4; mod test_controller { - use type_c_interface::port::{ControllerStatus, PortRegistration}; + use type_c_interface::port::PortRegistration; use super::*; diff --git a/examples/std/src/bin/type_c/service.rs b/examples/std/src/bin/type_c/service.rs index e05b2f18e..008c20e48 100644 --- a/examples/std/src/bin/type_c/service.rs +++ b/examples/std/src/bin/type_c/service.rs @@ -16,8 +16,9 @@ use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::Port; use std_examples::type_c::mock_controller::{self, InterruptReceiver}; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_interface::service::event::PortEventData as ServicePortEventData; use type_c_service::bridge::Bridge; diff --git a/examples/std/src/bin/type_c/ucsi.rs b/examples/std/src/bin/type_c/ucsi.rs index 04f126293..0262d5fd8 100644 --- a/examples/std/src/bin/type_c/ucsi.rs +++ b/examples/std/src/bin/type_c/ucsi.rs @@ -22,8 +22,9 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::{self, InterruptReceiver, Port}; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::context::Context; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; use type_c_service::bridge::Bridge; diff --git a/examples/std/src/bin/type_c/unconstrained.rs b/examples/std/src/bin/type_c/unconstrained.rs index 43b1b686c..8b1191463 100644 --- a/examples/std/src/bin/type_c/unconstrained.rs +++ b/examples/std/src/bin/type_c/unconstrained.rs @@ -17,7 +17,7 @@ use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::Port; use std_examples::type_c::mock_controller::{self, InterruptReceiver}; -use type_c_interface::port::ControllerId; +use type_c_interface::controller::ControllerId; use type_c_interface::port::Device; use type_c_interface::port::PortRegistration; use type_c_interface::port::event::PortEventBitfield; diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index 9ba50dad1..a020a9cfb 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -9,11 +9,16 @@ use embedded_usb_pd::{type_c::ConnectionState, ucsi::lpm}; use log::{debug, info}; use power_policy_interface::capability::PowerCapability; -use type_c_interface::port::SystemPowerState; -use type_c_interface::port::{ - AttnVdm, ControllerStatus, DpConfig, DpPinConfig, DpStatus, OtherVdm, PdStateMachineConfig, PortStatus, - RetimerFwUpdateState, SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, event::PortEventBitfield, -}; +use type_c_interface::control::dp::{DpConfig, DpPinConfig, DpStatus}; +use type_c_interface::control::pd::{PdStateMachineConfig, PortStatus}; +use type_c_interface::control::power::SystemPowerState; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::control::tbt::TbtConfig; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::control::usb::UsbControlConfig; +use type_c_interface::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::controller::ControllerStatus; +use type_c_interface::port::event::PortEventBitfield; use type_c_service::controller::state::SharedState; use type_c_service::util::power_capability_from_current; @@ -129,7 +134,7 @@ impl type_c_service::controller::event_receiver::InterruptReceiv } } -impl type_c_interface::port::Controller for Controller<'_> { +impl type_c_interface::controller::Controller for Controller<'_> { type BusError = (); async fn get_port_status(&mut self, _port: LocalPortId) -> Result> { diff --git a/type-c-interface/src/control/dp.rs b/type-c-interface/src/control/dp.rs new file mode 100644 index 000000000..21c616521 --- /dev/null +++ b/type-c-interface/src/control/dp.rs @@ -0,0 +1,32 @@ +//! DP-related control types +/// DisplayPort pin configuration +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpPinConfig { + /// 4L DP connection using USBC-USBC cable (Pin Assignment C) + pub pin_c: bool, + /// 2L USB + 2L DP connection using USBC-USBC cable (Pin Assignment D) + pub pin_d: bool, + /// 4L DP connection using USBC-DP cable (Pin Assignment E) + pub pin_e: bool, +} + +/// DisplayPort status data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpStatus { + /// DP alt-mode entered + pub alt_mode_entered: bool, + /// Get DP DFP pin config + pub dfp_d_pin_cfg: DpPinConfig, +} + +/// DisplayPort configuration data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpConfig { + /// DP alt-mode enabled + pub enable: bool, + /// Set DP DFP pin config + pub dfp_d_pin_cfg: DpPinConfig, +} diff --git a/type-c-interface/src/control/mod.rs b/type-c-interface/src/control/mod.rs new file mode 100644 index 000000000..05607decc --- /dev/null +++ b/type-c-interface/src/control/mod.rs @@ -0,0 +1,9 @@ +//! Shared types for controlling a PD port +pub mod dp; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod tbt; +pub mod type_c; +pub mod usb; +pub mod vdm; diff --git a/type-c-interface/src/control/pd.rs b/type-c-interface/src/control/pd.rs new file mode 100644 index 000000000..1a9ed6579 --- /dev/null +++ b/type-c-interface/src/control/pd.rs @@ -0,0 +1,84 @@ +//! Control types for code PD functionality + +use embedded_usb_pd::{ + DataRole, PlugOrientation, PowerRole, + pdinfo::{AltMode, PowerPathStatus}, + type_c::ConnectionState, +}; + +/// Port status +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PortStatus { + /// Current available source contract + pub available_source_contract: Option, + /// Current available sink contract + pub available_sink_contract: Option, + /// Current connection state + pub connection_state: Option, + /// Port partner supports dual-power roles + pub dual_power: bool, + /// plug orientation + pub plug_orientation: PlugOrientation, + /// power role + pub power_role: PowerRole, + /// data role + pub data_role: DataRole, + /// Active alt-modes + pub alt_mode: AltMode, + /// Power path status + pub power_path: PowerPathStatus, + /// EPR mode active + pub epr: bool, + /// Port partner is unconstrained + pub unconstrained_power: bool, +} + +impl PortStatus { + /// Create a new blank port status + /// Needed because default() is not const + pub const fn new() -> Self { + Self { + available_source_contract: None, + available_sink_contract: None, + connection_state: None, + dual_power: false, + plug_orientation: PlugOrientation::CC1, + power_role: PowerRole::Sink, + data_role: DataRole::Dfp, + alt_mode: AltMode::none(), + power_path: PowerPathStatus::none(), + epr: false, + unconstrained_power: false, + } + } + + /// Check if the port is connected + pub fn is_connected(&self) -> bool { + matches!( + self.connection_state, + Some(ConnectionState::Attached) + | Some(ConnectionState::DebugAccessory) + | Some(ConnectionState::AudioAccessory) + ) + } + + /// Check if a debug accessory is connected + pub fn is_debug_accessory(&self) -> bool { + matches!(self.connection_state, Some(ConnectionState::DebugAccessory)) + } +} + +impl Default for PortStatus { + fn default() -> Self { + Self::new() + } +} + +/// PD state-machine configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct PdStateMachineConfig { + /// Enable or disable the PD state-machine + pub enabled: bool, +} diff --git a/type-c-interface/src/control/power.rs b/type-c-interface/src/control/power.rs new file mode 100644 index 000000000..e4388e95c --- /dev/null +++ b/type-c-interface/src/control/power.rs @@ -0,0 +1,20 @@ +//! General power related control types + +/// System power state +/// +/// Used to notify the PD controller of the current system power state, +/// which triggers Application Configuration updates (e.g., crossbar reconfiguration). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SystemPowerState { + /// S0 - System fully running + S0, + /// S3 - Suspend to RAM + S3, + /// S4 - Hibernate + S4, + /// S5 - Soft off + S5, + /// S0ix - Modern standby / Connected standby + S0ix, +} diff --git a/type-c-interface/src/control/retimer.rs b/type-c-interface/src/control/retimer.rs new file mode 100644 index 000000000..e3460638d --- /dev/null +++ b/type-c-interface/src/control/retimer.rs @@ -0,0 +1,11 @@ +//! Retimer related control types + +/// Retimer update state +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RetimerFwUpdateState { + /// Retimer FW Update Inactive + Inactive, + /// Retimer FW Update Active + Active, +} diff --git a/type-c-interface/src/control/tbt.rs b/type-c-interface/src/control/tbt.rs new file mode 100644 index 000000000..192ed6c23 --- /dev/null +++ b/type-c-interface/src/control/tbt.rs @@ -0,0 +1,9 @@ +//! Thunderbolt-related control types + +/// Thunderbolt control configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct TbtConfig { + /// Enable Thunderbolt + pub tbt_enabled: bool, +} diff --git a/type-c-interface/src/control/type_c.rs b/type-c-interface/src/control/type_c.rs new file mode 100644 index 000000000..0e13c7b86 --- /dev/null +++ b/type-c-interface/src/control/type_c.rs @@ -0,0 +1,15 @@ +//! Type-C related control types + +/// TypeC State Machine +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TypeCStateMachineState { + /// Sink state machine only + Sink, + /// Source state machine only + Source, + /// DRP state machine + Drp, + /// Disabled + Disabled, +} diff --git a/type-c-interface/src/control/usb.rs b/type-c-interface/src/control/usb.rs new file mode 100644 index 000000000..237eb947d --- /dev/null +++ b/type-c-interface/src/control/usb.rs @@ -0,0 +1,23 @@ +//! USB related control types + +/// USB control configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct UsbControlConfig { + /// Enable USB2 data path + pub usb2_enabled: bool, + /// Enable USB3 data path + pub usb3_enabled: bool, + /// Enable USB4 data path + pub usb4_enabled: bool, +} + +impl Default for UsbControlConfig { + fn default() -> Self { + Self { + usb2_enabled: true, + usb3_enabled: true, + usb4_enabled: true, + } + } +} diff --git a/type-c-interface/src/control/vdm.rs b/type-c-interface/src/control/vdm.rs new file mode 100644 index 000000000..6baecb463 --- /dev/null +++ b/type-c-interface/src/control/vdm.rs @@ -0,0 +1,93 @@ +//! VDM-related control types + +/// Length of the Other VDM data +pub const OTHER_VDM_LEN: usize = 29; +/// Length of the Attention VDM data +pub const ATTN_VDM_LEN: usize = 9; +/// maximum number of data objects in a VDM +pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each + +/// Other Vdm data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OtherVdm { + /// Other VDM data + pub data: [u8; OTHER_VDM_LEN], +} + +impl Default for OtherVdm { + fn default() -> Self { + Self { + data: [0; OTHER_VDM_LEN], + } + } +} + +impl From for [u8; OTHER_VDM_LEN] { + fn from(vdm: OtherVdm) -> Self { + vdm.data + } +} + +impl From<[u8; OTHER_VDM_LEN]> for OtherVdm { + fn from(data: [u8; OTHER_VDM_LEN]) -> Self { + Self { data } + } +} + +/// Attention Vdm data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AttnVdm { + /// Attention VDM data + pub data: [u8; ATTN_VDM_LEN], +} + +impl Default for AttnVdm { + fn default() -> Self { + Self { + data: [0; ATTN_VDM_LEN], + } + } +} + +impl From for [u8; ATTN_VDM_LEN] { + fn from(vdm: AttnVdm) -> Self { + vdm.data + } +} + +impl From<[u8; ATTN_VDM_LEN]> for AttnVdm { + fn from(data: [u8; ATTN_VDM_LEN]) -> Self { + Self { data } + } +} + +/// Send VDM data +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SendVdm { + /// initiating a VDM sequence + pub initiator: bool, + /// VDO count + pub vdo_count: u8, + /// VDO data + pub vdo_data: [u32; MAX_NUM_DATA_OBJECTS], +} + +impl SendVdm { + /// Create a new blank port status + pub const fn new() -> Self { + Self { + initiator: false, + vdo_count: 0, + vdo_data: [0; MAX_NUM_DATA_OBJECTS], + } + } +} + +impl Default for SendVdm { + fn default() -> Self { + Self::new() + } +} diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs new file mode 100644 index 000000000..b7f223439 --- /dev/null +++ b/type-c-interface/src/controller/mod.rs @@ -0,0 +1,172 @@ +//! Module for PD controller related code +use core::future::Future; +use core::num::NonZeroU8; + +use embedded_usb_pd::ado::Ado; +use embedded_usb_pd::{Error, LocalPortId, ucsi::lpm}; + +use crate::control::dp::{DpConfig, DpStatus}; +use crate::control::pd::{PdStateMachineConfig, PortStatus}; +use crate::control::power::SystemPowerState; +use crate::control::retimer::RetimerFwUpdateState; +use crate::control::tbt::TbtConfig; +use crate::control::type_c::TypeCStateMachineState; +use crate::control::usb::UsbControlConfig; +use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; + +/// Controller status +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControllerStatus<'a> { + /// Current controller mode + pub mode: &'a str, + /// True if we did not have to boot from a backup FW bank + pub valid_fw_bank: bool, + /// FW version 0 + pub fw_version0: u32, + /// FW version 1 + pub fw_version1: u32, +} + +/// Controller ID +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControllerId(pub u8); + +/// PD controller trait +pub trait Controller { + /// Type of error returned by the bus + type BusError; + + /// Returns the port status + fn get_port_status(&mut self, port: LocalPortId) + -> impl Future>>; + + /// Reset the controller + fn reset_controller(&mut self) -> impl Future>>; + + /// Returns the retimer fw update state + fn get_rt_fw_update_status( + &mut self, + port: LocalPortId, + ) -> impl Future>>; + /// Set retimer fw update state + fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>>; + /// Clear retimer fw update state + fn clear_rt_fw_update_state( + &mut self, + port: LocalPortId, + ) -> impl Future>>; + /// Set retimer compliance + fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>>; + + /// Reconfigure the retimer for the given port. + fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>>; + + /// Clear the dead battery flag for the given port. + fn clear_dead_battery_flag(&mut self, port: LocalPortId) + -> impl Future>>; + + /// Enable or disable sink path + fn enable_sink_path( + &mut self, + port: LocalPortId, + enable: bool, + ) -> impl Future>>; + /// Get current controller status + fn get_controller_status( + &mut self, + ) -> impl Future, Error>>; + /// Get current PD alert + fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, Error>>; + /// Set the maximum sink voltage for the given port + /// + /// This may trigger a renegotiation + fn set_max_sink_voltage( + &mut self, + port: LocalPortId, + voltage_mv: Option, + ) -> impl Future>>; + /// Set port unconstrained status + fn set_unconstrained_power( + &mut self, + port: LocalPortId, + unconstrained: bool, + ) -> impl Future>>; + + /// Get the Rx Other VDM data for the given port + fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>>; + /// Get the Rx Attention VDM data for the given port + fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>>; + /// Send a VDM to the given port + fn send_vdm( + &mut self, + port: LocalPortId, + tx_vdm: SendVdm, + ) -> impl Future>>; + + /// Set USB control configuration for the given port + fn set_usb_control( + &mut self, + port: LocalPortId, + config: UsbControlConfig, + ) -> impl Future>>; + + /// Get DisplayPort status for the given port + fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>>; + /// Set DisplayPort configuration for the given port + fn set_dp_config( + &mut self, + port: LocalPortId, + config: DpConfig, + ) -> impl Future>>; + /// Execute PD Data Reset for the given port + fn execute_drst(&mut self, port: LocalPortId) -> impl Future>>; + + /// Set Thunderbolt configuration for the given port + fn set_tbt_config( + &mut self, + port: LocalPortId, + config: TbtConfig, + ) -> impl Future>>; + + /// Set PD state-machine configuration for the given port + fn set_pd_state_machine_config( + &mut self, + port: LocalPortId, + config: PdStateMachineConfig, + ) -> impl Future>>; + + /// Set Type-C state-machine configuration for the given port + fn set_type_c_state_machine_config( + &mut self, + port: LocalPortId, + state: TypeCStateMachineState, + ) -> impl Future>>; + + /// Execute the given UCSI command + fn execute_ucsi_command( + &mut self, + command: lpm::LocalCommand, + ) -> impl Future, Error>>; + + /// Execute an electrical disconnect on the given port, if supported by the controller. + /// + /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time + /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. + fn execute_electrical_disconnect( + &mut self, + port: LocalPortId, + reconnect_time_s: Option, + ) -> impl Future>>; + + /// Set the system power state on the given port. + /// + /// This notifies the PD controller of the current system power state, + /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). + fn set_power_state( + &mut self, + port: LocalPortId, + state: SystemPowerState, + ) -> impl Future>>; +} diff --git a/type-c-interface/src/lib.rs b/type-c-interface/src/lib.rs index 8c5e96b62..5adcc451b 100644 --- a/type-c-interface/src/lib.rs +++ b/type-c-interface/src/lib.rs @@ -1,4 +1,6 @@ //! Interface for type-C service. #![no_std] +pub mod control; +pub mod controller; pub mod port; pub mod service; diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index cd4877660..a3784db03 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -1,273 +1,23 @@ //! PD controller related code -use core::future::Future; -use core::num::NonZeroU8; - use embassy_sync::channel::{DynamicReceiver, DynamicSender}; use embedded_usb_pd::ucsi::lpm; -use embedded_usb_pd::{ - DataRole, Error, GlobalPortId, LocalPortId, PdError, PlugOrientation, PowerRole, - ado::Ado, - pdinfo::{AltMode, PowerPathStatus}, - type_c::ConnectionState, -}; +use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError, ado::Ado}; use embedded_services::ipc::deferred; use embedded_services::{GlobalRawMutex, intrusive_list}; pub mod event; +use crate::control::dp::{DpConfig, DpStatus}; +use crate::control::pd::PdStateMachineConfig; +use crate::control::retimer::RetimerFwUpdateState; +use crate::control::tbt::TbtConfig; +use crate::control::type_c::TypeCStateMachineState; +use crate::control::usb::UsbControlConfig; +use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use crate::controller::{ControllerId, ControllerStatus}; use crate::service::event::PortEvent as ServicePortEvent; -/// Length of the Other VDM data -pub const OTHER_VDM_LEN: usize = 29; -/// Length of the Attention VDM data -pub const ATTN_VDM_LEN: usize = 9; -/// maximum number of data objects in a VDM -pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each - -/// Controller ID -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerId(pub u8); - -/// Port status -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PortStatus { - /// Current available source contract - pub available_source_contract: Option, - /// Current available sink contract - pub available_sink_contract: Option, - /// Current connection state - pub connection_state: Option, - /// Port partner supports dual-power roles - pub dual_power: bool, - /// plug orientation - pub plug_orientation: PlugOrientation, - /// power role - pub power_role: PowerRole, - /// data role - pub data_role: DataRole, - /// Active alt-modes - pub alt_mode: AltMode, - /// Power path status - pub power_path: PowerPathStatus, - /// EPR mode active - pub epr: bool, - /// Port partner is unconstrained - pub unconstrained_power: bool, -} - -impl PortStatus { - /// Create a new blank port status - /// Needed because default() is not const - pub const fn new() -> Self { - Self { - available_source_contract: None, - available_sink_contract: None, - connection_state: None, - dual_power: false, - plug_orientation: PlugOrientation::CC1, - power_role: PowerRole::Sink, - data_role: DataRole::Dfp, - alt_mode: AltMode::none(), - power_path: PowerPathStatus::none(), - epr: false, - unconstrained_power: false, - } - } - - /// Check if the port is connected - pub fn is_connected(&self) -> bool { - matches!( - self.connection_state, - Some(ConnectionState::Attached) - | Some(ConnectionState::DebugAccessory) - | Some(ConnectionState::AudioAccessory) - ) - } - - /// Check if a debug accessory is connected - pub fn is_debug_accessory(&self) -> bool { - matches!(self.connection_state, Some(ConnectionState::DebugAccessory)) - } -} - -impl Default for PortStatus { - fn default() -> Self { - Self::new() - } -} - -/// Other Vdm data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OtherVdm { - /// Other VDM data - pub data: [u8; OTHER_VDM_LEN], -} - -impl Default for OtherVdm { - fn default() -> Self { - Self { - data: [0; OTHER_VDM_LEN], - } - } -} - -impl From for [u8; OTHER_VDM_LEN] { - fn from(vdm: OtherVdm) -> Self { - vdm.data - } -} - -impl From<[u8; OTHER_VDM_LEN]> for OtherVdm { - fn from(data: [u8; OTHER_VDM_LEN]) -> Self { - Self { data } - } -} - -/// Attention Vdm data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AttnVdm { - /// Attention VDM data - pub data: [u8; ATTN_VDM_LEN], -} - -/// DisplayPort pin configuration -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpPinConfig { - /// 4L DP connection using USBC-USBC cable (Pin Assignment C) - pub pin_c: bool, - /// 2L USB + 2L DP connection using USBC-USBC cable (Pin Assignment D) - pub pin_d: bool, - /// 4L DP connection using USBC-DP cable (Pin Assignment E) - pub pin_e: bool, -} - -/// DisplayPort status data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpStatus { - /// DP alt-mode entered - pub alt_mode_entered: bool, - /// Get DP DFP pin config - pub dfp_d_pin_cfg: DpPinConfig, -} - -/// DisplayPort configuration data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpConfig { - /// DP alt-mode enabled - pub enable: bool, - /// Set DP DFP pin config - pub dfp_d_pin_cfg: DpPinConfig, -} - -impl Default for AttnVdm { - fn default() -> Self { - Self { - data: [0; ATTN_VDM_LEN], - } - } -} - -impl From for [u8; ATTN_VDM_LEN] { - fn from(vdm: AttnVdm) -> Self { - vdm.data - } -} - -impl From<[u8; ATTN_VDM_LEN]> for AttnVdm { - fn from(data: [u8; ATTN_VDM_LEN]) -> Self { - Self { data } - } -} - -/// Send VDM data -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SendVdm { - /// initiating a VDM sequence - pub initiator: bool, - /// VDO count - pub vdo_count: u8, - /// VDO data - pub vdo_data: [u32; MAX_NUM_DATA_OBJECTS], -} - -impl SendVdm { - /// Create a new blank port status - pub const fn new() -> Self { - Self { - initiator: false, - vdo_count: 0, - vdo_data: [0; MAX_NUM_DATA_OBJECTS], - } - } -} - -impl Default for SendVdm { - fn default() -> Self { - Self::new() - } -} - -/// USB control configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct UsbControlConfig { - /// Enable USB2 data path - pub usb2_enabled: bool, - /// Enable USB3 data path - pub usb3_enabled: bool, - /// Enable USB4 data path - pub usb4_enabled: bool, -} - -impl Default for UsbControlConfig { - fn default() -> Self { - Self { - usb2_enabled: true, - usb3_enabled: true, - usb4_enabled: true, - } - } -} - -/// Thunderbolt control configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Default, Copy, PartialEq)] -pub struct TbtConfig { - /// Enable Thunderbolt - pub tbt_enabled: bool, -} - -/// PD state-machine configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Default, Copy, PartialEq)] -pub struct PdStateMachineConfig { - /// Enable or disable the PD state-machine - pub enabled: bool, -} - -/// TypeC State Machine -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum TypeCStateMachineState { - /// Sink state machine only - Sink, - /// Source state machine only - Source, - /// DRP state machine - Drp, - /// Disabled - Disabled, -} - /// Port-specific command data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -322,16 +72,6 @@ pub struct PortCommand { pub data: PortCommandData, } -/// PD controller command-specific data -#[derive(Copy, Clone, Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RetimerFwUpdateState { - /// Retimer FW Update Inactive - Inactive, - /// Retimer FW Update Active - Active, -} - /// Port-specific response data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -365,25 +105,6 @@ impl PortResponseData { /// Port-specific command response pub type PortResponse = Result; -/// System power state for Sx App Config register. -/// -/// Used to notify the PD controller of the current system power state, -/// which triggers Application Configuration updates (e.g., crossbar reconfiguration). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum SystemPowerState { - /// S0 - System fully running - S0, - /// S3 - Suspend to RAM - S3, - /// S4 - Hibernate - S4, - /// S5 - Soft off - S5, - /// S0ix - Modern standby / Connected standby - S0ix, -} - /// PD controller command-specific data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -429,20 +150,6 @@ pub enum Response<'a> { Port(PortResponse), } -/// Controller status -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerStatus<'a> { - /// Current controller mode - pub mode: &'a str, - /// True if we did not have to boot from a backup FW bank - pub valid_fw_bank: bool, - /// FW version 0 - pub fw_version0: u32, - /// FW version 1 - pub fw_version1: u32, -} - /// Per-port registration info pub struct PortRegistration { /// Global port ID of the port @@ -521,141 +228,3 @@ impl<'a> Device<'a> { self.num_ports } } - -/// PD controller trait that device drivers may use to integrate with internal messaging system -pub trait Controller { - /// Type of error returned by the bus - type BusError; - - /// Returns the port status - fn get_port_status(&mut self, port: LocalPortId) - -> impl Future>>; - - /// Reset the controller - fn reset_controller(&mut self) -> impl Future>>; - - /// Returns the retimer fw update state - fn get_rt_fw_update_status( - &mut self, - port: LocalPortId, - ) -> impl Future>>; - /// Set retimer fw update state - fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>>; - /// Clear retimer fw update state - fn clear_rt_fw_update_state( - &mut self, - port: LocalPortId, - ) -> impl Future>>; - /// Set retimer compliance - fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>>; - - /// Reconfigure the retimer for the given port. - fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>>; - - /// Clear the dead battery flag for the given port. - fn clear_dead_battery_flag(&mut self, port: LocalPortId) - -> impl Future>>; - - /// Enable or disable sink path - fn enable_sink_path( - &mut self, - port: LocalPortId, - enable: bool, - ) -> impl Future>>; - /// Get current controller status - fn get_controller_status( - &mut self, - ) -> impl Future, Error>>; - /// Get current PD alert - fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, Error>>; - /// Set the maximum sink voltage for the given port - /// - /// This may trigger a renegotiation - fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> impl Future>>; - /// Set port unconstrained status - fn set_unconstrained_power( - &mut self, - port: LocalPortId, - unconstrained: bool, - ) -> impl Future>>; - - /// Get the Rx Other VDM data for the given port - fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>>; - /// Get the Rx Attention VDM data for the given port - fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>>; - /// Send a VDM to the given port - fn send_vdm( - &mut self, - port: LocalPortId, - tx_vdm: SendVdm, - ) -> impl Future>>; - - /// Set USB control configuration for the given port - fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> impl Future>>; - - /// Get DisplayPort status for the given port - fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>>; - /// Set DisplayPort configuration for the given port - fn set_dp_config( - &mut self, - port: LocalPortId, - config: DpConfig, - ) -> impl Future>>; - /// Execute PD Data Reset for the given port - fn execute_drst(&mut self, port: LocalPortId) -> impl Future>>; - - /// Set Thunderbolt configuration for the given port - fn set_tbt_config( - &mut self, - port: LocalPortId, - config: TbtConfig, - ) -> impl Future>>; - - /// Set PD state-machine configuration for the given port - fn set_pd_state_machine_config( - &mut self, - port: LocalPortId, - config: PdStateMachineConfig, - ) -> impl Future>>; - - /// Set Type-C state-machine configuration for the given port - fn set_type_c_state_machine_config( - &mut self, - port: LocalPortId, - state: TypeCStateMachineState, - ) -> impl Future>>; - - /// Execute the given UCSI command - fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> impl Future, Error>>; - - /// Execute an electrical disconnect on the given port, if supported by the controller. - /// - /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time - /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. - fn execute_electrical_disconnect( - &mut self, - port: LocalPortId, - reconnect_time_s: Option, - ) -> impl Future>>; - - /// Set the system power state on the given port. - /// - /// This notifies the PD controller of the current system power state, - /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). - fn set_power_state( - &mut self, - port: LocalPortId, - state: SystemPowerState, - ) -> impl Future>>; -} diff --git a/type-c-interface/src/service/context.rs b/type-c-interface/src/service/context.rs index 6c877f5b0..0a38b5af1 100644 --- a/type-c-interface/src/service/context.rs +++ b/type-c-interface/src/service/context.rs @@ -2,11 +2,17 @@ use embassy_time::{Duration, with_timeout}; use embedded_usb_pd::ucsi::lpm; use embedded_usb_pd::{GlobalPortId, PdError}; -use crate::port::ControllerId; +use crate::control::dp::{DpConfig, DpStatus}; +use crate::control::pd::PdStateMachineConfig; +use crate::control::retimer::RetimerFwUpdateState; +use crate::control::tbt::TbtConfig; +use crate::control::type_c::TypeCStateMachineState; +use crate::control::usb::UsbControlConfig; +use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use crate::controller::{ControllerId, ControllerStatus}; use crate::port::{ - AttnVdm, Command, ControllerStatus, Device, DpConfig, DpStatus, InternalCommandData, InternalResponseData, - OtherVdm, PdStateMachineConfig, PortCommand, PortCommandData, PortResponseData, Response, RetimerFwUpdateState, - SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, + Command, Device, InternalCommandData, InternalResponseData, PortCommand, PortCommandData, PortResponseData, + Response, }; use crate::service; use crate::service::event::{Event, PortEvent}; diff --git a/type-c-interface/src/service/event.rs b/type-c-interface/src/service/event.rs index 88b4e7ea6..e8ca1bf1c 100644 --- a/type-c-interface/src/service/event.rs +++ b/type-c-interface/src/service/event.rs @@ -2,9 +2,9 @@ use embedded_usb_pd::{GlobalPortId, ado::Ado}; -use crate::port::{ - DpStatus, PortStatus, - event::{PortStatusEventBitfield, VdmData}, +use crate::{ + control::{dp::DpStatus, pd::PortStatus}, + port::event::{PortStatusEventBitfield, VdmData}, }; /// Struct containing data for a [`PortEventData::StatusChanged`] event diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index dbf9f0257..916b4241a 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -2,17 +2,18 @@ use embedded_services::{debug, sync::Lockable}; use embedded_usb_pd::{Error, PdError, ucsi::lpm}; -use type_c_interface::port::{self, Controller as _, InternalResponseData, Response}; +use type_c_interface::controller::Controller as _; +use type_c_interface::port::{self, InternalResponseData, Response}; use crate::bridge::event_receiver::{ControllerCommand, OutputControllerCommand}; pub mod event_receiver; -pub struct Bridge<'device, Controller: Lockable> { +pub struct Bridge<'device, Controller: Lockable> { controller: &'device Controller, registration: &'static port::Device<'static>, } -impl<'device, Controller: Lockable> Bridge<'device, Controller> { +impl<'device, Controller: Lockable> Bridge<'device, Controller> { pub fn new(controller: &'device Controller, registration: &'static port::Device<'static>) -> Self { Self { controller, diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index dc6bf0d84..dab699a52 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -2,10 +2,9 @@ use embedded_services::{debug, error, event::Sender, info, named::Named, sync::Lockable}; use embedded_usb_pd::{Error, GlobalPortId, LocalPortId, PdError}; use power_policy_interface::psu::PsuState; -use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ - Controller, PortStatus, event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield, -}; +use type_c_interface::control::pd::PortStatus; +use type_c_interface::controller::Controller; +use type_c_interface::port::{event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield}; use type_c_interface::service::event::{ PortEvent as ServicePortEvent, PortEventData as ServicePortEventData, StatusChangedData, }; diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index 07d71c9f4..9677ca5e5 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -1,9 +1,6 @@ //! PD functionality unrelated to power contracts and general port status use embedded_services::{event::Sender, sync::Lockable}; -use type_c_interface::port::{ - Controller, - event::{VdmData, VdmNotification}, -}; +use type_c_interface::port::event::{VdmData, VdmNotification}; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; use super::*; diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index 8fd0bd6e0..b7504516e 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -9,7 +9,6 @@ use power_policy_interface::{ capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}, psu::{Error as PsuError, Psu, State}, }; -use type_c_interface::port::Controller; use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_bus_error}; diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index 906a298ea..93c17ecaf 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -29,14 +29,16 @@ use tps6699x::command::{ use tps6699x::fw_update::UpdateConfig as FwUpdateConfig; use tps6699x::registers::field_sets::IntEventBus1; use tps6699x::registers::port_config::TypeCStateMachine; +use type_c_interface::control::dp::{DpConfig, DpPinConfig, DpStatus}; +use type_c_interface::control::pd::{PdStateMachineConfig, PortStatus}; +use type_c_interface::control::power::SystemPowerState; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::control::tbt::TbtConfig; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::control::usb::UsbControlConfig; +use type_c_interface::control::vdm::{ATTN_VDM_LEN, AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::controller::{Controller, ControllerStatus}; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ - ATTN_VDM_LEN, DpConfig, DpStatus, PdStateMachineConfig, RetimerFwUpdateState, SystemPowerState, -}; -use type_c_interface::port::{ - AttnVdm, Controller, ControllerStatus, DpPinConfig, OtherVdm, PortStatus, SendVdm, TbtConfig, - TypeCStateMachineState, UsbControlConfig, -}; use crate::util::power_capability_try_from_contract; use crate::util::{basic_fw_update_error_from_pd_bus_error, power_capability_from_current}; diff --git a/type-c-service/src/service/mod.rs b/type-c-service/src/service/mod.rs index 70e7f11e6..a0ff5ec8b 100644 --- a/type-c-service/src/service/mod.rs +++ b/type-c-service/src/service/mod.rs @@ -8,10 +8,11 @@ use embedded_services::{debug, error, event::Receiver, info, trace}; use embedded_usb_pd::GlobalPortId; use embedded_usb_pd::PdError as Error; use power_policy_interface::service::event::EventData as PowerPolicyEventData; +use type_c_interface::control::pd::PortStatus; use type_c_interface::service::event::{PortEvent, PortEventData}; +use type_c_interface::port::Device; use type_c_interface::port::event::PortStatusEventBitfield; -use type_c_interface::port::{Device, PortStatus}; use type_c_interface::service::event; pub mod config; diff --git a/type-c-service/src/service/vdm.rs b/type-c-service/src/service/vdm.rs index d92590709..d238c61cf 100644 --- a/type-c-service/src/service/vdm.rs +++ b/type-c-service/src/service/vdm.rs @@ -1,7 +1,7 @@ //! VDM (Vendor Defined Messages) related functionality. use embedded_usb_pd::{GlobalPortId, PdError}; -use type_c_interface::port::{AttnVdm, OtherVdm}; +use type_c_interface::control::vdm::{AttnVdm, OtherVdm}; use super::Service; From 67ddc9c0c1091166a24ba08d0e1a426980f8153d Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 10:49:55 -0700 Subject: [PATCH 2/9] type-c-interface: Remove bus error type from controller trait The `Controller` trait is meant to abstract over PD controller hardware. However, the current implementation exposes the underlying bus error type. This isn't particulary useful, leaks implementation details, and makes code more complicated when using enum dispatch. Remove it. Implementators of this trait should log bus-specific error information and return a `PdError`. --- .../std/src/lib/type_c/mock_controller.rs | 78 ++-- type-c-interface/src/controller/mod.rs | 80 ++--- type-c-service/src/bridge/mod.rs | 226 ++++-------- type-c-service/src/controller/mod.rs | 25 +- type-c-service/src/controller/pd.rs | 13 +- type-c-service/src/controller/power.rs | 20 +- type-c-service/src/driver/tps6699x.rs | 333 +++++++++++------- 7 files changed, 342 insertions(+), 433 deletions(-) diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index a020a9cfb..608112a86 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU8; use embassy_sync::{channel, mutex::Mutex, signal::Signal}; use embedded_services::GlobalRawMutex; -use embedded_usb_pd::{Error, ado::Ado}; +use embedded_usb_pd::ado::Ado; use embedded_usb_pd::{LocalPortId, PdError}; use embedded_usb_pd::{PowerRole, type_c::Current}; use embedded_usb_pd::{type_c::ConnectionState, ucsi::lpm}; @@ -135,19 +135,17 @@ impl type_c_service::controller::event_receiver::InterruptReceiv } impl type_c_interface::controller::Controller for Controller<'_> { - type BusError = (); - - async fn get_port_status(&mut self, _port: LocalPortId) -> Result> { + async fn get_port_status(&mut self, _port: LocalPortId) -> Result { debug!("Get port status: {:#?}", *self.state.status.lock().await); Ok(*self.state.status.lock().await) } - async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), Error> { + async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), PdError> { debug!("Enable sink path: {enable}"); Ok(()) } - async fn get_controller_status(&mut self) -> Result, Error> { + async fn get_controller_status(&mut self) -> Result, PdError> { debug!("Get controller status"); Ok(ControllerStatus { mode: "Test", @@ -157,35 +155,32 @@ impl type_c_interface::controller::Controller for Controller<'_> { }) } - async fn reset_controller(&mut self) -> Result<(), Error> { + async fn reset_controller(&mut self) -> Result<(), PdError> { debug!("Reset controller"); Ok(()) } - async fn get_rt_fw_update_status( - &mut self, - _port: LocalPortId, - ) -> Result> { + async fn get_rt_fw_update_status(&mut self, _port: LocalPortId) -> Result { debug!("Get retimer fw update status"); Ok(RetimerFwUpdateState::Inactive) } - async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), Error> { + async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { debug!("Set retimer fw update state"); Ok(()) } - async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), Error> { + async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { debug!("Clear retimer fw update state"); Ok(()) } - async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), Error> { + async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), PdError> { debug!("Set retimer compliance"); Ok(()) } - async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, Error> { + async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, PdError> { let pd_alert = self.state.pd_alert.lock().await; if let Some(ado) = *pd_alert { debug!("Port{}: Get PD alert: {ado:#?}", port.0); @@ -196,54 +191,42 @@ impl type_c_interface::controller::Controller for Controller<'_> { } } - async fn set_unconstrained_power( - &mut self, - _port: LocalPortId, - unconstrained: bool, - ) -> Result<(), Error> { + async fn set_unconstrained_power(&mut self, _port: LocalPortId, unconstrained: bool) -> Result<(), PdError> { debug!("Set unconstrained power: {unconstrained}"); Ok(()) } - async fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> Result<(), Error> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { debug!("Set max sink voltage for port {}: {:?}", port.0, voltage_mv); Ok(()) } - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("reconfigure_retimer(port: {port:?})"); Ok(()) } - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("clear_dead_battery_flag(port: {port:?})"); Ok(()) } - async fn get_other_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_other_vdm(&mut self, port: LocalPortId) -> Result { debug!("Get other VDM for port {port:?}"); Ok(OtherVdm::default()) } - async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result { debug!("Get attention VDM for port {port:?}"); Ok(AttnVdm::default()) } - async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), Error> { + async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), PdError> { debug!("Send VDM for port {port:?}: {tx_vdm:?}"); Ok(()) } - async fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> Result<(), Error> { + async fn set_usb_control(&mut self, port: LocalPortId, config: UsbControlConfig) -> Result<(), PdError> { debug!( "set_usb_control(port: {port:?}, usb2: {}, usb3: {}, usb4: {})", config.usb2_enabled, config.usb3_enabled, config.usb4_enabled @@ -251,7 +234,7 @@ impl type_c_interface::controller::Controller for Controller<'_> { Ok(()) } - async fn get_dp_status(&mut self, port: LocalPortId) -> Result> { + async fn get_dp_status(&mut self, port: LocalPortId) -> Result { debug!("Get DisplayPort status for port {port:?}"); Ok(DpStatus { alt_mode_entered: false, @@ -259,7 +242,7 @@ impl type_c_interface::controller::Controller for Controller<'_> { }) } - async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), Error> { + async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), PdError> { debug!( "Set DisplayPort config for port {port:?}: enable={}, pin_cfg={:?}", config.enable, config.dfp_d_pin_cfg @@ -267,12 +250,12 @@ impl type_c_interface::controller::Controller for Controller<'_> { Ok(()) } - async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("Execute PD Data Reset for port {port:?}"); Ok(()) } - async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), Error> { + async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), PdError> { debug!("Set Thunderbolt config for port {port:?}: {config:?}"); Ok(()) } @@ -281,7 +264,7 @@ impl type_c_interface::controller::Controller for Controller<'_> { &mut self, port: LocalPortId, config: PdStateMachineConfig, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Set PD State Machine config for port {port:?}: {config:?}"); Ok(()) } @@ -290,15 +273,12 @@ impl type_c_interface::controller::Controller for Controller<'_> { &mut self, port: LocalPortId, state: TypeCStateMachineState, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Set Type-C State Machine state for port {port:?}: {state:?}"); Ok(()) } - async fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> Result, Error> { + async fn execute_ucsi_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { debug!("Execute UCSI command for port {:?}: {command:?}", command.port()); match command.operation() { lpm::CommandData::GetConnectorStatus => Ok(Some(lpm::ResponseData::GetConnectorStatus( @@ -312,16 +292,12 @@ impl type_c_interface::controller::Controller for Controller<'_> { &mut self, port: LocalPortId, reconnect_time_s: Option, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Execute electrical disconnect for port {port:?} with reconnect time {reconnect_time_s:?}"); Ok(()) } - async fn set_power_state( - &mut self, - port: LocalPortId, - state: SystemPowerState, - ) -> Result<(), Error> { + async fn set_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { debug!("Set power state for port {port:?}: {state:?}"); Ok(()) } diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs index b7f223439..89abe3fbd 100644 --- a/type-c-interface/src/controller/mod.rs +++ b/type-c-interface/src/controller/mod.rs @@ -3,7 +3,7 @@ use core::future::Future; use core::num::NonZeroU8; use embedded_usb_pd::ado::Ado; -use embedded_usb_pd::{Error, LocalPortId, ucsi::lpm}; +use embedded_usb_pd::{LocalPortId, PdError, ucsi::lpm}; use crate::control::dp::{DpConfig, DpStatus}; use crate::control::pd::{PdStateMachineConfig, PortStatus}; @@ -35,50 +35,36 @@ pub struct ControllerId(pub u8); /// PD controller trait pub trait Controller { - /// Type of error returned by the bus - type BusError; - /// Returns the port status - fn get_port_status(&mut self, port: LocalPortId) - -> impl Future>>; + fn get_port_status(&mut self, port: LocalPortId) -> impl Future>; /// Reset the controller - fn reset_controller(&mut self) -> impl Future>>; + fn reset_controller(&mut self) -> impl Future>; /// Returns the retimer fw update state fn get_rt_fw_update_status( &mut self, port: LocalPortId, - ) -> impl Future>>; + ) -> impl Future>; /// Set retimer fw update state - fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>>; + fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; /// Clear retimer fw update state - fn clear_rt_fw_update_state( - &mut self, - port: LocalPortId, - ) -> impl Future>>; + fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; /// Set retimer compliance - fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>>; + fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>; /// Reconfigure the retimer for the given port. - fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>>; + fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>; /// Clear the dead battery flag for the given port. - fn clear_dead_battery_flag(&mut self, port: LocalPortId) - -> impl Future>>; + fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> impl Future>; /// Enable or disable sink path - fn enable_sink_path( - &mut self, - port: LocalPortId, - enable: bool, - ) -> impl Future>>; + fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> impl Future>; /// Get current controller status - fn get_controller_status( - &mut self, - ) -> impl Future, Error>>; + fn get_controller_status(&mut self) -> impl Future, PdError>>; /// Get current PD alert - fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, Error>>; + fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, PdError>>; /// Set the maximum sink voltage for the given port /// /// This may trigger a renegotiation @@ -86,69 +72,57 @@ pub trait Controller { &mut self, port: LocalPortId, voltage_mv: Option, - ) -> impl Future>>; + ) -> impl Future>; /// Set port unconstrained status fn set_unconstrained_power( &mut self, port: LocalPortId, unconstrained: bool, - ) -> impl Future>>; + ) -> impl Future>; /// Get the Rx Other VDM data for the given port - fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>>; + fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>; /// Get the Rx Attention VDM data for the given port - fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>>; + fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>; /// Send a VDM to the given port - fn send_vdm( - &mut self, - port: LocalPortId, - tx_vdm: SendVdm, - ) -> impl Future>>; + fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> impl Future>; /// Set USB control configuration for the given port fn set_usb_control( &mut self, port: LocalPortId, config: UsbControlConfig, - ) -> impl Future>>; + ) -> impl Future>; /// Get DisplayPort status for the given port - fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>>; + fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>; /// Set DisplayPort configuration for the given port - fn set_dp_config( - &mut self, - port: LocalPortId, - config: DpConfig, - ) -> impl Future>>; + fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> impl Future>; /// Execute PD Data Reset for the given port - fn execute_drst(&mut self, port: LocalPortId) -> impl Future>>; + fn execute_drst(&mut self, port: LocalPortId) -> impl Future>; /// Set Thunderbolt configuration for the given port - fn set_tbt_config( - &mut self, - port: LocalPortId, - config: TbtConfig, - ) -> impl Future>>; + fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> impl Future>; /// Set PD state-machine configuration for the given port fn set_pd_state_machine_config( &mut self, port: LocalPortId, config: PdStateMachineConfig, - ) -> impl Future>>; + ) -> impl Future>; /// Set Type-C state-machine configuration for the given port fn set_type_c_state_machine_config( &mut self, port: LocalPortId, state: TypeCStateMachineState, - ) -> impl Future>>; + ) -> impl Future>; /// Execute the given UCSI command fn execute_ucsi_command( &mut self, command: lpm::LocalCommand, - ) -> impl Future, Error>>; + ) -> impl Future, PdError>>; /// Execute an electrical disconnect on the given port, if supported by the controller. /// @@ -158,7 +132,7 @@ pub trait Controller { &mut self, port: LocalPortId, reconnect_time_s: Option, - ) -> impl Future>>; + ) -> impl Future>; /// Set the system power state on the given port. /// @@ -168,5 +142,5 @@ pub trait Controller { &mut self, port: LocalPortId, state: SystemPowerState, - ) -> impl Future>>; + ) -> impl Future>; } diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index 916b4241a..909392cb8 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -1,7 +1,7 @@ //! Temporary bridge between a controller and the type-C service use embedded_services::{debug, sync::Lockable}; -use embedded_usb_pd::{Error, PdError, ucsi::lpm}; +use embedded_usb_pd::{PdError, ucsi::lpm}; use type_c_interface::controller::Controller as _; use type_c_interface::port::{self, InternalResponseData, Response}; @@ -32,158 +32,80 @@ impl<'device, Controller: Lockable { - match controller.get_rt_fw_update_status(local_port).await { - Ok(status) => Ok(port::PortResponseData::RtFwUpdateStatus(status)), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::RetimerFwUpdateSetState => { - match controller.set_rt_fw_update_state(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::RetimerFwUpdateClearState => { - match controller.clear_rt_fw_update_state(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::SetRetimerCompliance => match controller.set_rt_compliance(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::ReconfigureRetimer => match controller.reconfigure_retimer(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, + port::PortCommandData::RetimerFwUpdateGetState => controller + .get_rt_fw_update_status(local_port) + .await + .map(port::PortResponseData::RtFwUpdateStatus), + port::PortCommandData::RetimerFwUpdateSetState => controller + .set_rt_fw_update_state(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::RetimerFwUpdateClearState => controller + .clear_rt_fw_update_state(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetRetimerCompliance => controller + .set_rt_compliance(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ReconfigureRetimer => controller + .reconfigure_retimer(local_port) + .await + .map(|_| port::PortResponseData::Complete), // This command isn't sent by the type-C service, disable it for the transition port::PortCommandData::SetMaxSinkVoltage(_) => Ok(port::PortResponseData::Complete), - port::PortCommandData::SetUnconstrainedPower(unconstrained) => { - match controller.set_unconstrained_power(local_port, unconstrained).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::ClearDeadBatteryFlag => match controller.clear_dead_battery_flag(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::GetOtherVdm => match controller.get_other_vdm(local_port).await { - Ok(vdm) => { - debug!("Port{}: Other VDM: {:?}", local_port.0, vdm); - Ok(port::PortResponseData::OtherVdm(vdm)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::GetAttnVdm => match controller.get_attn_vdm(local_port).await { - Ok(vdm) => { - debug!("Port{}: Attention VDM: {:?}", local_port.0, vdm); - Ok(port::PortResponseData::AttnVdm(vdm)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SendVdm(tx_vdm) => match controller.send_vdm(local_port, tx_vdm).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetUsbControl(config) => { - match controller.set_usb_control(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::GetDpStatus => match controller.get_dp_status(local_port).await { - Ok(status) => { - debug!("Port{}: DP Status: {:?}", local_port.0, status); - Ok(port::PortResponseData::DpStatus(status)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetDpConfig(config) => match controller.set_dp_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::ExecuteDrst => match controller.execute_drst(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetTbtConfig(config) => match controller.set_tbt_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetPdStateMachineConfig(config) => { - match controller.set_pd_state_machine_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::SetTypeCStateMachineConfig(state) => { - match controller.set_type_c_state_machine_config(local_port, state).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } + port::PortCommandData::SetUnconstrainedPower(unconstrained) => controller + .set_unconstrained_power(local_port, unconstrained) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ClearDeadBatteryFlag => controller + .clear_dead_battery_flag(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::GetOtherVdm => controller.get_other_vdm(local_port).await.map(|vdm| { + debug!("Port{}: Other VDM: {:?}", local_port.0, vdm); + port::PortResponseData::OtherVdm(vdm) + }), + port::PortCommandData::GetAttnVdm => controller.get_attn_vdm(local_port).await.map(|vdm| { + debug!("Port{}: Attention VDM: {:?}", local_port.0, vdm); + port::PortResponseData::AttnVdm(vdm) + }), + port::PortCommandData::SendVdm(tx_vdm) => controller + .send_vdm(local_port, tx_vdm) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetUsbControl(config) => controller + .set_usb_control(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::GetDpStatus => controller.get_dp_status(local_port).await.map(|status| { + debug!("Port{}: DP Status: {:?}", local_port.0, status); + port::PortResponseData::DpStatus(status) + }), + port::PortCommandData::SetDpConfig(config) => controller + .set_dp_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ExecuteDrst => controller + .execute_drst(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetTbtConfig(config) => controller + .set_tbt_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetPdStateMachineConfig(config) => controller + .set_pd_state_machine_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetTypeCStateMachineConfig(state) => controller + .set_type_c_state_machine_config(local_port, state) + .await + .map(|_| port::PortResponseData::Complete), port::PortCommandData::ExecuteUcsiCommand(command_data) => Ok(port::PortResponseData::UcsiResponse( controller .execute_ucsi_command(lpm::Command::new(local_port, command_data)) - .await - .map_err(|e| match e { - Error::Bus(_) => PdError::Failed, - Error::Pd(e) => e, - }), + .await, )), }) } @@ -193,17 +115,13 @@ impl<'device, Controller: Lockable { let status = controller.get_controller_status().await; - port::Response::Controller(status.map(InternalResponseData::Status).map_err(|_| PdError::Failed)) + port::Response::Controller(status.map(InternalResponseData::Status)) } // This isn't sent by the type-C service, disable it for the transition port::InternalCommandData::SyncState => port::Response::Controller(Ok(InternalResponseData::Complete)), port::InternalCommandData::Reset => { let result = controller.reset_controller().await; - port::Response::Controller( - result - .map(|_| InternalResponseData::Complete) - .map_err(|_| PdError::Failed), - ) + port::Response::Controller(result.map(|_| InternalResponseData::Complete)) } } } diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index dab699a52..df7a7f5f0 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -1,6 +1,6 @@ //! Struct that manages per-port state, interfacing with a controller object that exposes multiple ports. use embedded_services::{debug, error, event::Sender, info, named::Named, sync::Lockable}; -use embedded_usb_pd::{Error, GlobalPortId, LocalPortId, PdError}; +use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError}; use power_policy_interface::psu::PsuState; use type_c_interface::control::pd::PortStatus; use type_c_interface::controller::Controller; @@ -89,20 +89,14 @@ impl< } /// Top-level processing function - pub async fn process_event( - &mut self, - event: Event, - ) -> Result, Error<::BusError>> { + pub async fn process_event(&mut self, event: Event) -> Result, PdError> { match event { Event::PortEvent(port_event) => self.process_port_event(port_event).await, } } /// Process a port notification - async fn process_port_event( - &mut self, - event: InterfacePortEvent, - ) -> Result, Error<::BusError>> { + async fn process_port_event(&mut self, event: InterfacePortEvent) -> Result, PdError> { match event { InterfacePortEvent::StatusChanged(status_event) => { self.process_port_status_changed(status_event).await.map(Some) @@ -122,7 +116,7 @@ impl< async fn process_port_status_changed( &mut self, status_event: PortStatusEventBitfield, - ) -> Result::BusError>> { + ) -> Result { let new_status = self.controller.lock().await.get_port_status(self.port).await?; debug!("({}) status: {:#?}", self.name, new_status); debug!("({}) status events: {:#?}", self.name, status_event); @@ -159,15 +153,12 @@ impl< event, }) .await - .map_err(Error::Pd)?; + .map_err(|_| PdError::Failed)?; Ok(event) } /// Handle a plug event - async fn process_plug_event( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + async fn process_plug_event(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Plug event"); if new_status.is_connected() { info!("Plug inserted"); @@ -179,7 +170,7 @@ impl< if let Err(e) = self.psu_state.attach() { // This should never happen because we should have detached above error!("Failed to attach PSU: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender @@ -202,7 +193,7 @@ impl< } /// Synchronize the state between the controller and the internal state - pub async fn sync_state(&mut self) -> Result<(), Error<::BusError>> { + pub async fn sync_state(&mut self) -> Result<(), PdError> { let status = self.controller.lock().await.get_port_status(self.port).await?; let mut event = PortEventBitfield::none(); diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index 9677ca5e5..2158b9f38 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -15,10 +15,7 @@ impl< > Port<'device, C, Shared, PowerSender, LoopbackSender> { /// Process a VDM event by retrieving the relevant VDM data from the `controller` for the appropriate `port`. - pub(super) async fn process_vdm_event( - &mut self, - event: VdmNotification, - ) -> Result::BusError>> { + pub(super) async fn process_vdm_event(&mut self, event: VdmNotification) -> Result { debug!("({}): Processing VDM event: {:?}", self.name, event); let vdm_data = { let mut controller = self.controller.lock().await; @@ -42,9 +39,7 @@ impl< } /// Process a DisplayPort status update by retrieving the current DP status from the `controller` for the appropriate `port`. - pub(super) async fn process_dp_status_update( - &mut self, - ) -> Result::BusError>> { + pub(super) async fn process_dp_status_update(&mut self) -> Result { debug!("({}): Processing DP status update event", self.name); let status = self.controller.lock().await.get_dp_status(self.port).await?; let event = ServicePortEventData::DpStatusUpdate(status); @@ -58,9 +53,7 @@ impl< Ok(event) } - pub(super) async fn process_pd_alert( - &mut self, - ) -> Result, Error<::BusError>> { + pub(super) async fn process_pd_alert(&mut self) -> Result, PdError> { let ado = self.controller.lock().await.get_pd_alert(self.port).await?; debug!("({}): PD alert: {:#?}", self.name, ado); if let Some(ado) = ado { diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index b7504516e..4f353e4a1 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -10,7 +10,7 @@ use power_policy_interface::{ psu::{Error as PsuError, Psu, State}, }; -use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_bus_error}; +use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_error}; use super::*; @@ -23,10 +23,7 @@ impl< > Port<'device, C, Shared, PowerSender, LoopbackSender> { /// Handle a new contract as consumer - pub(super) async fn process_new_consumer_contract( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + pub(super) async fn process_new_consumer_contract(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Process new consumer contract"); let available_sink_contract = new_status.available_sink_contract.map(|c| { let mut c: ConsumerPowerCapability = c.into(); @@ -42,7 +39,7 @@ impl< if let Err(e) = self.psu_state.update_consumer_power_capability(available_sink_contract) { error!("Failed to update consumer power capability: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender .send(power_policy_interface::psu::event::EventData::UpdatedConsumerCapability(available_sink_contract)) @@ -51,10 +48,7 @@ impl< } /// Handle a new contract as provider - pub(super) async fn process_new_provider_contract( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + pub(super) async fn process_new_provider_contract(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Process New provider contract"); let capability = new_status.available_source_contract.map(|caps| { let mut caps = ProviderPowerCapability::from(caps); @@ -63,7 +57,7 @@ impl< }); if let Err(e) = self.psu_state.update_requested_provider_power_capability(capability) { error!("Failed to update requested provider power capability: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender .send(power_policy_interface::psu::event::EventData::RequestedProviderCapability(capability)) @@ -131,7 +125,7 @@ impl< .await .map_err(|e| { error!("({}): Error disabling sink path", self.name); - power_policy_error_from_pd_bus_error(e) + power_policy_error_from_pd_error(e) })?; self.psu_state.disconnect(false) } @@ -156,7 +150,7 @@ impl< .await .map_err(|e| { error!("({}): Error enabling sink path", self.name); - power_policy_error_from_pd_bus_error(e) + power_policy_error_from_pd_error(e) })?; self.psu_state.connect_consumer(capability) } diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index 93c17ecaf..b08708a47 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -40,8 +40,9 @@ use type_c_interface::control::vdm::{ATTN_VDM_LEN, AttnVdm, OtherVdm, SendVdm}; use type_c_interface::controller::{Controller, ControllerStatus}; use type_c_interface::port::event::PortEventBitfield; -use crate::util::power_capability_try_from_contract; -use crate::util::{basic_fw_update_error_from_pd_bus_error, power_capability_from_current}; +use crate::util::{ + basic_fw_update_error_from_pd_error, power_capability_from_current, power_capability_try_from_contract, +}; type Updater<'a, M, B> = BorrowedUpdaterInProgress>; @@ -118,18 +119,23 @@ impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> { } } - fn log_error(&self, e: Error) -> Error { + fn log_error(&self, e: Error) -> PdError { match e { - Error::Bus(_) => error!("({}): Bus error", self.name()), - Error::Pd(pd_error) => error!("({}): PD error: {:#?}", self.name(), pd_error), + Error::Bus(_) => { + error!("({}): Bus error", self.name()); + PdError::Failed + } + Error::Pd(pd_error) => { + error!("({}): PD error: {:#?}", self.name(), pd_error); + pd_error + } } - e } /// Returns a busy error if a FW update is currently in progress - fn guard_no_fw_update_active(&self) -> Result<(), Error> { + fn guard_no_fw_update_active(&self) -> Result<(), PdError> { if self.update_state.is_some() { - Err(Error::Pd(PdError::Busy)) + Err(PdError::Busy) } else { Ok(()) } @@ -225,7 +231,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { self.tps6699x .get_customer_use() .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?, + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?, ); Ok(customer_use.custom_fw_version()) } @@ -248,17 +254,17 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { // Disable all interrupts on both ports, use guards[1] to ensure that this set of guards is dropped last disable_all_interrupts::>(&mut [&mut self.tps6699x], &mut guards[1..]) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; let in_progress = updater .start_fw_update(&mut [&mut self.tps6699x], &mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; // Re-enable interrupts on port 0 only if let Err(e) = enable_port0_interrupts::>(&mut [&mut self.tps6699x], &mut guards[0..1]) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) { error!("Failed to enable port 0 interrupts, aborting update: {:#?}", e); in_progress.abort_fw_update(&mut [&mut self.tps6699x], &mut delay).await; @@ -281,7 +287,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .tps6699x .get_mode() .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))? + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))? == tps6699x::Mode::F211 { let mut delay = Delay; @@ -298,7 +304,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { self.tps6699x .fw_update_mode_exit(&mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) } } else { // Not in FW update mode, don't need to do anything @@ -316,7 +322,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .updater .complete_fw_update(&mut [&mut self.tps6699x], &mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) } else { Err(BasicFwUpdateError::NeedsActiveUpdate) } @@ -329,7 +335,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .updater .write_bytes(&mut [&mut self.tps6699x], &mut delay, data) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; Ok(()) } else { Err(BasicFwUpdateError::NeedsActiveUpdate) @@ -338,27 +344,33 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { } impl Controller for Tps6699x<'_, M, B> { - type BusError = B::Error; - /// Controller reset - async fn reset_controller(&mut self) -> Result<(), Error> { + async fn reset_controller(&mut self) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let mut delay = Delay; - self.tps6699x.reset(&mut delay).await?; + self.tps6699x.reset(&mut delay).await.map_err(|e| self.log_error(e))?; Ok(()) } /// Returns the current status of the port - async fn get_port_status(&mut self, port: LocalPortId) -> Result> { + async fn get_port_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; - let status = self.tps6699x.get_port_status(port).await?; + let status = self + .tps6699x + .get_port_status(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} status: {:#?}", port.0, status); - let pd_status = self.tps6699x.get_pd_status(port).await?; + let pd_status = self.tps6699x.get_pd_status(port).await.map_err(|e| self.log_error(e))?; debug!("Port{} PD status: {:#?}", port.0, pd_status); - let port_control = self.tps6699x.get_port_control(port).await?; + let port_control = self + .tps6699x + .get_port_control(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} control: {:#?}", port.0, port_control); let mut port_status = PortStatus::default(); @@ -371,16 +383,26 @@ impl Controller for Tps6699x<'_, M, B> { if port_status.is_connected() { // Determine current contract if any - let pdo_raw = self.tps6699x.get_active_pdo_contract(port).await?.active_pdo(); + let pdo_raw = self + .tps6699x + .get_active_pdo_contract(port) + .await + .map_err(|e| self.log_error(e))? + .active_pdo(); trace!("Raw PDO: {:#X}", pdo_raw); - let rdo_raw = self.tps6699x.get_active_rdo_contract(port).await?.active_rdo(); + let rdo_raw = self + .tps6699x + .get_active_rdo_contract(port) + .await + .map_err(|e| self.log_error(e))? + .active_rdo(); trace!("Raw RDO: {:#X}", rdo_raw); if pdo_raw != 0 && rdo_raw != 0 { // Got a valid explicit contract if pd_status.is_source() { - let pdo = source::Pdo::try_from(pdo_raw).map_err(|_| Error::from(PdError::InvalidParams))?; - let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; + let pdo = source::Pdo::try_from(pdo_raw)?; + let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(PdError::InvalidParams)?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); port_status.available_source_contract = @@ -390,21 +412,23 @@ impl Controller for Tps6699x<'_, M, B> { // active_rdo_contract doesn't contain the full picture let mut source_pdos: [source::Pdo; 1] = [source::Pdo::default()]; // Read 5V fixed supply source PDO, guaranteed to be present as the first SPR PDO - let (num_sprs, _) = self - .tps6699x - .lock_inner() - .await - .get_rx_src_caps(port, &mut source_pdos[..], &mut []) - .await?; + let (num_sprs, _) = { + self.tps6699x + .lock_inner() + .await + .get_rx_src_caps(port, &mut source_pdos[..], &mut []) + .await + } + .map_err(|e| self.log_error(e.into()))?; if num_sprs == 0 { // USB PD spec requires at least one source PDO be present, something is really wrong error!("Port{} no source PDOs found", port.0); - return Err(PdError::InvalidParams.into()); + return Err(PdError::InvalidParams); } - let pdo = sink::Pdo::try_from(pdo_raw).map_err(|_| Error::from(PdError::InvalidParams))?; - let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; + let pdo = sink::Pdo::try_from(pdo_raw)?; + let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(PdError::InvalidParams)?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); port_status.available_sink_contract = @@ -415,7 +439,7 @@ impl Controller for Tps6699x<'_, M, B> { } else if status.port_role() { // port_role is true for source // Implicit source contract - let current = TypecCurrent::try_from(port_control.typec_current()).map_err(Error::Pd)?; + let current = TypecCurrent::try_from(port_control.typec_current())?; debug!("Port{} type-C source current: {:#?}", port.0, current); port_status.available_source_contract = Some(power_capability_from_current(current)); } else { @@ -426,7 +450,7 @@ impl Controller for Tps6699x<'_, M, B> { debug!("Port{} no pull up", port.0); None } else { - let current = TypecCurrent::try_from(pd_status.cc_pull_up()).map_err(Error::Pd)?; + let current = TypecCurrent::try_from(pd_status.cc_pull_up())?; debug!("Port{} type-C sink current: {:#?}", port.0, current); Some(power_capability_from_current(current)) }; @@ -450,12 +474,20 @@ impl Controller for Tps6699x<'_, M, B> { }; // Update alt-mode status - let alt_mode = self.tps6699x.get_alt_mode_status(port).await?; + let alt_mode = self + .tps6699x + .get_alt_mode_status(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} alt mode: {:#?}", port.0, alt_mode); port_status.alt_mode = alt_mode; // Update power path status - let power_path = self.tps6699x.get_power_path_status(port).await?; + let power_path = self + .tps6699x + .get_power_path_status(port) + .await + .map_err(|e| self.log_error(e))?; trace!("Port{} power source: {:#?}", port.0, power_path); port_status.power_path = match port { PORT0 => PowerPathStatus::new( @@ -474,34 +506,40 @@ impl Controller for Tps6699x<'_, M, B> { Ok(port_status) } - async fn get_rt_fw_update_status( - &mut self, - port: LocalPortId, - ) -> Result> { + async fn get_rt_fw_update_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rt_fw_update_status(port).await { Ok(true) => Ok(RetimerFwUpdateState::Active), Ok(false) => Ok(RetimerFwUpdateState::Inactive), - Err(e) => Err(e), + Err(e) => Err(self.log_error(e)), } } - async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_rt_fw_update_state(port).await + self.tps6699x + .set_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) } - async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.clear_rt_fw_update_state(port).await + self.tps6699x + .clear_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) } - async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_rt_compliance(port).await + self.tps6699x + .set_rt_compliance(port) + .await + .map_err(|e| self.log_error(e)) } - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let input = { let mut input = tps6699x::command::muxr::Input(0); @@ -509,44 +547,55 @@ impl Controller for Tps6699x<'_, M, B> { input }; - match self.tps6699x.execute_muxr(port, input).await? { + match self + .tps6699x + .execute_muxr(port, input) + .await + .map_err(|e| self.log_error(e))? + { ReturnValue::Success => Ok(()), r => { - debug!("Error executing MuxR on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing MuxR on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - match self.tps6699x.execute_dbfg(port).await? { + match self.tps6699x.execute_dbfg(port).await.map_err(|e| self.log_error(e))? { ReturnValue::Success => Ok(()), r => { - debug!("Error executing DBfg on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing DBfg on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } - async fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> Result<(), Error> { + async fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} enable sink path: {}", port.0, enable); - self.tps6699x.enable_sink_path(port, enable).await + self.tps6699x + .enable_sink_path(port, enable) + .await + .map_err(|e| self.log_error(e)) } - async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, Error> { + async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.get_rx_ado(port).await.map_err(Error::from) + self.tps6699x + .get_rx_ado(port) + .await + .map_err(|e| self.log_error(e.into())) } - async fn get_controller_status(&mut self) -> Result, Error> { + async fn get_controller_status(&mut self) -> Result, PdError> { self.guard_no_fw_update_active()?; - let boot_flags = self.tps6699x.get_boot_flags().await?; - let customer_use = CustomerUse(self.tps6699x.get_customer_use().await?); + let boot_flags = self.tps6699x.get_boot_flags().await.map_err(|e| self.log_error(e))?; + let customer_use = CustomerUse(self.tps6699x.get_customer_use().await.map_err(|e| self.log_error(e))?); Ok(ControllerStatus { - mode: self.tps6699x.get_mode().await?.into(), + mode: self.tps6699x.get_mode().await.map_err(|e| self.log_error(e))?.into(), valid_fw_bank: (boot_flags.active_bank() == 0 && boot_flags.bank0_valid() != 0) || (boot_flags.active_bank() == 1 && boot_flags.bank1_valid() != 0), fw_version0: customer_use.ti_fw_version(), @@ -554,33 +603,31 @@ impl Controller for Tps6699x<'_, M, B> { }) } - async fn set_unconstrained_power( - &mut self, - port: LocalPortId, - unconstrained: bool, - ) -> Result<(), Error> { + async fn set_unconstrained_power(&mut self, port: LocalPortId, unconstrained: bool) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_unconstrained_power(port, unconstrained).await + self.tps6699x + .set_unconstrained_power(port, unconstrained) + .await + .map_err(|e| self.log_error(e)) } - async fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> Result<(), Error> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_autonegotiate_sink_max_voltage(port, voltage_mv).await + self.tps6699x + .set_autonegotiate_sink_max_voltage(port, voltage_mv) + .await + .map_err(|e| self.log_error(e)) } - async fn get_other_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_other_vdm(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rx_other_vdm(port).await { Ok(vdm) => Ok((*vdm.as_bytes()).into()), - Err(e) => Err(e), + Err(e) => Err(self.log_error(e)), } } - async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rx_attn_vdm(port).await { Ok(vdm) => { @@ -588,11 +635,11 @@ impl Controller for Tps6699x<'_, M, B> { let attn_vdm: AttnVdm = buf.into(); Ok(attn_vdm) } - Err(e) => Err(e), + Err(e) => Err(self.log_error(e)), } } - async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), Error> { + async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let input = { let mut input = tps6699x::command::vdms::Input::default(); @@ -613,21 +660,22 @@ impl Controller for Tps6699x<'_, M, B> { input }; - match self.tps6699x.send_vdms(port, input).await? { + match self + .tps6699x + .send_vdms(port, input) + .await + .map_err(|e| self.log_error(e))? + { ReturnValue::Success => Ok(()), r => { - debug!("Error executing VDMs on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing VDMs on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } /// Set USB control configuration for the given port - async fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> Result<(), Error> { + async fn set_usb_control(&mut self, port: LocalPortId, config: UsbControlConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; match self.config.usb_control_method { UsbControlMethod::TxIdentity => { @@ -641,7 +689,8 @@ impl Controller for Tps6699x<'_, M, B> { identity.set_dfp1_vdo(dfp_vdo.0); identity.clone() }) - .await?; + .await + .map_err(|e| self.log_error(e))?; } UsbControlMethod::DpConfig => { use tps6699x::registers::DpUsbDataPath; @@ -656,7 +705,8 @@ impl Controller for Tps6699x<'_, M, B> { dp_config.set_usb_data_path(usb_data_path); *dp_config }) - .await?; + .await + .map_err(|e| self.log_error(e))?; } UsbControlMethod::TbtConfig => { use tps6699x::registers::TbtUsbDataPath; @@ -666,23 +716,26 @@ impl Controller for Tps6699x<'_, M, B> { TbtUsbDataPath::NotRequired }; - self.tps6699x - .lock_inner() - .await - .modify_tbt_config(port, |tbt_config| { - tbt_config.set_usb_data_path(usb_data_path); - *tbt_config - }) - .await?; + { + self.tps6699x + .lock_inner() + .await + .modify_tbt_config(port, |tbt_config| { + tbt_config.set_usb_data_path(usb_data_path); + *tbt_config + }) + .await + } + .map_err(|e| self.log_error(e))?; } } Ok(()) } - async fn get_dp_status(&mut self, port: LocalPortId) -> Result> { + async fn get_dp_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; - let dp_status = self.tps6699x.get_dp_status(port).await?; + let dp_status = self.tps6699x.get_dp_status(port).await.map_err(|e| self.log_error(e))?; debug!("Port{} DP status: {:#?}", port.0, dp_status); let alt_mode_entered = dp_status.dp_mode_active() != 0; @@ -697,11 +750,11 @@ impl Controller for Tps6699x<'_, M, B> { }) } - async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), Error> { + async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting DP config: {:#?}", port.0, config); - let mut dp_config_reg = self.tps6699x.get_dp_config(port).await?; + let mut dp_config_reg = self.tps6699x.get_dp_config(port).await.map_err(|e| self.log_error(e))?; debug!("Current DP config: {:#?}", dp_config_reg); @@ -709,57 +762,63 @@ impl Controller for Tps6699x<'_, M, B> { let cfg_raw: PdDpPinConfig = config.dfp_d_pin_cfg.into(); dp_config_reg.set_dfpd_pin_assignment(cfg_raw.bits()); - self.tps6699x.set_dp_config(port, dp_config_reg).await?; + self.tps6699x + .set_dp_config(port, dp_config_reg) + .await + .map_err(|e| self.log_error(e))?; Ok(()) } - async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - match self.tps6699x.execute_drst(port).await? { + match self.tps6699x.execute_drst(port).await.map_err(|e| self.log_error(e))? { ReturnValue::Success => Ok(()), r => { error!("Error executing DRST on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + Err(PdError::InvalidResponse) } } } - async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), Error> { + async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting TBT config: {:#?}", port.0, config); - let mut config_reg = self.tps6699x.lock_inner().await.get_tbt_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_tbt_config(port).await }.map_err(|e| self.log_error(e))?; config_reg.set_tbt_vid_en(config.tbt_enabled); config_reg.set_tbt_mode_en(config.tbt_enabled); - self.tps6699x.lock_inner().await.set_tbt_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_tbt_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } async fn set_pd_state_machine_config( &mut self, port: LocalPortId, config: PdStateMachineConfig, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting PD state machine config: {:#?}", port.0, config); - let mut config_reg = self.tps6699x.lock_inner().await.get_port_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_port_config(port).await }.map_err(|e| self.log_error(e))?; config_reg.set_disable_pd(!config.enabled); - self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } async fn set_type_c_state_machine_config( &mut self, port: LocalPortId, state: TypeCStateMachineState, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting Type-C state machine state: {:#?}", port.0, state); - let mut config_reg = self.tps6699x.lock_inner().await.get_port_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_port_config(port).await }.map_err(|e| self.log_error(e))?; let typec_state = match state { TypeCStateMachineState::Sink => TypeCStateMachine::Sink, TypeCStateMachineState::Source => TypeCStateMachine::Source, @@ -768,38 +827,39 @@ impl Controller for Tps6699x<'_, M, B> { }; config_reg.set_typec_state_machine(typec_state); - self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } - async fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> Result, Error> { + async fn execute_ucsi_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.execute_ucsi_command(&command).await + self.tps6699x + .execute_ucsi_command(&command) + .await + .map_err(|e| self.log_error(e)) } async fn execute_electrical_disconnect( &mut self, port: LocalPortId, reconnect_time_s: Option, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let reconnect_time_s = reconnect_time_s.map(|t| t.get()); - match self.tps6699x.execute_disc(port, reconnect_time_s).await? { + match self + .tps6699x + .execute_disc(port, reconnect_time_s) + .await + .map_err(|e| self.log_error(e))? + { ReturnValue::Success => Ok(()), r => { - debug!("Error executing DISC on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing DISC on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } - async fn set_power_state( - &mut self, - port: LocalPortId, - state: SystemPowerState, - ) -> Result<(), Error> { + async fn set_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { self.guard_no_fw_update_active()?; use tps6699x::registers::SystemPowerState as DriverSystemPowerState; @@ -811,7 +871,10 @@ impl Controller for Tps6699x<'_, M, B> { SystemPowerState::S0ix => DriverSystemPowerState::S0Ix, }; - self.tps6699x.set_sx_app_config(port, driver_state).await + self.tps6699x + .set_sx_app_config(port, driver_state) + .await + .map_err(|e| self.log_error(e)) } } From 653d291cd7c06255e49a29ffb8590d106e16149d Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 11:44:44 -0700 Subject: [PATCH 3/9] type-c-interface: Break-up `Controller` trait Break-up this trait to make everything more modular. --- .../std/src/lib/type_c/mock_controller.rs | 92 +++++---- .../src/controller/electrical_disconnect.rs | 17 ++ .../src/controller/max_sink_voltage.rs | 15 ++ type-c-interface/src/controller/mod.rs | 124 +----------- type-c-interface/src/controller/pd.rs | 65 +++++++ type-c-interface/src/controller/power.rs | 14 ++ type-c-interface/src/controller/retimer.rs | 20 ++ type-c-interface/src/controller/type_c.rs | 13 ++ type-c-interface/src/controller/ucsi.rs | 10 + type-c-service/src/bridge/mod.rs | 24 ++- type-c-service/src/controller/mod.rs | 8 +- type-c-service/src/controller/pd.rs | 2 +- type-c-service/src/controller/power.rs | 4 +- type-c-service/src/driver/tps6699x.rs | 178 ++++++++++-------- 14 files changed, 341 insertions(+), 245 deletions(-) create mode 100644 type-c-interface/src/controller/electrical_disconnect.rs create mode 100644 type-c-interface/src/controller/max_sink_voltage.rs create mode 100644 type-c-interface/src/controller/pd.rs create mode 100644 type-c-interface/src/controller/power.rs create mode 100644 type-c-interface/src/controller/retimer.rs create mode 100644 type-c-interface/src/controller/type_c.rs create mode 100644 type-c-interface/src/controller/ucsi.rs diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index 608112a86..c8462f011 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -135,16 +135,6 @@ impl type_c_service::controller::event_receiver::InterruptReceiv } impl type_c_interface::controller::Controller for Controller<'_> { - async fn get_port_status(&mut self, _port: LocalPortId) -> Result { - debug!("Get port status: {:#?}", *self.state.status.lock().await); - Ok(*self.state.status.lock().await) - } - - async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), PdError> { - debug!("Enable sink path: {enable}"); - Ok(()) - } - async fn get_controller_status(&mut self) -> Result, PdError> { debug!("Get controller status"); Ok(ControllerStatus { @@ -159,24 +149,16 @@ impl type_c_interface::controller::Controller for Controller<'_> { debug!("Reset controller"); Ok(()) } +} - async fn get_rt_fw_update_status(&mut self, _port: LocalPortId) -> Result { - debug!("Get retimer fw update status"); - Ok(RetimerFwUpdateState::Inactive) - } - - async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { - debug!("Set retimer fw update state"); - Ok(()) - } - - async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { - debug!("Clear retimer fw update state"); - Ok(()) +impl type_c_interface::controller::pd::Pd for Controller<'_> { + async fn get_port_status(&mut self, _port: LocalPortId) -> Result { + debug!("Get port status: {:#?}", *self.state.status.lock().await); + Ok(*self.state.status.lock().await) } - async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), PdError> { - debug!("Set retimer compliance"); + async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), PdError> { + debug!("Enable sink path: {enable}"); Ok(()) } @@ -196,16 +178,6 @@ impl type_c_interface::controller::Controller for Controller<'_> { Ok(()) } - async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { - debug!("Set max sink voltage for port {}: {:?}", port.0, voltage_mv); - Ok(()) - } - - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { - debug!("reconfigure_retimer(port: {port:?})"); - Ok(()) - } - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("clear_dead_battery_flag(port: {port:?})"); Ok(()) @@ -259,7 +231,16 @@ impl type_c_interface::controller::Controller for Controller<'_> { debug!("Set Thunderbolt config for port {port:?}: {config:?}"); Ok(()) } +} + +impl type_c_interface::controller::max_sink_voltage::MaxSinkVoltage for Controller<'_> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { + debug!("Set max sink voltage for port {}: {:?}", port.0, voltage_mv); + Ok(()) + } +} +impl type_c_interface::controller::pd::StateMachine for Controller<'_> { async fn set_pd_state_machine_config( &mut self, port: LocalPortId, @@ -268,7 +249,9 @@ impl type_c_interface::controller::Controller for Controller<'_> { debug!("Set PD State Machine config for port {port:?}: {config:?}"); Ok(()) } +} +impl type_c_interface::controller::type_c::StateMachine for Controller<'_> { async fn set_type_c_state_machine_config( &mut self, port: LocalPortId, @@ -277,8 +260,10 @@ impl type_c_interface::controller::Controller for Controller<'_> { debug!("Set Type-C State Machine state for port {port:?}: {state:?}"); Ok(()) } +} - async fn execute_ucsi_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { +impl type_c_interface::controller::ucsi::Lpm for Controller<'_> { + async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { debug!("Execute UCSI command for port {:?}: {command:?}", command.port()); match command.operation() { lpm::CommandData::GetConnectorStatus => Ok(Some(lpm::ResponseData::GetConnectorStatus( @@ -287,7 +272,9 @@ impl type_c_interface::controller::Controller for Controller<'_> { _ => Err(PdError::UnrecognizedCommand.into()), } } +} +impl type_c_interface::controller::electrical_disconnect::ElectricalDisconnect for Controller<'_> { async fn execute_electrical_disconnect( &mut self, port: LocalPortId, @@ -296,9 +283,38 @@ impl type_c_interface::controller::Controller for Controller<'_> { debug!("Execute electrical disconnect for port {port:?} with reconnect time {reconnect_time_s:?}"); Ok(()) } +} + +impl type_c_interface::controller::power::SystemPowerState for Controller<'_> { + async fn set_system_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { + debug!("Set system power state for port {port:?}: {state:?}"); + Ok(()) + } +} - async fn set_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { - debug!("Set power state for port {port:?}: {state:?}"); +impl type_c_interface::controller::retimer::Retimer for Controller<'_> { + async fn get_rt_fw_update_status(&mut self, _port: LocalPortId) -> Result { + debug!("Get retimer fw update status"); + Ok(RetimerFwUpdateState::Inactive) + } + + async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Set retimer fw update state"); + Ok(()) + } + + async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Clear retimer fw update state"); + Ok(()) + } + + async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Set retimer compliance"); + Ok(()) + } + + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { + debug!("reconfigure_retimer(port: {port:?})"); Ok(()) } } diff --git a/type-c-interface/src/controller/electrical_disconnect.rs b/type-c-interface/src/controller/electrical_disconnect.rs new file mode 100644 index 000000000..f4d54df74 --- /dev/null +++ b/type-c-interface/src/controller/electrical_disconnect.rs @@ -0,0 +1,17 @@ +use core::num::NonZeroU8; + +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::controller::pd::Pd; + +pub trait ElectricalDisconnect: Pd { + /// Execute an electrical disconnect on the given port, if supported by the controller. + /// + /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time + /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. + fn execute_electrical_disconnect( + &mut self, + port: LocalPortId, + reconnect_time_s: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/max_sink_voltage.rs b/type-c-interface/src/controller/max_sink_voltage.rs new file mode 100644 index 000000000..706282331 --- /dev/null +++ b/type-c-interface/src/controller/max_sink_voltage.rs @@ -0,0 +1,15 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::controller::pd::Pd; + +/// Functionality related to setting the maximum sink voltage for a port. +pub trait MaxSinkVoltage: Pd { + /// Set the maximum sink voltage for the given port + /// + /// This may trigger a renegotiation + fn set_max_sink_voltage( + &mut self, + port: LocalPortId, + voltage_mv: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs index 89abe3fbd..37e921ab6 100644 --- a/type-c-interface/src/controller/mod.rs +++ b/type-c-interface/src/controller/mod.rs @@ -1,18 +1,15 @@ //! Module for PD controller related code -use core::future::Future; -use core::num::NonZeroU8; +//! use embedded_usb_pd::{LocalPortId, PdError}; -use embedded_usb_pd::ado::Ado; -use embedded_usb_pd::{LocalPortId, PdError, ucsi::lpm}; +use embedded_usb_pd::PdError; -use crate::control::dp::{DpConfig, DpStatus}; -use crate::control::pd::{PdStateMachineConfig, PortStatus}; -use crate::control::power::SystemPowerState; -use crate::control::retimer::RetimerFwUpdateState; -use crate::control::tbt::TbtConfig; -use crate::control::type_c::TypeCStateMachineState; -use crate::control::usb::UsbControlConfig; -use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +pub mod electrical_disconnect; +pub mod max_sink_voltage; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod type_c; +pub mod ucsi; /// Controller status #[derive(Copy, Clone, Debug)] @@ -35,112 +32,9 @@ pub struct ControllerId(pub u8); /// PD controller trait pub trait Controller { - /// Returns the port status - fn get_port_status(&mut self, port: LocalPortId) -> impl Future>; - /// Reset the controller fn reset_controller(&mut self) -> impl Future>; - /// Returns the retimer fw update state - fn get_rt_fw_update_status( - &mut self, - port: LocalPortId, - ) -> impl Future>; - /// Set retimer fw update state - fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; - /// Clear retimer fw update state - fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; - /// Set retimer compliance - fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>; - - /// Reconfigure the retimer for the given port. - fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>; - - /// Clear the dead battery flag for the given port. - fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> impl Future>; - - /// Enable or disable sink path - fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> impl Future>; /// Get current controller status fn get_controller_status(&mut self) -> impl Future, PdError>>; - /// Get current PD alert - fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, PdError>>; - /// Set the maximum sink voltage for the given port - /// - /// This may trigger a renegotiation - fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> impl Future>; - /// Set port unconstrained status - fn set_unconstrained_power( - &mut self, - port: LocalPortId, - unconstrained: bool, - ) -> impl Future>; - - /// Get the Rx Other VDM data for the given port - fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>; - /// Get the Rx Attention VDM data for the given port - fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>; - /// Send a VDM to the given port - fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> impl Future>; - - /// Set USB control configuration for the given port - fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> impl Future>; - - /// Get DisplayPort status for the given port - fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>; - /// Set DisplayPort configuration for the given port - fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> impl Future>; - /// Execute PD Data Reset for the given port - fn execute_drst(&mut self, port: LocalPortId) -> impl Future>; - - /// Set Thunderbolt configuration for the given port - fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> impl Future>; - - /// Set PD state-machine configuration for the given port - fn set_pd_state_machine_config( - &mut self, - port: LocalPortId, - config: PdStateMachineConfig, - ) -> impl Future>; - - /// Set Type-C state-machine configuration for the given port - fn set_type_c_state_machine_config( - &mut self, - port: LocalPortId, - state: TypeCStateMachineState, - ) -> impl Future>; - - /// Execute the given UCSI command - fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> impl Future, PdError>>; - - /// Execute an electrical disconnect on the given port, if supported by the controller. - /// - /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time - /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. - fn execute_electrical_disconnect( - &mut self, - port: LocalPortId, - reconnect_time_s: Option, - ) -> impl Future>; - - /// Set the system power state on the given port. - /// - /// This notifies the PD controller of the current system power state, - /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). - fn set_power_state( - &mut self, - port: LocalPortId, - state: SystemPowerState, - ) -> impl Future>; } diff --git a/type-c-interface/src/controller/pd.rs b/type-c-interface/src/controller/pd.rs new file mode 100644 index 000000000..f909f4847 --- /dev/null +++ b/type-c-interface/src/controller/pd.rs @@ -0,0 +1,65 @@ +use embedded_usb_pd::{LocalPortId, PdError, ado::Ado}; + +use crate::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, +}; + +/// Trait for basic functionality from the PD spec. +pub trait Pd { + /// Returns the port status + fn get_port_status(&mut self, port: LocalPortId) -> impl Future>; + + /// Clear the dead battery flag for the given port. + fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> impl Future>; + + /// Enable or disable sink path + fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> impl Future>; + + /// Get current PD alert + fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, PdError>>; + + /// Set port unconstrained status + fn set_unconstrained_power( + &mut self, + port: LocalPortId, + unconstrained: bool, + ) -> impl Future>; + + /// Get the Rx Other VDM data for the given port + fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>; + /// Get the Rx Attention VDM data for the given port + fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>; + /// Send a VDM to the given port + fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> impl Future>; + /// Execute PD Data Reset for the given port + fn execute_drst(&mut self, port: LocalPortId) -> impl Future>; + + /// Get DisplayPort status for the given port + fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>; + /// Set DisplayPort configuration for the given port + fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> impl Future>; + + /// Set Thunderbolt configuration for the given port + fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> impl Future>; + + /// Set USB control configuration for the given port + fn set_usb_control( + &mut self, + port: LocalPortId, + config: UsbControlConfig, + ) -> impl Future>; +} + +/// PD state machine related controller functionality +pub trait StateMachine: Pd { + /// Set PD state-machine configuration for the given port + fn set_pd_state_machine_config( + &mut self, + port: LocalPortId, + config: PdStateMachineConfig, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/power.rs b/type-c-interface/src/controller/power.rs new file mode 100644 index 000000000..5046a410b --- /dev/null +++ b/type-c-interface/src/controller/power.rs @@ -0,0 +1,14 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +/// System power state related controller functionality +pub trait SystemPowerState { + /// Set the system power state on the given port. + /// + /// This notifies the PD controller of the current system power state, + /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). + fn set_system_power_state( + &mut self, + port: LocalPortId, + state: crate::control::power::SystemPowerState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/retimer.rs b/type-c-interface/src/controller/retimer.rs new file mode 100644 index 000000000..843a53b76 --- /dev/null +++ b/type-c-interface/src/controller/retimer.rs @@ -0,0 +1,20 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::control::retimer::RetimerFwUpdateState; + +/// Retimer-related functionality +pub trait Retimer { + /// Returns the retimer fw update state + fn get_rt_fw_update_status( + &mut self, + port: LocalPortId, + ) -> impl Future>; + /// Set retimer fw update state + fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; + /// Clear retimer fw update state + fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; + /// Set retimer compliance + fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>; + /// Reconfigure the retimer for the given port. + fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>; +} diff --git a/type-c-interface/src/controller/type_c.rs b/type-c-interface/src/controller/type_c.rs new file mode 100644 index 000000000..fd7271c55 --- /dev/null +++ b/type-c-interface/src/controller/type_c.rs @@ -0,0 +1,13 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::{control::type_c::TypeCStateMachineState, controller::pd::Pd}; + +/// Type-C state machine related controller functionality +pub trait StateMachine: Pd { + /// Set Type-C state-machine configuration for the given port + fn set_type_c_state_machine_config( + &mut self, + port: LocalPortId, + state: TypeCStateMachineState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/ucsi.rs b/type-c-interface/src/controller/ucsi.rs new file mode 100644 index 000000000..2ed23175b --- /dev/null +++ b/type-c-interface/src/controller/ucsi.rs @@ -0,0 +1,10 @@ +use embedded_usb_pd::{PdError, ucsi::lpm}; + +/// UCSI LPM command execution trait +pub trait Lpm { + /// Execute the given LPM command + fn execute_lpm_command( + &mut self, + command: lpm::LocalCommand, + ) -> impl Future, PdError>>; +} diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index 909392cb8..93a611eaf 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -2,19 +2,31 @@ use embedded_services::{debug, sync::Lockable}; use embedded_usb_pd::{PdError, ucsi::lpm}; -use type_c_interface::controller::Controller as _; +use type_c_interface::controller::{ + Controller, + pd::{Pd, StateMachine as PdStateMachine}, + retimer::Retimer, + type_c::StateMachine as TypeCStateMachine, + ucsi::Lpm as UcsiLpm, +}; use type_c_interface::port::{self, InternalResponseData, Response}; use crate::bridge::event_receiver::{ControllerCommand, OutputControllerCommand}; pub mod event_receiver; -pub struct Bridge<'device, Controller: Lockable> { - controller: &'device Controller, +pub struct Bridge<'device, C: Lockable> +where + C::Inner: Controller + Pd + PdStateMachine + Retimer + TypeCStateMachine + UcsiLpm, +{ + controller: &'device C, registration: &'static port::Device<'static>, } -impl<'device, Controller: Lockable> Bridge<'device, Controller> { - pub fn new(controller: &'device Controller, registration: &'static port::Device<'static>) -> Self { +impl<'device, C: Lockable> Bridge<'device, C> +where + C::Inner: Controller + Pd + PdStateMachine + Retimer + TypeCStateMachine + UcsiLpm, +{ + pub fn new(controller: &'device C, registration: &'static port::Device<'static>) -> Self { Self { controller, registration, @@ -104,7 +116,7 @@ impl<'device, Controller: Lockable Ok(port::PortResponseData::UcsiResponse( controller - .execute_ucsi_command(lpm::Command::new(local_port, command_data)) + .execute_lpm_command(lpm::Command::new(local_port, command_data)) .await, )), }) diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index df7a7f5f0..ba3df3648 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -3,7 +3,7 @@ use embedded_services::{debug, error, event::Sender, info, named::Named, sync::L use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError}; use power_policy_interface::psu::PsuState; use type_c_interface::control::pd::PortStatus; -use type_c_interface::controller::Controller; +use type_c_interface::controller::pd::Pd; use type_c_interface::port::{event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield}; use type_c_interface::service::event::{ PortEvent as ServicePortEvent, PortEventData as ServicePortEventData, StatusChangedData, @@ -22,7 +22,7 @@ pub mod state; pub struct Port< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -53,7 +53,7 @@ pub struct Port< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -220,7 +220,7 @@ impl< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index 2158b9f38..cb48bab1a 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -8,7 +8,7 @@ use crate::controller::state::SharedState; impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index 4f353e4a1..fdfb0a4bb 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -16,7 +16,7 @@ use super::*; impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -111,7 +111,7 @@ impl< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index b08708a47..2d24170f0 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -37,6 +37,8 @@ use type_c_interface::control::tbt::TbtConfig; use type_c_interface::control::type_c::TypeCStateMachineState; use type_c_interface::control::usb::UsbControlConfig; use type_c_interface::control::vdm::{ATTN_VDM_LEN, AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::controller::pd::Pd; +use type_c_interface::controller::retimer::Retimer; use type_c_interface::controller::{Controller, ControllerStatus}; use type_c_interface::port::event::PortEventBitfield; @@ -353,6 +355,22 @@ impl Controller for Tps6699x<'_, M, B> { Ok(()) } + async fn get_controller_status(&mut self) -> Result, PdError> { + self.guard_no_fw_update_active()?; + let boot_flags = self.tps6699x.get_boot_flags().await.map_err(|e| self.log_error(e))?; + let customer_use = CustomerUse(self.tps6699x.get_customer_use().await.map_err(|e| self.log_error(e))?); + + Ok(ControllerStatus { + mode: self.tps6699x.get_mode().await.map_err(|e| self.log_error(e))?.into(), + valid_fw_bank: (boot_flags.active_bank() == 0 && boot_flags.bank0_valid() != 0) + || (boot_flags.active_bank() == 1 && boot_flags.bank1_valid() != 0), + fw_version0: customer_use.ti_fw_version(), + fw_version1: customer_use.custom_fw_version(), + }) + } +} + +impl Pd for Tps6699x<'_, M, B> { /// Returns the current status of the port async fn get_port_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; @@ -506,61 +524,6 @@ impl Controller for Tps6699x<'_, M, B> { Ok(port_status) } - async fn get_rt_fw_update_status(&mut self, port: LocalPortId) -> Result { - self.guard_no_fw_update_active()?; - match self.tps6699x.get_rt_fw_update_status(port).await { - Ok(true) => Ok(RetimerFwUpdateState::Active), - Ok(false) => Ok(RetimerFwUpdateState::Inactive), - Err(e) => Err(self.log_error(e)), - } - } - - async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { - self.guard_no_fw_update_active()?; - self.tps6699x - .set_rt_fw_update_state(port) - .await - .map_err(|e| self.log_error(e)) - } - - async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { - self.guard_no_fw_update_active()?; - self.tps6699x - .clear_rt_fw_update_state(port) - .await - .map_err(|e| self.log_error(e)) - } - - async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), PdError> { - self.guard_no_fw_update_active()?; - self.tps6699x - .set_rt_compliance(port) - .await - .map_err(|e| self.log_error(e)) - } - - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { - self.guard_no_fw_update_active()?; - let input = { - let mut input = tps6699x::command::muxr::Input(0); - input.set_en_retry_on_target_addr_tbt(true); - input - }; - - match self - .tps6699x - .execute_muxr(port, input) - .await - .map_err(|e| self.log_error(e))? - { - ReturnValue::Success => Ok(()), - r => { - error!("Error executing MuxR on port {}: {:#?}", port.0, r); - Err(PdError::InvalidResponse) - } - } - } - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; match self.tps6699x.execute_dbfg(port).await.map_err(|e| self.log_error(e))? { @@ -589,20 +552,6 @@ impl Controller for Tps6699x<'_, M, B> { .map_err(|e| self.log_error(e.into())) } - async fn get_controller_status(&mut self) -> Result, PdError> { - self.guard_no_fw_update_active()?; - let boot_flags = self.tps6699x.get_boot_flags().await.map_err(|e| self.log_error(e))?; - let customer_use = CustomerUse(self.tps6699x.get_customer_use().await.map_err(|e| self.log_error(e))?); - - Ok(ControllerStatus { - mode: self.tps6699x.get_mode().await.map_err(|e| self.log_error(e))?.into(), - valid_fw_bank: (boot_flags.active_bank() == 0 && boot_flags.bank0_valid() != 0) - || (boot_flags.active_bank() == 1 && boot_flags.bank1_valid() != 0), - fw_version0: customer_use.ti_fw_version(), - fw_version1: customer_use.custom_fw_version(), - }) - } - async fn set_unconstrained_power(&mut self, port: LocalPortId, unconstrained: bool) -> Result<(), PdError> { self.guard_no_fw_update_active()?; self.tps6699x @@ -611,14 +560,6 @@ impl Controller for Tps6699x<'_, M, B> { .map_err(|e| self.log_error(e)) } - async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { - self.guard_no_fw_update_active()?; - self.tps6699x - .set_autonegotiate_sink_max_voltage(port, voltage_mv) - .await - .map_err(|e| self.log_error(e)) - } - async fn get_other_vdm(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rx_other_vdm(port).await { @@ -792,7 +733,66 @@ impl Controller for Tps6699x<'_, M, B> { { self.tps6699x.lock_inner().await.set_tbt_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} +impl Retimer for Tps6699x<'_, M, B> { + async fn get_rt_fw_update_status(&mut self, port: LocalPortId) -> Result { + self.guard_no_fw_update_active()?; + match self.tps6699x.get_rt_fw_update_status(port).await { + Ok(true) => Ok(RetimerFwUpdateState::Active), + Ok(false) => Ok(RetimerFwUpdateState::Inactive), + Err(e) => Err(self.log_error(e)), + } + } + + async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .clear_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_rt_compliance(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + let input = { + let mut input = tps6699x::command::muxr::Input(0); + input.set_en_retry_on_target_addr_tbt(true); + input + }; + + match self + .tps6699x + .execute_muxr(port, input) + .await + .map_err(|e| self.log_error(e))? + { + ReturnValue::Success => Ok(()), + r => { + error!("Error executing MuxR on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) + } + } + } +} + +impl type_c_interface::controller::pd::StateMachine for Tps6699x<'_, M, B> { async fn set_pd_state_machine_config( &mut self, port: LocalPortId, @@ -808,7 +808,9 @@ impl Controller for Tps6699x<'_, M, B> { { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} +impl type_c_interface::controller::type_c::StateMachine for Tps6699x<'_, M, B> { async fn set_type_c_state_machine_config( &mut self, port: LocalPortId, @@ -829,15 +831,21 @@ impl Controller for Tps6699x<'_, M, B> { config_reg.set_typec_state_machine(typec_state); { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} - async fn execute_ucsi_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { +impl type_c_interface::controller::ucsi::Lpm for Tps6699x<'_, M, B> { + async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { self.guard_no_fw_update_active()?; self.tps6699x .execute_ucsi_command(&command) .await .map_err(|e| self.log_error(e)) } +} +impl type_c_interface::controller::electrical_disconnect::ElectricalDisconnect + for Tps6699x<'_, M, B> +{ async fn execute_electrical_disconnect( &mut self, port: LocalPortId, @@ -858,8 +866,10 @@ impl Controller for Tps6699x<'_, M, B> { } } } +} - async fn set_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { +impl type_c_interface::controller::power::SystemPowerState for Tps6699x<'_, M, B> { + async fn set_system_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { self.guard_no_fw_update_active()?; use tps6699x::registers::SystemPowerState as DriverSystemPowerState; @@ -878,6 +888,16 @@ impl Controller for Tps6699x<'_, M, B> { } } +impl type_c_interface::controller::max_sink_voltage::MaxSinkVoltage for Tps6699x<'_, M, B> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_autonegotiate_sink_max_voltage(port, voltage_mv) + .await + .map_err(|e| self.log_error(e)) + } +} + impl<'a, M: RawMutex, BUS: I2c> AsRef> for Tps6699x<'a, M, BUS> { fn as_ref(&self) -> &tps6699x_drv::Tps6699x<'a, M, BUS> { &self.tps6699x From 4dce0e4252a2e4f1f361f0a45e31dec0333fb4e4 Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 13:14:47 -0700 Subject: [PATCH 4/9] type-c-interface: Add corresponding per-port traits --- .../src/port/electrical_disconnect.rs | 16 ++++++ type-c-interface/src/port/max_sink_voltage.rs | 11 ++++ type-c-interface/src/port/mod.rs | 7 +++ type-c-interface/src/port/pd.rs | 56 +++++++++++++++++++ type-c-interface/src/port/power.rs | 13 +++++ type-c-interface/src/port/retimer.rs | 17 ++++++ type-c-interface/src/port/type_c.rs | 12 ++++ type-c-interface/src/port/ucsi.rs | 10 ++++ 8 files changed, 142 insertions(+) create mode 100644 type-c-interface/src/port/electrical_disconnect.rs create mode 100644 type-c-interface/src/port/max_sink_voltage.rs create mode 100644 type-c-interface/src/port/pd.rs create mode 100644 type-c-interface/src/port/power.rs create mode 100644 type-c-interface/src/port/retimer.rs create mode 100644 type-c-interface/src/port/type_c.rs create mode 100644 type-c-interface/src/port/ucsi.rs diff --git a/type-c-interface/src/port/electrical_disconnect.rs b/type-c-interface/src/port/electrical_disconnect.rs new file mode 100644 index 000000000..d0b62d437 --- /dev/null +++ b/type-c-interface/src/port/electrical_disconnect.rs @@ -0,0 +1,16 @@ +use core::num::NonZeroU8; + +use embedded_usb_pd::PdError; + +use crate::port::pd::Pd; + +pub trait ElectricalDisconnect: Pd { + /// Execute an electrical disconnect on this port, if supported by the controller. + /// + /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time + /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. + fn execute_electrical_disconnect( + &mut self, + reconnect_time_s: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/max_sink_voltage.rs b/type-c-interface/src/port/max_sink_voltage.rs new file mode 100644 index 000000000..a37c8a116 --- /dev/null +++ b/type-c-interface/src/port/max_sink_voltage.rs @@ -0,0 +1,11 @@ +use embedded_usb_pd::PdError; + +use crate::port::pd::Pd; + +/// Functionality related to setting the maximum sink voltage for a port. +pub trait MaxSinkVoltage: Pd { + /// Set the maximum sink voltage for this port + /// + /// This may trigger a renegotiation + fn set_max_sink_voltage(&mut self, voltage_mv: Option) -> impl Future>; +} diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index a3784db03..bbd6db096 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -6,7 +6,14 @@ use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError, ado::Ado}; use embedded_services::ipc::deferred; use embedded_services::{GlobalRawMutex, intrusive_list}; +pub mod electrical_disconnect; pub mod event; +pub mod max_sink_voltage; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod type_c; +pub mod ucsi; use crate::control::dp::{DpConfig, DpStatus}; use crate::control::pd::PdStateMachineConfig; diff --git a/type-c-interface/src/port/pd.rs b/type-c-interface/src/port/pd.rs new file mode 100644 index 000000000..2f00ca68d --- /dev/null +++ b/type-c-interface/src/port/pd.rs @@ -0,0 +1,56 @@ +use embedded_usb_pd::{PdError, ado::Ado}; + +use crate::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, +}; + +/// Trait for basic functionality from the PD spec. +pub trait Pd { + /// Returns the port status + fn get_port_status(&mut self) -> impl Future>; + + /// Clear the dead battery flag for this port. + fn clear_dead_battery_flag(&mut self) -> impl Future>; + + /// Enable or disable sink path + fn enable_sink_path(&mut self, enable: bool) -> impl Future>; + + /// Get current PD alert + fn get_pd_alert(&mut self) -> impl Future, PdError>>; + + /// Set port unconstrained status + fn set_unconstrained_power(&mut self, unconstrained: bool) -> impl Future>; + + /// Get the Rx Other VDM data for this port + fn get_other_vdm(&mut self) -> impl Future>; + /// Get the Rx Attention VDM data for this port + fn get_attn_vdm(&mut self) -> impl Future>; + /// Send a VDM to this port + fn send_vdm(&mut self, tx_vdm: SendVdm) -> impl Future>; + /// Execute PD Data Reset for this port + fn execute_drst(&mut self) -> impl Future>; + + /// Get DisplayPort status for this port + fn get_dp_status(&mut self) -> impl Future>; + /// Set DisplayPort configuration for this port + fn set_dp_config(&mut self, config: DpConfig) -> impl Future>; + + /// Set Thunderbolt configuration for this port + fn set_tbt_config(&mut self, config: TbtConfig) -> impl Future>; + + /// Set USB control configuration for this port + fn set_usb_control(&mut self, config: UsbControlConfig) -> impl Future>; +} + +/// PD state machine related controller functionality +pub trait StateMachine: Pd { + /// Set PD state-machine configuration for this port + fn set_pd_state_machine_config( + &mut self, + config: PdStateMachineConfig, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/power.rs b/type-c-interface/src/port/power.rs new file mode 100644 index 000000000..c247cef39 --- /dev/null +++ b/type-c-interface/src/port/power.rs @@ -0,0 +1,13 @@ +use embedded_usb_pd::PdError; + +/// System power state related controller functionality +pub trait SystemPowerState { + /// Set the system power state on this port. + /// + /// This notifies the PD controller of the current system power state, + /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). + fn set_system_power_state( + &mut self, + state: crate::control::power::SystemPowerState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/retimer.rs b/type-c-interface/src/port/retimer.rs new file mode 100644 index 000000000..d64962c2c --- /dev/null +++ b/type-c-interface/src/port/retimer.rs @@ -0,0 +1,17 @@ +use embedded_usb_pd::PdError; + +use crate::control::retimer::RetimerFwUpdateState; + +/// Retimer-related functionality +pub trait Retimer { + /// Returns the retimer fw update state + fn get_rt_fw_update_status(&mut self) -> impl Future>; + /// Set retimer fw update state + fn set_rt_fw_update_state(&mut self) -> impl Future>; + /// Clear retimer fw update state + fn clear_rt_fw_update_state(&mut self) -> impl Future>; + /// Set retimer compliance + fn set_rt_compliance(&mut self) -> impl Future>; + /// Reconfigure the retimer for this port. + fn reconfigure_retimer(&mut self) -> impl Future>; +} diff --git a/type-c-interface/src/port/type_c.rs b/type-c-interface/src/port/type_c.rs new file mode 100644 index 000000000..5d24fb528 --- /dev/null +++ b/type-c-interface/src/port/type_c.rs @@ -0,0 +1,12 @@ +use embedded_usb_pd::PdError; + +use crate::{control::type_c::TypeCStateMachineState, port::pd::Pd}; + +/// Type-C state machine related controller functionality +pub trait StateMachine: Pd { + /// Set Type-C state-machine configuration for this port + fn set_type_c_state_machine_config( + &mut self, + state: TypeCStateMachineState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/ucsi.rs b/type-c-interface/src/port/ucsi.rs new file mode 100644 index 000000000..2b5a6e47e --- /dev/null +++ b/type-c-interface/src/port/ucsi.rs @@ -0,0 +1,10 @@ +use embedded_usb_pd::{PdError, ucsi::lpm}; + +/// UCSI LPM command execution trait +pub trait Lpm { + /// Execute the given LPM command + fn execute_lpm_command( + &mut self, + command: lpm::LocalCommand, + ) -> impl Future, PdError>>; +} From 03dd7830794758c94e290d4984905318ff01ead2 Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 15:17:03 -0700 Subject: [PATCH 5/9] type-c-interface: Combine redundant UCSI traits The LPM command contains the port number. Combine controller and port ucsi traits. --- type-c-interface/src/controller/mod.rs | 1 - type-c-interface/src/lib.rs | 1 + type-c-interface/src/port/mod.rs | 2 -- type-c-interface/src/port/ucsi.rs | 10 ---------- type-c-interface/src/{controller => }/ucsi.rs | 0 type-c-service/src/bridge/mod.rs | 2 +- type-c-service/src/driver/tps6699x.rs | 2 +- 7 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 type-c-interface/src/port/ucsi.rs rename type-c-interface/src/{controller => }/ucsi.rs (100%) diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs index 37e921ab6..b24158ecf 100644 --- a/type-c-interface/src/controller/mod.rs +++ b/type-c-interface/src/controller/mod.rs @@ -9,7 +9,6 @@ pub mod pd; pub mod power; pub mod retimer; pub mod type_c; -pub mod ucsi; /// Controller status #[derive(Copy, Clone, Debug)] diff --git a/type-c-interface/src/lib.rs b/type-c-interface/src/lib.rs index 5adcc451b..aaa86cafa 100644 --- a/type-c-interface/src/lib.rs +++ b/type-c-interface/src/lib.rs @@ -4,3 +4,4 @@ pub mod control; pub mod controller; pub mod port; pub mod service; +pub mod ucsi; diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index bbd6db096..2186b2c9f 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -13,8 +13,6 @@ pub mod pd; pub mod power; pub mod retimer; pub mod type_c; -pub mod ucsi; - use crate::control::dp::{DpConfig, DpStatus}; use crate::control::pd::PdStateMachineConfig; use crate::control::retimer::RetimerFwUpdateState; diff --git a/type-c-interface/src/port/ucsi.rs b/type-c-interface/src/port/ucsi.rs deleted file mode 100644 index 2b5a6e47e..000000000 --- a/type-c-interface/src/port/ucsi.rs +++ /dev/null @@ -1,10 +0,0 @@ -use embedded_usb_pd::{PdError, ucsi::lpm}; - -/// UCSI LPM command execution trait -pub trait Lpm { - /// Execute the given LPM command - fn execute_lpm_command( - &mut self, - command: lpm::LocalCommand, - ) -> impl Future, PdError>>; -} diff --git a/type-c-interface/src/controller/ucsi.rs b/type-c-interface/src/ucsi.rs similarity index 100% rename from type-c-interface/src/controller/ucsi.rs rename to type-c-interface/src/ucsi.rs diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index 93a611eaf..0f87d6e92 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -7,9 +7,9 @@ use type_c_interface::controller::{ pd::{Pd, StateMachine as PdStateMachine}, retimer::Retimer, type_c::StateMachine as TypeCStateMachine, - ucsi::Lpm as UcsiLpm, }; use type_c_interface::port::{self, InternalResponseData, Response}; +use type_c_interface::ucsi::Lpm as UcsiLpm; use crate::bridge::event_receiver::{ControllerCommand, OutputControllerCommand}; pub mod event_receiver; diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index 2d24170f0..bfa2afc62 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -833,7 +833,7 @@ impl type_c_interface::controller::type_c::StateMachine for } } -impl type_c_interface::controller::ucsi::Lpm for Tps6699x<'_, M, B> { +impl type_c_interface::ucsi::Lpm for Tps6699x<'_, M, B> { async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { self.guard_no_fw_update_active()?; self.tps6699x From 501fc6d356e012d8e190a6db2d62518133b63483 Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 15:27:57 -0700 Subject: [PATCH 6/9] type-c-interface/controller: Remove `get_controller_status` function This information is too hardware specific to expose it in a trait. --- examples/std/src/bin/type_c/basic.rs | 16 ++--------- .../std/src/lib/type_c/mock_controller.rs | 13 +-------- type-c-interface/src/controller/mod.rs | 17 ------------ type-c-interface/src/port/mod.rs | 20 ++++++-------- type-c-interface/src/service/context.rs | 27 +++---------------- type-c-service/src/bridge/event_receiver.rs | 4 +-- type-c-service/src/bridge/mod.rs | 9 ++----- type-c-service/src/driver/tps6699x.rs | 16 +---------- 8 files changed, 19 insertions(+), 103 deletions(-) diff --git a/examples/std/src/bin/type_c/basic.rs b/examples/std/src/bin/type_c/basic.rs index 9422bb2de..516e56069 100644 --- a/examples/std/src/bin/type_c/basic.rs +++ b/examples/std/src/bin/type_c/basic.rs @@ -6,7 +6,7 @@ use embedded_services::GlobalRawMutex; use embedded_usb_pd::{GlobalPortId, PdError as Error}; use log::*; use static_cell::StaticCell; -use type_c_interface::controller::{ControllerId, ControllerStatus}; +use type_c_interface::controller::ControllerId; use type_c_interface::port::{self, PortRegistration}; use type_c_interface::service::context::{Context, DeviceContainer}; use type_c_interface::service::event::PortEvent as ServicePortEvent; @@ -41,21 +41,12 @@ mod test_controller { async fn process_controller_command( &self, command: port::InternalCommandData, - ) -> Result, Error> { + ) -> Result { match command { port::InternalCommandData::Reset => { info!("Reset controller"); Ok(port::InternalResponseData::Complete) } - port::InternalCommandData::Status => { - info!("Get controller status"); - Ok(port::InternalResponseData::Status(ControllerStatus { - mode: "Test", - valid_fw_bank: true, - fw_version0: 0xbadf00d, - fw_version1: 0xdeadbeef, - })) - } port::InternalCommandData::SyncState => { info!("Sync controller state"); Ok(port::InternalResponseData::Complete) @@ -123,9 +114,6 @@ async fn task(spawner: Spawner) { Timer::after_secs(1).await; controller_context.reset_controller(CONTROLLER0_ID).await.unwrap(); - - let status = controller_context.get_controller_status(CONTROLLER0_ID).await.unwrap(); - info!("Controller 0 status: {status:#?}"); } fn main() { diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index c8462f011..5eb06116e 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -17,7 +17,6 @@ use type_c_interface::control::tbt::TbtConfig; use type_c_interface::control::type_c::TypeCStateMachineState; use type_c_interface::control::usb::UsbControlConfig; use type_c_interface::control::vdm::{AttnVdm, OtherVdm, SendVdm}; -use type_c_interface::controller::ControllerStatus; use type_c_interface::port::event::PortEventBitfield; use type_c_service::controller::state::SharedState; use type_c_service::util::power_capability_from_current; @@ -135,16 +134,6 @@ impl type_c_service::controller::event_receiver::InterruptReceiv } impl type_c_interface::controller::Controller for Controller<'_> { - async fn get_controller_status(&mut self) -> Result, PdError> { - debug!("Get controller status"); - Ok(ControllerStatus { - mode: "Test", - valid_fw_bank: true, - fw_version0: 0xbadf00d, - fw_version1: 0xdeadbeef, - }) - } - async fn reset_controller(&mut self) -> Result<(), PdError> { debug!("Reset controller"); Ok(()) @@ -262,7 +251,7 @@ impl type_c_interface::controller::type_c::StateMachine for Controller<'_> { } } -impl type_c_interface::controller::ucsi::Lpm for Controller<'_> { +impl type_c_interface::ucsi::Lpm for Controller<'_> { async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { debug!("Execute UCSI command for port {:?}: {command:?}", command.port()); match command.operation() { diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs index b24158ecf..1edc0069c 100644 --- a/type-c-interface/src/controller/mod.rs +++ b/type-c-interface/src/controller/mod.rs @@ -10,20 +10,6 @@ pub mod power; pub mod retimer; pub mod type_c; -/// Controller status -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerStatus<'a> { - /// Current controller mode - pub mode: &'a str, - /// True if we did not have to boot from a backup FW bank - pub valid_fw_bank: bool, - /// FW version 0 - pub fw_version0: u32, - /// FW version 1 - pub fw_version1: u32, -} - /// Controller ID #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -33,7 +19,4 @@ pub struct ControllerId(pub u8); pub trait Controller { /// Reset the controller fn reset_controller(&mut self) -> impl Future>; - - /// Get current controller status - fn get_controller_status(&mut self) -> impl Future, PdError>>; } diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index 2186b2c9f..ffc8e8bb8 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -20,7 +20,7 @@ use crate::control::tbt::TbtConfig; use crate::control::type_c::TypeCStateMachineState; use crate::control::usb::UsbControlConfig; use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; -use crate::controller::{ControllerId, ControllerStatus}; +use crate::controller::ControllerId; use crate::service::event::PortEvent as ServicePortEvent; /// Port-specific command data @@ -116,8 +116,6 @@ pub type PortResponse = Result; pub enum InternalCommandData { /// Reset the PD controller Reset, - /// Get controller status - Status, /// Sync controller state SyncState, } @@ -135,22 +133,20 @@ pub enum Command { /// Controller-specific response data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InternalResponseData<'a> { +pub enum InternalResponseData { /// Command complete Complete, - /// Controller status - Status(ControllerStatus<'a>), } /// Response for controller-specific commands -pub type InternalResponse<'a> = Result, PdError>; +pub type InternalResponse = Result; /// PD controller command response #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Response<'a> { +pub enum Response { /// Controller response - Controller(InternalResponse<'a>), + Controller(InternalResponse), /// Port response Port(PortResponse), } @@ -171,7 +167,7 @@ pub struct Device<'a> { id: ControllerId, pub ports: &'a [PortRegistration], num_ports: usize, - command: deferred::Channel>, + command: deferred::Channel, } impl intrusive_list::NodeContainer for Device<'static> { @@ -198,7 +194,7 @@ impl<'a> Device<'a> { } /// Send a command to this controller - pub async fn execute_command(&self, command: Command) -> Response<'_> { + pub async fn execute_command(&self, command: Command) -> Response { self.command.execute(command).await } @@ -224,7 +220,7 @@ impl<'a> Device<'a> { /// Create a command handler for this controller /// /// DROP SAFETY: Direct call to deferred channel primitive - pub async fn receive(&self) -> deferred::Request<'_, GlobalRawMutex, Command, Response<'static>> { + pub async fn receive(&self) -> deferred::Request<'_, GlobalRawMutex, Command, Response> { self.command.receive().await } diff --git a/type-c-interface/src/service/context.rs b/type-c-interface/src/service/context.rs index 0a38b5af1..4d2217833 100644 --- a/type-c-interface/src/service/context.rs +++ b/type-c-interface/src/service/context.rs @@ -9,7 +9,7 @@ use crate::control::tbt::TbtConfig; use crate::control::type_c::TypeCStateMachineState; use crate::control::usb::UsbControlConfig; use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; -use crate::controller::{ControllerId, ControllerStatus}; +use crate::controller::ControllerId; use crate::port::{ Command, Device, InternalCommandData, InternalResponseData, PortCommand, PortCommandData, PortResponseData, Response, @@ -64,7 +64,7 @@ impl Context { &self, controller_id: ControllerId, command: InternalCommandData, - ) -> Result, PdError> { + ) -> Result { let node = self .controllers .into_iter() @@ -96,7 +96,7 @@ impl Context { &self, controller_id: ControllerId, command: InternalCommandData, - ) -> Result, PdError> { + ) -> Result { match with_timeout( DEFAULT_TIMEOUT, self.send_controller_command_no_timeout(controller_id, command), @@ -244,23 +244,6 @@ impl Context { } } - /// Get current controller status - pub async fn get_controller_status( - &self, - controller_id: ControllerId, - ) -> Result, PdError> { - match self - .send_controller_command(controller_id, InternalCommandData::Status) - .await? - { - InternalResponseData::Status(status) => Ok(status), - r => { - error!("Invalid response: expected controller status, got {:?}", r); - Err(PdError::InvalidResponse) - } - } - } - /// Set unconstrained power for the given port pub async fn set_unconstrained_power(&self, port: GlobalPortId, unconstrained: bool) -> Result<(), PdError> { match self @@ -279,10 +262,6 @@ impl Context { .await? { InternalResponseData::Complete => Ok(()), - r => { - error!("Invalid response: expected controller status, got {:?}", r); - Err(PdError::InvalidResponse) - } } } diff --git a/type-c-service/src/bridge/event_receiver.rs b/type-c-service/src/bridge/event_receiver.rs index aebad0541..da1b4be1c 100644 --- a/type-c-service/src/bridge/event_receiver.rs +++ b/type-c-service/src/bridge/event_receiver.rs @@ -1,14 +1,14 @@ use embedded_services::{GlobalRawMutex, ipc::deferred}; use type_c_interface::port; -pub type ControllerCommand<'a> = deferred::Request<'a, GlobalRawMutex, port::Command, port::Response<'static>>; +pub type ControllerCommand<'a> = deferred::Request<'a, GlobalRawMutex, port::Command, port::Response>; /// Controller command output data pub struct OutputControllerCommand<'a> { /// Controller request pub request: ControllerCommand<'a>, /// Response - pub response: port::Response<'static>, + pub response: port::Response, } pub struct EventReceiver { diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index 0f87d6e92..a4e8bf7f8 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -34,7 +34,7 @@ where } /// Handle a port command - pub async fn process_port_command(&mut self, command: &port::PortCommand) -> Response<'static> { + pub async fn process_port_command(&mut self, command: &port::PortCommand) -> Response { let local_port = if let Ok(port) = self.registration.lookup_local_port(command.port) { port } else { @@ -122,14 +122,9 @@ where }) } - pub async fn process_controller_command(&mut self, command: &port::InternalCommandData) -> Response<'static> { + pub async fn process_controller_command(&mut self, command: &port::InternalCommandData) -> Response { let mut controller = self.controller.lock().await; match command { - port::InternalCommandData::Status => { - let status = controller.get_controller_status().await; - port::Response::Controller(status.map(InternalResponseData::Status)) - } - // This isn't sent by the type-C service, disable it for the transition port::InternalCommandData::SyncState => port::Response::Controller(Ok(InternalResponseData::Complete)), port::InternalCommandData::Reset => { let result = controller.reset_controller().await; diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index bfa2afc62..f69bafa91 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -37,9 +37,9 @@ use type_c_interface::control::tbt::TbtConfig; use type_c_interface::control::type_c::TypeCStateMachineState; use type_c_interface::control::usb::UsbControlConfig; use type_c_interface::control::vdm::{ATTN_VDM_LEN, AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::controller::Controller; use type_c_interface::controller::pd::Pd; use type_c_interface::controller::retimer::Retimer; -use type_c_interface::controller::{Controller, ControllerStatus}; use type_c_interface::port::event::PortEventBitfield; use crate::util::{ @@ -354,20 +354,6 @@ impl Controller for Tps6699x<'_, M, B> { Ok(()) } - - async fn get_controller_status(&mut self) -> Result, PdError> { - self.guard_no_fw_update_active()?; - let boot_flags = self.tps6699x.get_boot_flags().await.map_err(|e| self.log_error(e))?; - let customer_use = CustomerUse(self.tps6699x.get_customer_use().await.map_err(|e| self.log_error(e))?); - - Ok(ControllerStatus { - mode: self.tps6699x.get_mode().await.map_err(|e| self.log_error(e))?.into(), - valid_fw_bank: (boot_flags.active_bank() == 0 && boot_flags.bank0_valid() != 0) - || (boot_flags.active_bank() == 1 && boot_flags.bank1_valid() != 0), - fw_version0: customer_use.ti_fw_version(), - fw_version1: customer_use.custom_fw_version(), - }) - } } impl Pd for Tps6699x<'_, M, B> { From 2b2712037ef4988d9d21cfa74d55a94a792a121f Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Mon, 4 May 2026 16:07:01 -0700 Subject: [PATCH 7/9] type-c-service/controller: Add port trait impls --- .../src/controller/electrical_disconnect.rs | 25 ++++++ .../src/controller/max_sink_voltage.rs | 23 +++++ type-c-service/src/controller/mod.rs | 5 ++ type-c-service/src/controller/pd.rs | 90 +++++++++++++++++++ type-c-service/src/controller/power.rs | 20 +++++ type-c-service/src/controller/retimer.rs | 36 ++++++++ type-c-service/src/controller/type_c.rs | 24 +++++ type-c-service/src/controller/ucsi.rs | 22 +++++ 8 files changed, 245 insertions(+) create mode 100644 type-c-service/src/controller/electrical_disconnect.rs create mode 100644 type-c-service/src/controller/max_sink_voltage.rs create mode 100644 type-c-service/src/controller/retimer.rs create mode 100644 type-c-service/src/controller/type_c.rs create mode 100644 type-c-service/src/controller/ucsi.rs diff --git a/type-c-service/src/controller/electrical_disconnect.rs b/type-c-service/src/controller/electrical_disconnect.rs new file mode 100644 index 000000000..b81e30772 --- /dev/null +++ b/type-c-service/src/controller/electrical_disconnect.rs @@ -0,0 +1,25 @@ +//! Electrical disconnect port trait implementation +use core::num::NonZeroU8; + +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::controller::electrical_disconnect::ElectricalDisconnect; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::electrical_disconnect::ElectricalDisconnect for Port<'device, C, Shared, PowerSender> +{ + async fn execute_electrical_disconnect(&mut self, reconnect_time_s: Option) -> Result<(), PdError> { + self.controller + .lock() + .await + .execute_electrical_disconnect(self.port, reconnect_time_s) + .await + } +} diff --git a/type-c-service/src/controller/max_sink_voltage.rs b/type-c-service/src/controller/max_sink_voltage.rs new file mode 100644 index 000000000..be16a562b --- /dev/null +++ b/type-c-service/src/controller/max_sink_voltage.rs @@ -0,0 +1,23 @@ +//! Max sink voltage port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::controller::max_sink_voltage::MaxSinkVoltage; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::max_sink_voltage::MaxSinkVoltage for Port<'device, C, Shared, PowerSender> +{ + async fn set_max_sink_voltage(&mut self, voltage_mv: Option) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_max_sink_voltage(self.port, voltage_mv) + .await + } +} diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index ba3df3648..56d84f59c 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -13,12 +13,17 @@ use crate::controller::event::{Event, Loopback}; use crate::controller::state::SharedState; pub mod config; +pub mod electrical_disconnect; pub mod event; pub mod event_receiver; pub mod macros; +pub mod max_sink_voltage; mod pd; mod power; +pub mod retimer; pub mod state; +pub mod type_c; +pub mod ucsi; pub struct Port< 'device, diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index cb48bab1a..d2ce212da 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -1,5 +1,15 @@ //! PD functionality unrelated to power contracts and general port status use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use embedded_usb_pd::ado::Ado; +use type_c_interface::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, +}; +use type_c_interface::controller::pd::StateMachine; use type_c_interface::port::event::{VdmData, VdmNotification}; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; @@ -72,3 +82,83 @@ impl< } } } + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::pd::Pd for Port<'device, C, Shared, PowerSender> +{ + async fn get_port_status(&mut self) -> Result { + self.controller.lock().await.get_port_status(self.port).await + } + + async fn clear_dead_battery_flag(&mut self) -> Result<(), PdError> { + self.controller.lock().await.clear_dead_battery_flag(self.port).await + } + + async fn enable_sink_path(&mut self, enable: bool) -> Result<(), PdError> { + self.controller.lock().await.enable_sink_path(self.port, enable).await + } + + async fn get_pd_alert(&mut self) -> Result, PdError> { + self.controller.lock().await.get_pd_alert(self.port).await + } + + async fn set_unconstrained_power(&mut self, unconstrained: bool) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_unconstrained_power(self.port, unconstrained) + .await + } + + async fn get_other_vdm(&mut self) -> Result { + self.controller.lock().await.get_other_vdm(self.port).await + } + + async fn get_attn_vdm(&mut self) -> Result { + self.controller.lock().await.get_attn_vdm(self.port).await + } + + async fn send_vdm(&mut self, tx_vdm: SendVdm) -> Result<(), PdError> { + self.controller.lock().await.send_vdm(self.port, tx_vdm).await + } + + async fn execute_drst(&mut self) -> Result<(), PdError> { + self.controller.lock().await.execute_drst(self.port).await + } + + async fn get_dp_status(&mut self) -> Result { + self.controller.lock().await.get_dp_status(self.port).await + } + + async fn set_dp_config(&mut self, config: DpConfig) -> Result<(), PdError> { + self.controller.lock().await.set_dp_config(self.port, config).await + } + + async fn set_tbt_config(&mut self, config: TbtConfig) -> Result<(), PdError> { + self.controller.lock().await.set_tbt_config(self.port, config).await + } + + async fn set_usb_control(&mut self, config: UsbControlConfig) -> Result<(), PdError> { + self.controller.lock().await.set_usb_control(self.port, config).await + } +} + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::pd::StateMachine for Port<'device, C, Shared, PowerSender> +{ + async fn set_pd_state_machine_config(&mut self, config: PdStateMachineConfig) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_pd_state_machine_config(self.port, config) + .await + } +} diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index fdfb0a4bb..5e37e4123 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -9,6 +9,7 @@ use power_policy_interface::{ capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}, psu::{Error as PsuError, Psu, State}, }; +use type_c_interface::controller::power::SystemPowerState; use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_error}; @@ -163,3 +164,22 @@ impl< &mut self.psu_state } } + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::power::SystemPowerState for Port<'device, C, Shared, PowerSender> +{ + async fn set_system_power_state( + &mut self, + state: type_c_interface::control::power::SystemPowerState, + ) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_system_power_state(self.port, state) + .await + } +} diff --git a/type-c-service/src/controller/retimer.rs b/type-c-service/src/controller/retimer.rs new file mode 100644 index 000000000..901fe5595 --- /dev/null +++ b/type-c-service/src/controller/retimer.rs @@ -0,0 +1,36 @@ +//! Retimer port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::controller::retimer::Retimer; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::retimer::Retimer for Port<'device, C, Shared, PowerSender> +{ + async fn get_rt_fw_update_status(&mut self) -> Result { + self.controller.lock().await.get_rt_fw_update_status(self.port).await + } + + async fn set_rt_fw_update_state(&mut self) -> Result<(), PdError> { + self.controller.lock().await.set_rt_fw_update_state(self.port).await + } + + async fn clear_rt_fw_update_state(&mut self) -> Result<(), PdError> { + self.controller.lock().await.clear_rt_fw_update_state(self.port).await + } + + async fn set_rt_compliance(&mut self) -> Result<(), PdError> { + self.controller.lock().await.set_rt_compliance(self.port).await + } + + async fn reconfigure_retimer(&mut self) -> Result<(), PdError> { + self.controller.lock().await.reconfigure_retimer(self.port).await + } +} diff --git a/type-c-service/src/controller/type_c.rs b/type-c-service/src/controller/type_c.rs new file mode 100644 index 000000000..e734f3dcf --- /dev/null +++ b/type-c-service/src/controller/type_c.rs @@ -0,0 +1,24 @@ +//! Type-C state machine port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::controller::type_c::StateMachine; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::port::type_c::StateMachine for Port<'device, C, Shared, PowerSender> +{ + async fn set_type_c_state_machine_config(&mut self, state: TypeCStateMachineState) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_type_c_state_machine_config(self.port, state) + .await + } +} diff --git a/type-c-service/src/controller/ucsi.rs b/type-c-service/src/controller/ucsi.rs new file mode 100644 index 000000000..a29de5b72 --- /dev/null +++ b/type-c-service/src/controller/ucsi.rs @@ -0,0 +1,22 @@ +//! UCSI LPM port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::ucsi::Lpm as UcsiLpm; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, +> type_c_interface::ucsi::Lpm for Port<'device, C, Shared, PowerSender> +{ + async fn execute_lpm_command( + &mut self, + command: embedded_usb_pd::ucsi::lpm::LocalCommand, + ) -> Result, PdError> { + self.controller.lock().await.execute_lpm_command(command).await + } +} From 817b11889939f801c7d62cfb66013ed5b6d61788 Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Wed, 6 May 2026 14:41:28 -0700 Subject: [PATCH 8/9] Fix rebase errors and minor changes --- examples/std/src/lib/type_c/mock_controller.rs | 2 +- type-c-interface/src/control/pd.rs | 2 +- type-c-interface/src/controller/mod.rs | 1 - type-c-service/src/controller/electrical_disconnect.rs | 4 +++- type-c-service/src/controller/max_sink_voltage.rs | 3 ++- type-c-service/src/controller/mod.rs | 4 ++-- type-c-service/src/controller/pd.rs | 6 ++++-- type-c-service/src/controller/power.rs | 3 ++- type-c-service/src/controller/retimer.rs | 3 ++- type-c-service/src/controller/type_c.rs | 3 ++- type-c-service/src/controller/ucsi.rs | 3 ++- 11 files changed, 21 insertions(+), 13 deletions(-) diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index 5eb06116e..03b6b99a4 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -258,7 +258,7 @@ impl type_c_interface::ucsi::Lpm for Controller<'_> { lpm::CommandData::GetConnectorStatus => Ok(Some(lpm::ResponseData::GetConnectorStatus( lpm::get_connector_status::ResponseData::default(), ))), - _ => Err(PdError::UnrecognizedCommand.into()), + _ => Err(PdError::UnrecognizedCommand), } } } diff --git a/type-c-interface/src/control/pd.rs b/type-c-interface/src/control/pd.rs index 1a9ed6579..a4b9c8a2a 100644 --- a/type-c-interface/src/control/pd.rs +++ b/type-c-interface/src/control/pd.rs @@ -1,4 +1,4 @@ -//! Control types for code PD functionality +//! Control types for core PD functionality use embedded_usb_pd::{ DataRole, PlugOrientation, PowerRole, diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs index 1edc0069c..d149d5da6 100644 --- a/type-c-interface/src/controller/mod.rs +++ b/type-c-interface/src/controller/mod.rs @@ -1,5 +1,4 @@ //! Module for PD controller related code -//! use embedded_usb_pd::{LocalPortId, PdError}; use embedded_usb_pd::PdError; diff --git a/type-c-service/src/controller/electrical_disconnect.rs b/type-c-service/src/controller/electrical_disconnect.rs index b81e30772..d4d59df6b 100644 --- a/type-c-service/src/controller/electrical_disconnect.rs +++ b/type-c-service/src/controller/electrical_disconnect.rs @@ -13,7 +13,9 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::electrical_disconnect::ElectricalDisconnect for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::electrical_disconnect::ElectricalDisconnect + for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn execute_electrical_disconnect(&mut self, reconnect_time_s: Option) -> Result<(), PdError> { self.controller diff --git a/type-c-service/src/controller/max_sink_voltage.rs b/type-c-service/src/controller/max_sink_voltage.rs index be16a562b..8cee77252 100644 --- a/type-c-service/src/controller/max_sink_voltage.rs +++ b/type-c-service/src/controller/max_sink_voltage.rs @@ -11,7 +11,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::max_sink_voltage::MaxSinkVoltage for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::max_sink_voltage::MaxSinkVoltage for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn set_max_sink_voltage(&mut self, voltage_mv: Option) -> Result<(), PdError> { self.controller diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index 56d84f59c..bc739d278 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -4,6 +4,7 @@ use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError}; use power_policy_interface::psu::PsuState; use type_c_interface::control::pd::PortStatus; use type_c_interface::controller::pd::Pd; +use type_c_interface::port::event::PortEventBitfield; use type_c_interface::port::{event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield}; use type_c_interface::service::event::{ PortEvent as ServicePortEvent, PortEventData as ServicePortEventData, StatusChangedData, @@ -157,8 +158,7 @@ impl< port: self.global_port, event, }) - .await - .map_err(|_| PdError::Failed)?; + .await?; Ok(event) } diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index d2ce212da..0cfe2bc6d 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -88,7 +88,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::pd::Pd for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::pd::Pd for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn get_port_status(&mut self) -> Result { self.controller.lock().await.get_port_status(self.port).await @@ -152,7 +153,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::pd::StateMachine for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::pd::StateMachine for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn set_pd_state_machine_config(&mut self, config: PdStateMachineConfig) -> Result<(), PdError> { self.controller diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index 5e37e4123..768b239c8 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -170,7 +170,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::power::SystemPowerState for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::power::SystemPowerState for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn set_system_power_state( &mut self, diff --git a/type-c-service/src/controller/retimer.rs b/type-c-service/src/controller/retimer.rs index 901fe5595..cdb9a4a0a 100644 --- a/type-c-service/src/controller/retimer.rs +++ b/type-c-service/src/controller/retimer.rs @@ -12,7 +12,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::retimer::Retimer for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::retimer::Retimer for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn get_rt_fw_update_status(&mut self) -> Result { self.controller.lock().await.get_rt_fw_update_status(self.port).await diff --git a/type-c-service/src/controller/type_c.rs b/type-c-service/src/controller/type_c.rs index e734f3dcf..663212e65 100644 --- a/type-c-service/src/controller/type_c.rs +++ b/type-c-service/src/controller/type_c.rs @@ -12,7 +12,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::port::type_c::StateMachine for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::port::type_c::StateMachine for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn set_type_c_state_machine_config(&mut self, state: TypeCStateMachineState) -> Result<(), PdError> { self.controller diff --git a/type-c-service/src/controller/ucsi.rs b/type-c-service/src/controller/ucsi.rs index a29de5b72..b899720be 100644 --- a/type-c-service/src/controller/ucsi.rs +++ b/type-c-service/src/controller/ucsi.rs @@ -11,7 +11,8 @@ impl< C: Lockable, Shared: Lockable, PowerSender: Sender, -> type_c_interface::ucsi::Lpm for Port<'device, C, Shared, PowerSender> + LoopbackSender: Sender, +> type_c_interface::ucsi::Lpm for Port<'device, C, Shared, PowerSender, LoopbackSender> { async fn execute_lpm_command( &mut self, From a715226177de9cc1bf99e978af97e0d2e631a76c Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Thu, 7 May 2026 11:12:48 -0700 Subject: [PATCH 9/9] Minor rename `SystemPowerState` trait, fix comment typo --- examples/std/src/lib/type_c/mock_controller.rs | 8 ++++++-- type-c-interface/src/control/vdm.rs | 2 +- type-c-interface/src/controller/power.rs | 4 ++-- type-c-interface/src/port/power.rs | 4 ++-- type-c-service/src/controller/power.rs | 10 +++++----- type-c-service/src/driver/tps6699x.rs | 8 ++++++-- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index 03b6b99a4..5acab89d4 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -274,8 +274,12 @@ impl type_c_interface::controller::electrical_disconnect::ElectricalDisconnect f } } -impl type_c_interface::controller::power::SystemPowerState for Controller<'_> { - async fn set_system_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { +impl type_c_interface::controller::power::SystemPowerStateStatus for Controller<'_> { + async fn set_system_power_state_status( + &mut self, + port: LocalPortId, + state: SystemPowerState, + ) -> Result<(), PdError> { debug!("Set system power state for port {port:?}: {state:?}"); Ok(()) } diff --git a/type-c-interface/src/control/vdm.rs b/type-c-interface/src/control/vdm.rs index 6baecb463..1bd2ebe3b 100644 --- a/type-c-interface/src/control/vdm.rs +++ b/type-c-interface/src/control/vdm.rs @@ -76,7 +76,7 @@ pub struct SendVdm { } impl SendVdm { - /// Create a new blank port status + /// Create a new blank VDM pub const fn new() -> Self { Self { initiator: false, diff --git a/type-c-interface/src/controller/power.rs b/type-c-interface/src/controller/power.rs index 5046a410b..238ce82ca 100644 --- a/type-c-interface/src/controller/power.rs +++ b/type-c-interface/src/controller/power.rs @@ -1,12 +1,12 @@ use embedded_usb_pd::{LocalPortId, PdError}; /// System power state related controller functionality -pub trait SystemPowerState { +pub trait SystemPowerStateStatus { /// Set the system power state on the given port. /// /// This notifies the PD controller of the current system power state, /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). - fn set_system_power_state( + fn set_system_power_state_status( &mut self, port: LocalPortId, state: crate::control::power::SystemPowerState, diff --git a/type-c-interface/src/port/power.rs b/type-c-interface/src/port/power.rs index c247cef39..4701328cc 100644 --- a/type-c-interface/src/port/power.rs +++ b/type-c-interface/src/port/power.rs @@ -1,12 +1,12 @@ use embedded_usb_pd::PdError; /// System power state related controller functionality -pub trait SystemPowerState { +pub trait SystemPowerStateStatus { /// Set the system power state on this port. /// /// This notifies the PD controller of the current system power state, /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). - fn set_system_power_state( + fn set_system_power_state_status( &mut self, state: crate::control::power::SystemPowerState, ) -> impl Future>; diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index 768b239c8..9e477e410 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -9,7 +9,7 @@ use power_policy_interface::{ capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}, psu::{Error as PsuError, Psu, State}, }; -use type_c_interface::controller::power::SystemPowerState; +use type_c_interface::controller::power::SystemPowerStateStatus; use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_error}; @@ -167,20 +167,20 @@ impl< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, -> type_c_interface::port::power::SystemPowerState for Port<'device, C, Shared, PowerSender, LoopbackSender> +> type_c_interface::port::power::SystemPowerStateStatus for Port<'device, C, Shared, PowerSender, LoopbackSender> { - async fn set_system_power_state( + async fn set_system_power_state_status( &mut self, state: type_c_interface::control::power::SystemPowerState, ) -> Result<(), PdError> { self.controller .lock() .await - .set_system_power_state(self.port, state) + .set_system_power_state_status(self.port, state) .await } } diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index f69bafa91..1560cd706 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -854,8 +854,12 @@ impl type_c_interface::controller::electrical_disconnect::E } } -impl type_c_interface::controller::power::SystemPowerState for Tps6699x<'_, M, B> { - async fn set_system_power_state(&mut self, port: LocalPortId, state: SystemPowerState) -> Result<(), PdError> { +impl type_c_interface::controller::power::SystemPowerStateStatus for Tps6699x<'_, M, B> { + async fn set_system_power_state_status( + &mut self, + port: LocalPortId, + state: SystemPowerState, + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; use tps6699x::registers::SystemPowerState as DriverSystemPowerState;