diff --git a/Cargo.lock b/Cargo.lock index 24d0c21b..1b77a98e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,7 @@ dependencies = [ "heapless", "log", "mctp-rs", + "power-policy-interface", "zerocopy", ] @@ -231,6 +232,7 @@ dependencies = [ "defmt 0.3.100", "embedded-batteries-async", "embedded-services", + "log", "num_enum", ] @@ -1002,7 +1004,6 @@ dependencies = [ "embassy-sync", "embassy-time", "embassy-time-driver", - "embedded-batteries-async", "embedded-cfu-protocol", "embedded-hal-async", "embedded-io", @@ -1839,19 +1840,38 @@ dependencies = [ "log", ] +[[package]] +name = "power-policy-interface" +version = "0.1.0" +dependencies = [ + "bitfield 0.17.0", + "defmt 0.3.100", + "embassy-futures", + "embassy-sync", + "embedded-batteries-async", + "embedded-services", + "heapless", + "log", + "num_enum", +] + [[package]] name = "power-policy-service" version = "0.1.0" dependencies = [ + "bitfield 0.17.0", "critical-section", "defmt 0.3.100", "embassy-futures", "embassy-sync", "embassy-time", + "embedded-batteries-async", "embedded-services", "env_logger", "heapless", "log", + "num_enum", + "power-policy-interface", "static_cell", "tokio", ] @@ -2492,6 +2512,7 @@ version = "0.1.0" dependencies = [ "bitfield 0.17.0", "bitflags 2.9.4", + "bitvec", "cfu-service", "critical-section", "defmt 0.3.100", @@ -2507,6 +2528,8 @@ dependencies = [ "embedded-usb-pd", "heapless", "log", + "power-policy-interface", + "power-policy-service", "static_cell", "tokio", "tps6699x", diff --git a/Cargo.toml b/Cargo.toml index 06f23b96..eadaac9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "debug-service", "debug-service-messages", "keyboard-service", + "power-policy-interface", ] exclude = ["examples/*"] @@ -86,6 +87,7 @@ embedded-usb-pd = { git = "https://github.com/OpenDevicePartnership/embedded-usb mctp-rs = { git = "https://github.com/dymk/mctp-rs" } num_enum = { version = "0.7.5", default-features = false } portable-atomic = { version = "1.11", default-features = false } +power-policy-interface = { path = "./power-policy-interface" } paste = "1.0.15" fixed = "1.23.1" heapless = "0.8.*" diff --git a/battery-service-messages/Cargo.toml b/battery-service-messages/Cargo.toml index 86d56e08..e771e16f 100644 --- a/battery-service-messages/Cargo.toml +++ b/battery-service-messages/Cargo.toml @@ -7,6 +7,7 @@ repository.workspace = true [dependencies] defmt = { workspace = true, optional = true } +log = { workspace = true, optional = true } embedded-batteries-async.workspace = true embedded-services.workspace = true num_enum.workspace = true @@ -15,4 +16,9 @@ num_enum.workspace = true workspace = true [features] -defmt = ["dep:defmt", "embedded-batteries-async/defmt"] +defmt = [ + "dep:defmt", + "embedded-services/defmt", + "embedded-batteries-async/defmt", +] +log = ["dep:log", "embedded-services/log"] diff --git a/battery-service/Cargo.toml b/battery-service/Cargo.toml index 3b330440..f18b6110 100644 --- a/battery-service/Cargo.toml +++ b/battery-service/Cargo.toml @@ -24,6 +24,7 @@ log = { workspace = true, optional = true } zerocopy.workspace = true mctp-rs = { workspace = true, features = ["espi"] } heapless.workspace = true +power-policy-interface.workspace = true [features] default = [] @@ -31,6 +32,7 @@ defmt = [ "dep:defmt", "battery-service-messages/defmt", "embedded-services/defmt", + "power-policy-interface/defmt", "embassy-time/defmt", "embassy-sync/defmt", "embedded-batteries-async/defmt", @@ -39,6 +41,7 @@ defmt = [ log = [ "dep:log", "embedded-services/log", + "power-policy-interface/log", "embassy-time/log", "embassy-sync/log", ] diff --git a/battery-service/src/acpi.rs b/battery-service/src/acpi.rs index 91031852..f0656a7d 100644 --- a/battery-service/src/acpi.rs +++ b/battery-service/src/acpi.rs @@ -2,13 +2,15 @@ use core::ops::Deref; use embedded_batteries_async::acpi::{PowerSourceState, PowerUnit}; -use embedded_services::{info, power::policy::PowerCapability, trace}; +use embedded_services::{info, trace}; use battery_service_messages::{ AcpiBatteryResponse, BixFixedStrings, DeviceId, PifFixedStrings, STD_BIX_BATTERY_SIZE, STD_BIX_MODEL_SIZE, STD_BIX_OEM_SIZE, STD_BIX_SERIAL_SIZE, STD_PIF_MODEL_SIZE, STD_PIF_OEM_SIZE, STD_PIF_SERIAL_SIZE, }; +use power_policy_interface::capability::PowerCapability; + use crate::{ AcpiBatteryError, context::PsuState, diff --git a/battery-service/src/context.rs b/battery-service/src/context.rs index d0286795..0b8f7716 100644 --- a/battery-service/src/context.rs +++ b/battery-service/src/context.rs @@ -8,8 +8,8 @@ use embassy_sync::mutex::Mutex; use embassy_time::{Duration, with_timeout}; use embedded_services::GlobalRawMutex; use embedded_services::comms::MailboxDelegateError; -use embedded_services::power::policy::PowerCapability; use embedded_services::{IntrusiveList, debug, error, info, intrusive_list, trace, warn}; +use power_policy_interface::capability::PowerCapability; use core::ops::DerefMut; use core::sync::atomic::AtomicUsize; @@ -519,7 +519,7 @@ impl Context { pub(crate) fn set_power_info( &self, - power_info: &embedded_services::power::policy::CommsData, + power_info: &power_policy_interface::service::event::CommsData, ) -> Result<(), MailboxDelegateError> { let mut guard = self .power_info @@ -529,13 +529,13 @@ impl Context { let psu_state = guard.deref_mut(); match power_info { - embedded_services::power::policy::CommsData::ConsumerDisconnected(_) => { + power_policy_interface::service::event::CommsData::ConsumerDisconnected(_) => { *psu_state = PsuState { psu_connected: false, power_capability: None, } } - embedded_services::power::policy::CommsData::ConsumerConnected(_device_id, power_capability) => { + power_policy_interface::service::event::CommsData::ConsumerConnected(_device_id, power_capability) => { *psu_state = PsuState { psu_connected: true, power_capability: Some(power_capability.capability), diff --git a/battery-service/src/lib.rs b/battery-service/src/lib.rs index 60e7edb2..dd3cf76a 100644 --- a/battery-service/src/lib.rs +++ b/battery-service/src/lib.rs @@ -126,7 +126,10 @@ impl comms::MailboxDelegate for Service { self.context.send_event_no_wait(*event).map_err(|e| match e { embassy_sync::channel::TrySendError::Full(_) => comms::MailboxDelegateError::BufferFull, })? - } else if let Some(power_policy_msg) = message.data.get::() { + } else if let Some(power_policy_msg) = message + .data + .get::() + { self.context.set_power_info(&power_policy_msg.data)?; } diff --git a/embedded-service/Cargo.toml b/embedded-service/Cargo.toml index 5e83b291..8185264d 100644 --- a/embedded-service/Cargo.toml +++ b/embedded-service/Cargo.toml @@ -22,7 +22,6 @@ document-features.workspace = true embassy-sync.workspace = true embassy-time.workspace = true embassy-futures.workspace = true -embedded-batteries-async.workspace = true embedded-cfu-protocol.workspace = true embedded-hal-async.workspace = true embedded-io-async.workspace = true diff --git a/embedded-service/src/lib.rs b/embedded-service/src/lib.rs index f20d6e89..c53aba53 100644 --- a/embedded-service/src/lib.rs +++ b/embedded-service/src/lib.rs @@ -21,10 +21,8 @@ pub mod hid; pub mod init; pub mod ipc; pub mod keyboard; -pub mod power; pub mod relay; pub mod sync; -pub mod type_c; /// Hidden re-exports used by macros defined in this crate. /// Not part of the public API — do not depend on these directly. @@ -85,5 +83,4 @@ pub async fn init() { comms::init(); activity::init(); keyboard::init(); - power::policy::init(); } diff --git a/embedded-service/src/power/mod.rs b/embedded-service/src/power/mod.rs deleted file mode 100644 index 962fba0b..00000000 --- a/embedded-service/src/power/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Module for anything power related -#[allow(clippy::module_inception)] -pub mod policy; diff --git a/embedded-service/src/power/policy/charger.rs b/embedded-service/src/power/policy/charger.rs deleted file mode 100644 index d589c66d..00000000 --- a/embedded-service/src/power/policy/charger.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! Charger device struct and controller -use core::{future::Future, ops::DerefMut}; - -use embassy_sync::{channel::Channel, mutex::Mutex}; - -use crate::{ - GlobalRawMutex, intrusive_list, - power::{self, policy::ConsumerPowerCapability}, -}; - -use super::PowerCapability; - -/// Charger controller trait that device drivers may use to integrate with internal messaging system -pub trait ChargeController: embedded_batteries_async::charger::Charger { - /// Type of error returned by the bus - type ChargeControllerError; - - /// Returns with pending events - fn wait_event(&mut self) -> impl Future; - /// Initialize charger hardware, after this returns the charger should be ready to charge - fn init_charger(&mut self) -> impl Future>; - /// Returns if the charger hardware detects if a PSU is attached - fn is_psu_attached(&mut self) -> impl Future>; - /// Called after power policy attaches to a power port. - fn attach_handler( - &mut self, - capability: ConsumerPowerCapability, - ) -> impl Future>; - /// Called after power policy detaches from a power port, either to switch consumers, - /// or because PSU was disconnected. - fn detach_handler(&mut self) -> impl Future>; - /// Called when a charger CheckReady request (PolicyEvent::CheckReady) is sent to the power policy. - /// Upon successful return of this method, the charger is assumed to be powered and ready to communicate, - /// transitioning state from unpowered to powered. - /// - /// If the charger is powered, an Ok(()) does nothing. An Err(_) will put the charger into an - /// unpowered state, meaning another PolicyEvent::CheckReady must be sent to re-establish communications - /// with the charger. Upon successful return, the charger must be re-initialized by sending a - /// `PolicyEvent::InitRequest`. - fn is_ready(&mut self) -> impl Future> { - core::future::ready(Ok(())) - } -} - -/// Charger Device ID new type -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ChargerId(pub u8); - -/// PSU state as determined by charger device -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PsuState { - /// Charger detected PSU attached - Attached, - /// Charger detected PSU detached - Detached, -} - -impl From for PsuState { - fn from(value: bool) -> Self { - match value { - true => PsuState::Attached, - false => PsuState::Detached, - } - } -} - -/// Data for a device request -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum ChargerEvent { - /// Charger finished initialization sequence - Initialized(PsuState), - /// PSU state changed - PsuStateChange(PsuState), - /// A timeout of some sort was detected - Timeout, - /// An error occured on the bus - BusError, -} - -/// Charger state errors -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum ChargerError { - /// Charger received command in an invalid state - InvalidState(State), - /// Charger hardware timed out responding - Timeout, - /// Charger underlying bus error - BusError, -} - -impl From for power::policy::Error { - fn from(value: ChargerError) -> Self { - Self::Charger(value) - } -} - -/// Data for a device request -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PolicyEvent { - /// Request to initialize charger hardware - InitRequest, - /// New power policy detected - PolicyConfiguration(ConsumerPowerCapability), - /// Request to check if the charger hardware is ready to receive communications. - /// For example, if the charger is powered. - CheckReady, -} - -/// Data for a device request -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum ChargerResponseData { - /// Command completed - Ack, - /// Charger Unpowered, but we are still Ok - UnpoweredAck, -} - -/// Response for charger requests from policy commands -pub type ChargerResponse = Result; - -/// Current state of the charger -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum State { - /// Device is unpowered - Unpowered, - /// Device is powered - Powered(PoweredSubstate), -} - -/// Powered state substates -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PoweredSubstate { - /// Device is initializing - Init, - /// PSU is attached and device can charge if desired - PsuAttached, - /// PSU is detached - PsuDetached, -} - -/// Current state of the charger -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct InternalState { - /// Charger device state - pub state: State, - /// Current charger capability - pub capability: Option, -} - -/// Channel size for device requests -pub const CHARGER_CHANNEL_SIZE: usize = 1; - -/// Device struct -pub struct Device { - /// Intrusive list node - node: intrusive_list::Node, - /// Device ID - id: ChargerId, - /// Current state of the device - state: Mutex, - /// Channel for requests to the device - commands: Channel, - /// Channel for responses from the device - response: Channel, -} - -impl Device { - /// Create a new device - pub fn new(id: ChargerId) -> Self { - Self { - node: intrusive_list::Node::uninit(), - id, - state: Mutex::new(InternalState { - state: State::Unpowered, - capability: None, - }), - commands: Channel::new(), - response: Channel::new(), - } - } - - /// Get the device ID - pub fn id(&self) -> ChargerId { - self.id - } - - /// Returns the current state of the device - pub async fn state(&self) -> InternalState { - *self.state.lock().await - } - - /// Set the state of the device - pub async fn set_state(&self, new_state: InternalState) { - let mut lock = self.state.lock().await; - let current_state = lock.deref_mut(); - *current_state = new_state; - } - - /// Wait for a command from policy - pub async fn wait_command(&self) -> PolicyEvent { - self.commands.receive().await - } - - /// Send a command to the charger - pub async fn send_command(&self, policy_event: PolicyEvent) { - self.commands.send(policy_event).await - } - - /// Send a response to the power policy - pub async fn send_response(&self, response: ChargerResponse) { - self.response.send(response).await - } - - /// Send a command and wait for a response from the charger - pub async fn execute_command(&self, policy_event: PolicyEvent) -> ChargerResponse { - self.send_command(policy_event).await; - self.response.receive().await - } -} - -impl intrusive_list::NodeContainer for Device { - fn get_node(&self) -> &crate::Node { - &self.node - } -} - -/// Trait for any container that holds a device -pub trait ChargerContainer { - /// Get the underlying device struct - fn get_charger(&self) -> &Device; -} - -impl ChargerContainer for Device { - fn get_charger(&self) -> &Device { - self - } -} diff --git a/embedded-service/src/power/policy/mod.rs b/embedded-service/src/power/policy/mod.rs deleted file mode 100644 index 1539d4dd..00000000 --- a/embedded-service/src/power/policy/mod.rs +++ /dev/null @@ -1,161 +0,0 @@ -//! Power policy related data structures and messages -pub mod charger; -pub mod device; -pub mod flags; -pub mod policy; - -pub use policy::init; - -use crate::power::policy::charger::ChargerError; - -/// Error type -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - /// The requested device does not exist - InvalidDevice, - /// The provide request was denied, contains maximum available power - CannotProvide(Option), - /// The consume request was denied, contains maximum available power - CannotConsume(Option), - /// The device is not in the correct state (expected, actual) - InvalidState(&'static [device::StateKind], device::StateKind), - /// Invalid response - InvalidResponse, - /// Busy, the device cannot respond to the request at this time - Busy, - /// Timeout - Timeout, - /// Bus error - Bus, - /// Charger specific error, underlying error should have more context - Charger(ChargerError), - /// Generic failure - Failed, -} - -/// Device ID new type -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DeviceId(pub u8); - -/// Amount of power that a device can provider or consume -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PowerCapability { - /// Available voltage in mV - pub voltage_mv: u16, - /// Max available current in mA - pub current_ma: u16, -} - -impl PowerCapability { - /// Calculate maximum power - pub fn max_power_mw(&self) -> u32 { - self.voltage_mv as u32 * self.current_ma as u32 / 1000 - } -} - -impl PartialOrd for PowerCapability { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PowerCapability { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.max_power_mw().cmp(&other.max_power_mw()) - } -} - -/// Power capability with consumer flags -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ConsumerPowerCapability { - /// Power capability - pub capability: PowerCapability, - /// Consumer flags - pub flags: flags::Consumer, -} - -impl From for ConsumerPowerCapability { - fn from(capability: PowerCapability) -> Self { - Self { - capability, - flags: flags::Consumer::none(), - } - } -} - -/// Power capability with provider flags -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ProviderPowerCapability { - /// Power capability - pub capability: PowerCapability, - /// Provider flags - pub flags: flags::Provider, -} - -impl From for ProviderPowerCapability { - fn from(capability: PowerCapability) -> Self { - Self { - capability, - flags: flags::Provider::none(), - } - } -} - -/// Combined power capability with flags enum -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PowerCapabilityFlags { - /// Consumer flags - Consumer(ConsumerPowerCapability), - /// Provider flags - Provider(ProviderPowerCapability), -} - -/// Unconstrained state information -#[derive(Debug, Clone, Default, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct UnconstrainedState { - /// Unconstrained state - pub unconstrained: bool, - /// Available unconstrained devices - pub available: usize, -} - -impl UnconstrainedState { - /// Create a new unconstrained state - pub fn new(unconstrained: bool, available: usize) -> Self { - Self { - unconstrained, - available, - } - } -} - -/// Data to send with the comms service -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum CommsData { - /// Consumer disconnected - ConsumerDisconnected(DeviceId), - /// Consumer connected - ConsumerConnected(DeviceId, ConsumerPowerCapability), - /// Provider disconnected - ProviderDisconnected(DeviceId), - /// Provider connected - ProviderConnected(DeviceId, ProviderPowerCapability), - /// Unconstrained state changed - Unconstrained(UnconstrainedState), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Message to send with the comms service -pub struct CommsMessage { - /// Message data - pub data: CommsData, -} diff --git a/embedded-service/src/type_c/mod.rs b/embedded-service/src/type_c/mod.rs deleted file mode 100644 index 2943acdd..00000000 --- a/embedded-service/src/type_c/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Type-C service -use embedded_usb_pd::pdo::{Common, Contract}; -use embedded_usb_pd::type_c; - -use crate::error; -use crate::power::policy; - -pub mod comms; -pub mod controller; -pub mod event; -pub mod external; - -/// Controller ID -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerId(pub u8); - -/// 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; - -impl TryFrom for policy::PowerCapability { - type Error = (); - - fn try_from(contract: Contract) -> Result { - Ok(policy::PowerCapability { - voltage_mv: contract.pdo.max_voltage_mv(), - current_ma: contract.operating_current_ma().ok_or(())?, - }) - } -} - -impl From for policy::PowerCapability { - fn from(current: type_c::Current) -> Self { - policy::PowerCapability { - voltage_mv: 5000, - // Assume higher power for now - current_ma: current.to_ma(false), - } - } -} - -/// Type-C USB2 power capability 5V@500mA -pub const POWER_CAPABILITY_USB_DEFAULT_USB2: policy::PowerCapability = policy::PowerCapability { - voltage_mv: 5000, - current_ma: 500, -}; - -/// Type-C USB3 power capability 5V@900mA -pub const POWER_CAPABILITY_USB_DEFAULT_USB3: policy::PowerCapability = policy::PowerCapability { - voltage_mv: 5000, - current_ma: 900, -}; - -/// Type-C power capability 5V@1.5A -pub const POWER_CAPABILITY_5V_1A5: policy::PowerCapability = policy::PowerCapability { - voltage_mv: 5000, - current_ma: 1500, -}; - -/// Type-C power capability 5V@3A -pub const POWER_CAPABILITY_5V_3A0: policy::PowerCapability = policy::PowerCapability { - voltage_mv: 5000, - current_ma: 3000, -}; - -/// Newtype to help clarify arguments to port status commands -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Cached(pub bool); diff --git a/examples/pico-de-gallo/Cargo.lock b/examples/pico-de-gallo/Cargo.lock index dc595eb5..f8e429c6 100644 --- a/examples/pico-de-gallo/Cargo.lock +++ b/examples/pico-de-gallo/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -73,12 +61,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - [[package]] name = "aquamarine" version = "0.6.0" @@ -86,56 +68,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" dependencies = [ "include_dir", - "itertools 0.10.5", + "itertools", "proc-macro-error2", "proc-macro2", "quote", "syn", ] -[[package]] -name = "arraydeque" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.14", -] - [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -181,6 +120,7 @@ dependencies = [ "heapless 0.8.0", "log", "mctp-rs", + "power-policy-interface", "zerocopy", ] @@ -255,9 +195,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitvec" @@ -273,9 +213,9 @@ dependencies = [ [[package]] name = "bq40z50-rx" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55262eaa8d376e3db634b2cf851d2f255fbe86076abc3d4f8088248340836bb6" +checksum = "09b6faf600295f12c3fb99b45266bc9140af5c344b08f2705bc06bfa0e8b549e" dependencies = [ "device-driver", "embassy-time", @@ -293,15 +233,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.54" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -328,15 +268,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cordyceps" version = "0.3.4" @@ -401,55 +332,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "yaml-rust2", -] - [[package]] name = "device-driver" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" dependencies = [ - "device-driver-macros", "embedded-io 0.6.1", "embedded-io-async", ] -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools 0.14.0", - "kdl", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn", -] - [[package]] name = "document-features" version = "0.2.12" @@ -628,7 +520,6 @@ dependencies = [ "embassy-futures", "embassy-sync", "embassy-time", - "embedded-batteries-async", "embedded-cfu-protocol", "embedded-hal-async", "embedded-io 0.6.1", @@ -661,20 +552,11 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -682,9 +564,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", @@ -718,9 +600,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "funty" @@ -730,15 +612,15 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "generator" @@ -773,24 +655,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown", -] - [[package]] name = "heapless" version = "0.7.17" @@ -865,26 +729,11 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - [[package]] name = "jiff" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +checksum = "b3e3d65f018c6ae946ab16e80944b97096ed73c35b221d1c478a6c81d8f57940" dependencies = [ "jiff-static", "log", @@ -895,26 +744,15 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +checksum = "a17c2b211d863c7fde02cbea8a3c1a439b98e109286554f2860bdded7ff83818" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "kdl" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" -dependencies = [ - "miette", - "num", - "winnow 0.6.24", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -923,9 +761,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linux-raw-sys" @@ -1012,19 +850,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "unicode-width", -] +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mycelium-bitfield" @@ -1056,70 +884,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1187,12 +951,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pico-de-gallo" version = "0.1.0" @@ -1277,15 +1035,15 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" dependencies = [ "portable-atomic", ] @@ -1344,6 +1102,20 @@ dependencies = [ "serde", ] +[[package]] +name = "power-policy-interface" +version = "0.1.0" +dependencies = [ + "bitfield 0.17.0", + "embassy-futures", + "embassy-sync", + "embedded-batteries-async", + "embedded-services", + "heapless 0.8.0", + "log", + "num_enum", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -1391,9 +1163,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1403,9 +1175,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1414,15 +1186,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" @@ -1524,19 +1290,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -1554,9 +1307,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -1627,9 +1380,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1767,21 +1520,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unty" @@ -1813,12 +1554,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "void" version = "1.0.2" @@ -1997,24 +1732,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" -dependencies = [ - "memchr", -] - [[package]] name = "wyz" version = "0.5.1" @@ -2024,39 +1741,22 @@ dependencies = [ "tap", ] -[[package]] -name = "yaml-rust2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "zerocopy" -version = "0.8.36" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dafd85c832c1b68bbb4ec0c72c7f6f4fc5179627d2bc7c26b30e4c0cc11e76cc" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.36" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb7e4e8436d9db52fbd6625dbf2f45243ab84994a72882ec8227b99e72b439a" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", "syn", ] - -[[package]] -name = "zmij" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" diff --git a/examples/rt633/Cargo.lock b/examples/rt633/Cargo.lock index 4fb0c9dd..517cec0a 100644 --- a/examples/rt633/Cargo.lock +++ b/examples/rt633/Cargo.lock @@ -2,24 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - [[package]] name = "aquamarine" version = "0.6.0" @@ -31,50 +13,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "arraydeque" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.104", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.12", + "syn", ] [[package]] @@ -85,9 +24,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "az" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" [[package]] name = "bare-metal" @@ -107,12 +46,13 @@ dependencies = [ "embassy-futures", "embassy-sync", "embassy-time", - "embedded-batteries-async 0.3.4", + "embedded-batteries-async", "embedded-hal 1.0.0", "embedded-hal-async", "embedded-services", "heapless", "mctp-rs", + "power-policy-interface", "zerocopy", ] @@ -121,7 +61,7 @@ name = "battery-service-messages" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embedded-batteries-async 0.3.4", + "embedded-batteries-async", "embedded-services", "num_enum", ] @@ -163,22 +103,22 @@ checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" [[package]] name = "bitfield" -version = "0.19.1" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db1bcd90f88eabbf0cadbfb87a45bceeaebcd3b4bc9e43da379cd2ef0162590d" +checksum = "21ba6517c6b0f2bf08be60e187ab64b038438f22dd755614d8fe4d4098c46419" dependencies = [ "bitfield-macros", ] [[package]] name = "bitfield-macros" -version = "0.19.1" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3787a07661997bfc05dd3431e379c0188573f78857080cf682e1393ab8e4d64c" +checksum = "f48d6ace212fdf1b45fd6b566bb40808415344642b76c3224c07c8df9da81e97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -189,7 +129,7 @@ checksum = "2be5a46ba01b60005ae2c51a36a29cfe134bcacae2dd5cedcd4615fbaad1494b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -200,7 +140,7 @@ checksum = "8769c4854c5ada2852ddf6fd09d15cf43d4c2aaeccb4de6432f5402f08a6003b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -211,9 +151,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitvec" @@ -229,23 +169,23 @@ dependencies = [ [[package]] name = "bq25773" -version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/bq25773#20bc26219b5372bc6146cdc509c21f6d43e257b3" +version = "0.1.1" +source = "git+https://github.com/OpenDevicePartnership/bq25773#0ca102dec24a617df5762cf0bf4217fd387d5c63" dependencies = [ "device-driver", - "embedded-batteries-async 0.2.1", + "embedded-batteries-async", "embedded-hal 1.0.0", "embedded-hal-async", ] [[package]] name = "bq40z50-rx" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55262eaa8d376e3db634b2cf851d2f255fbe86076abc3d4f8088248340836bb6" +checksum = "09b6faf600295f12c3fb99b45266bc9140af5c344b08f2705bc06bfa0e8b549e" dependencies = [ "device-driver", - "embedded-batteries-async 0.3.4", + "embedded-batteries-async", "embedded-hal 1.0.0", "embedded-hal-async", "smbus-pec", @@ -253,9 +193,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -265,18 +205,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "convert_case" -version = "0.6.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cortex-m" @@ -308,7 +239,7 @@ checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -344,7 +275,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn", ] [[package]] @@ -355,16 +286,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.104", -] - -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "yaml-rust2", + "syn", ] [[package]] @@ -405,7 +327,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -414,7 +336,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -429,49 +351,19 @@ dependencies = [ [[package]] name = "device-driver" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1298272ea07037196af2fe8d1eb50792206f45476d79eefa435432b9323cf488" +checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" dependencies = [ - "device-driver-macros", "embedded-io", "embedded-io-async", ] -[[package]] -name = "device-driver-generation" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86a17ed060a6119daeb05ad5596ac3bd945f7ab2213cc6260bf6a7623e73da1" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools 0.14.0", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c29238099c66bf44098efaa772cae6f47d632aebb7ade8d3087bd565e8fae0" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.104", -] - [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -523,7 +415,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -645,7 +537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e14d288a59ef41f4e05468eae9b1c9fef6866977cea86d3f1a1ced295b6cab" dependencies = [ "bitfield-struct 0.10.1", - "bitflags 2.9.1", + "bitflags 2.11.0", "defmt 0.3.100", "embedded-hal 1.0.0", "zerocopy", @@ -653,28 +545,17 @@ dependencies = [ [[package]] name = "embedded-batteries" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8996d7168535579180a0eead82efaba718ebd598782f986bfd635458259df2" +checksum = "40f975432b4e146342a1589c563cffab6b7a692024cb511bf87b6bfe78c84125" dependencies = [ - "bitfield-struct 0.10.1", - "bitflags 2.9.1", + "bitfield-struct 0.12.1", + "bitflags 2.11.0", "defmt 0.3.100", "embedded-hal 1.0.0", "zerocopy", ] -[[package]] -name = "embedded-batteries-async" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cb543f4eea7e2c57544f345a5cf40fd90e9d3593b96cb7515f6c1d62c7fc68" -dependencies = [ - "bitfield-struct 0.10.1", - "embedded-batteries 0.2.1", - "embedded-hal 1.0.0", -] - [[package]] name = "embedded-batteries-async" version = "0.3.4" @@ -683,14 +564,14 @@ checksum = "a3bf0e4be67770cfc31f1cea8b73baf98c0baf2c57d6bd8c3a4c315acb1d8bd4" dependencies = [ "bitfield-struct 0.12.1", "defmt 0.3.100", - "embedded-batteries 0.3.1", + "embedded-batteries 0.3.4", "embedded-hal 1.0.0", ] [[package]] name = "embedded-cfu-protocol" version = "0.2.0" -source = "git+https://github.com/OpenDevicePartnership/embedded-cfu#a4cc8707842b878048447abbf2af4efa79fed368" +source = "git+https://github.com/OpenDevicePartnership/embedded-cfu#e0d776017cf34c902c9f2a2be0c75fe73a3a4dda" dependencies = [ "defmt 0.3.100", "embedded-io-async", @@ -766,7 +647,7 @@ name = "embedded-services" version = "0.1.0" dependencies = [ "bitfield 0.17.0", - "bitflags 2.9.1", + "bitflags 2.11.0", "bitvec", "cfg-if", "cortex-m", @@ -777,7 +658,6 @@ dependencies = [ "embassy-futures", "embassy-sync", "embassy-time", - "embedded-batteries-async 0.3.4", "embedded-cfu-protocol", "embedded-hal-async", "embedded-io", @@ -814,27 +694,18 @@ source = "git+https://github.com/OpenDevicePartnership/embedded-usb-pd#9a42f07ce dependencies = [ "aquamarine", "bincode", - "bitfield 0.19.1", + "bitfield 0.19.4", "defmt 0.3.100", "embedded-hal-async", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "espi-device" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/haf-ec-service#e9c43ec493ba9c4e3db84c73530f919448c07b6d" +source = "git+https://github.com/OpenDevicePartnership/haf-ec-service#9805f13c044b0e314d415410c57a8a59a40eabeb" dependencies = [ "bit-register", - "bitflags 2.9.1", + "bitflags 2.11.0", "num-traits", "num_enum", "static_assertions", @@ -864,9 +735,9 @@ dependencies = [ [[package]] name = "fixed" -version = "1.29.0" +version = "1.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707070ccf8c4173548210893a0186e29c266901b71ed20cd9e2ca0193dfe95c3" +checksum = "c566da967934c6c7ee0458a9773de9b2a685bd2ce26a3b28ddfc740e640182f5" dependencies = [ "az", "bytemuck", @@ -888,9 +759,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -902,9 +773,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -912,61 +783,61 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-macro", "futures-sink", "futures-task", "pin-project-lite", - "pin-utils", ] [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -978,24 +849,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown", -] - [[package]] name = "heapless" version = "0.8.0" @@ -1008,9 +861,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "ident_case" @@ -1055,38 +908,11 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "kdl" -version = "6.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661358400b02cbbf1fbd05f0a483335490e8a6bd1867620f2eeb78f304a22f" -dependencies = [ - "miette", - "num", - "thiserror 1.0.69", - "winnow 0.6.24", -] - [[package]] name = "litrs" -version = "0.4.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "mctp-rs" @@ -1099,35 +925,7 @@ dependencies = [ "espi-device", "num_enum", "smbus-pec", - "thiserror 2.0.16", -] - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "miette-derive", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "thiserror", ] [[package]] @@ -1180,70 +978,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1271,15 +1005,9 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - [[package]] name = "panic-probe" version = "0.3.2" @@ -1296,12 +1024,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1309,16 +1031,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "portable-atomic" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +name = "power-policy-interface" +version = "0.1.0" +dependencies = [ + "bitfield 0.17.0", + "defmt 0.3.100", + "embassy-futures", + "embassy-sync", + "embedded-batteries-async", + "embedded-services", + "heapless", + "num_enum", +] [[package]] name = "proc-macro-error-attr2" @@ -1339,23 +1069,23 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1404,23 +1134,18 @@ dependencies = [ "embassy-imxrt", "embassy-sync", "embassy-time", - "embedded-batteries-async 0.3.4", + "embedded-batteries-async", "embedded-hal-async", "embedded-services", "espi-service", "futures", "mimxrt600-fcb", "panic-probe", + "power-policy-interface", "rand", "static_cell", ] -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1436,12 +1161,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "semver" version = "0.9.0" @@ -1459,34 +1178,32 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "serde_derive", ] [[package]] -name = "serde_json" -version = "1.0.141" +name = "serde_derive" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1500,9 +1217,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -1532,32 +1249,21 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subenum" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5d5dfb8556dd04017db5e318bbeac8ab2b0c67b76bf197bfb79e9b29f18ecf" +checksum = "ec3d08fe7078c57309d5c3d938e50eba95ba1d33b9c3a101a8465fc6861a5416" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "syn", ] [[package]] name = "syn" -version = "2.0.104" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1582,42 +1288,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1634,27 +1320,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unty" @@ -1674,12 +1348,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "void" version = "1.0.2" @@ -1695,24 +1363,6 @@ dependencies = [ "vcell", ] -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" -dependencies = [ - "memchr", -] - [[package]] name = "wyz" version = "0.5.1" @@ -1722,33 +1372,22 @@ dependencies = [ "tap", ] -[[package]] -name = "yaml-rust2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] diff --git a/examples/rt633/Cargo.toml b/examples/rt633/Cargo.toml index 64a312b8..cd9682e8 100644 --- a/examples/rt633/Cargo.toml +++ b/examples/rt633/Cargo.toml @@ -49,6 +49,9 @@ mimxrt600-fcb = "0.2.0" rand = { version = "0.8.5", default-features = false } espi-service = { path = "../../espi-service", features = ["defmt"] } embedded-services = { path = "../../embedded-service", features = ["defmt"] } +power-policy-interface = { path = "../../power-policy-interface", features = [ + "defmt", +] } embedded-batteries-async = { version = "0.3", features = ["defmt"] } bq25773 = { git = "https://github.com/OpenDevicePartnership/bq25773" } diff --git a/examples/rt685s-evk/Cargo.lock b/examples/rt685s-evk/Cargo.lock index 333705b8..819c5ac3 100644 --- a/examples/rt685s-evk/Cargo.lock +++ b/examples/rt685s-evk/Cargo.lock @@ -735,7 +735,6 @@ dependencies = [ "embassy-futures", "embassy-sync", "embassy-time", - "embedded-batteries-async", "embedded-cfu-protocol", "embedded-hal-async", "embedded-io", @@ -1303,16 +1302,34 @@ dependencies = [ "embedded-hal-async", ] +[[package]] +name = "power-policy-interface" +version = "0.1.0" +dependencies = [ + "bitfield 0.17.0", + "defmt 0.3.100", + "embassy-futures", + "embassy-sync", + "embedded-batteries-async", + "embedded-services", + "heapless", + "num_enum", +] + [[package]] name = "power-policy-service" version = "0.1.0" dependencies = [ + "bitfield 0.17.0", "defmt 0.3.100", "embassy-futures", "embassy-sync", "embassy-time", + "embedded-batteries-async", "embedded-services", "heapless", + "num_enum", + "power-policy-interface", ] [[package]] @@ -1395,6 +1412,7 @@ dependencies = [ "panic-probe", "platform-service", "power-button-service", + "power-policy-interface", "power-policy-service", "static_cell", "time-alarm-service", @@ -1651,6 +1669,7 @@ version = "0.1.0" dependencies = [ "bitfield 0.17.0", "bitflags 2.9.4", + "bitvec", "cfu-service", "defmt 0.3.100", "embassy-futures", @@ -1663,6 +1682,8 @@ dependencies = [ "embedded-services", "embedded-usb-pd", "heapless", + "power-policy-interface", + "power-policy-service", "tps6699x", ] diff --git a/examples/rt685s-evk/Cargo.toml b/examples/rt685s-evk/Cargo.toml index 2f3cd630..4c5310c5 100644 --- a/examples/rt685s-evk/Cargo.toml +++ b/examples/rt685s-evk/Cargo.toml @@ -54,6 +54,9 @@ embedded-services = { path = "../../embedded-service", features = ["defmt"] } power-button-service = { path = "../../power-button-service", features = [ "defmt", ] } +power-policy-interface = { path = "../../power-policy-interface", features = [ + "defmt", +] } power-policy-service = { path = "../../power-policy-service", features = [ "defmt", ] } diff --git a/examples/rt685s-evk/src/bin/type_c.rs b/examples/rt685s-evk/src/bin/type_c.rs index 637021f3..e73a71f7 100644 --- a/examples/rt685s-evk/src/bin/type_c.rs +++ b/examples/rt685s-evk/src/bin/type_c.rs @@ -15,16 +15,16 @@ use embassy_sync::once_lock::OnceLock; use embassy_sync::pubsub::PubSubChannel; use embassy_time::{self as _, Delay, Timer}; use embedded_cfu_protocol::protocol_definitions::{FwUpdateOffer, FwUpdateOfferResponse, FwVersion, HostToken}; -use embedded_services::power::policy::{DeviceId as PowerId, policy}; -use embedded_services::type_c::{Cached, ControllerId}; use embedded_services::{GlobalRawMutex, IntrusiveList}; use embedded_services::{error, info}; use embedded_usb_pd::GlobalPortId; -use power_policy_service::PowerPolicy; +use power_policy_interface::psu::DeviceId as PowerId; +use power_policy_service::service::Service as PowerPolicyService; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; use type_c_service::driver::tps6699x::{self as tps6699x_drv}; use type_c_service::service::Service; +use type_c_service::type_c::{Cached, ControllerId}; use type_c_service::wrapper::ControllerWrapper; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; use type_c_service::wrapper::proxy::PowerProxyDevice; @@ -58,8 +58,8 @@ type Wrapper<'a> = ControllerWrapper< 'a, GlobalRawMutex, Tps6699xMutex<'a>, - DynamicSender<'a, policy::RequestData>, - DynamicReceiver<'a, policy::RequestData>, + DynamicSender<'a, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'a, power_policy_interface::psu::event::RequestData>, Validator, >; type Controller<'a> = tps6699x::controller::Controller>; @@ -81,14 +81,14 @@ async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: Interrupt<'st #[embassy_executor::task] async fn power_policy_service_task( - service: &'static PowerPolicy< + service: &'static PowerPolicyService< 'static, Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { Timer::after_millis(100).await; // Give some time for other tasks to start - power_policy_service::task::task(service) + power_policy_service::service::task::task(service) .await .expect("Failed to start power policy service task"); } @@ -97,9 +97,9 @@ async fn power_policy_service_task( async fn type_c_service_task( service: &'static Service<'static>, wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], - power_policy_context: &'static policy::Context< + power_policy_context: &'static power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, cfu_client: &'static CfuClient, ) { @@ -149,26 +149,26 @@ async fn main(spawner: Spawner) { // Create power policy service static POWER_SERVICE_CONTEXT: StaticCell< - policy::Context< + power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service_context = POWER_SERVICE_CONTEXT.init(policy::Context::new()); + let power_service_context = POWER_SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); static POWER_SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service = POWER_SERVICE.init(power_policy_service::PowerPolicy::new( + let power_service = POWER_SERVICE.init(power_policy_service::service::Service::new( power_service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); - static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); - let controller_context = CONTROLLER_CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); + let controller_context = CONTROLLER_CONTEXT.init(type_c_service::type_c::controller::Context::new()); static CONTROLLER_LIST: StaticCell = StaticCell::new(); let controller_list = CONTROLLER_LIST.init(IntrusiveList::new()); @@ -188,12 +188,14 @@ async fn main(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL0: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL0: StaticCell> = + StaticCell::new(); let policy_channel0 = POLICY_CHANNEL0.init(Channel::new()); let policy_sender0 = policy_channel0.dyn_sender(); let policy_receiver0 = policy_channel0.dyn_receiver(); - static POLICY_CHANNEL1: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL1: StaticCell> = + StaticCell::new(); let policy_channel1 = POLICY_CHANNEL1.init(Channel::new()); let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); @@ -202,8 +204,8 @@ async fn main(spawner: Spawner) { ReferencedStorage< TPS66994_NUM_PORTS, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced = REFERENCED.init( @@ -225,7 +227,7 @@ async fn main(spawner: Spawner) { // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot static POWER_POLICY_CHANNEL: StaticCell< - PubSubChannel, + PubSubChannel, > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); @@ -247,7 +249,12 @@ async fn main(spawner: Spawner) { let cfu_client = CfuClient::new(&CFU_CLIENT).await; info!("Spawining type-c service task"); - spawner.must_spawn(type_c_service_task(type_c_service, [wrapper], power_service_context, cfu_client)); + spawner.must_spawn(type_c_service_task( + type_c_service, + [wrapper], + power_service_context, + cfu_client, + )); info!("Spawining power policy task"); spawner.must_spawn(power_policy_service_task(power_service)); diff --git a/examples/rt685s-evk/src/bin/type_c_cfu.rs b/examples/rt685s-evk/src/bin/type_c_cfu.rs index 8a4d143d..f0c5a9e6 100644 --- a/examples/rt685s-evk/src/bin/type_c_cfu.rs +++ b/examples/rt685s-evk/src/bin/type_c_cfu.rs @@ -18,17 +18,16 @@ use embassy_time::Timer; use embassy_time::{self as _, Delay}; use embedded_cfu_protocol::protocol_definitions::*; use embedded_cfu_protocol::protocol_definitions::{FwUpdateOffer, FwUpdateOfferResponse, FwVersion}; -use embedded_services::power::policy::DeviceId as PowerId; -use embedded_services::power::policy::policy; -use embedded_services::type_c::ControllerId; use embedded_services::{GlobalRawMutex, IntrusiveList}; use embedded_services::{error, info}; use embedded_usb_pd::GlobalPortId; -use power_policy_service::PowerPolicy; +use power_policy_interface::psu::DeviceId as PowerId; +use power_policy_service::service::Service as PowerPolicyService; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; use type_c_service::driver::tps6699x::{self as tps6699x_drv}; use type_c_service::service::Service; +use type_c_service::type_c::ControllerId; use type_c_service::wrapper::ControllerWrapper; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; use type_c_service::wrapper::proxy::PowerProxyDevice; @@ -55,8 +54,8 @@ type Wrapper<'a> = ControllerWrapper< 'a, GlobalRawMutex, Tps6699xMutex<'a>, - DynamicSender<'a, policy::RequestData>, - DynamicReceiver<'a, policy::RequestData>, + DynamicSender<'a, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'a, power_policy_interface::psu::event::RequestData>, Validator, >; type Controller<'a> = tps6699x::controller::Controller>; @@ -166,14 +165,14 @@ async fn fw_update_task() { #[embassy_executor::task] async fn power_policy_service_task( - service: &'static PowerPolicy< + service: &'static PowerPolicyService< 'static, Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { Timer::after_millis(100).await; // Give some time for other tasks to start - power_policy_service::task::task(service) + power_policy_service::service::task::task(service) .await .expect("Failed to start power policy service task"); } @@ -182,9 +181,9 @@ async fn power_policy_service_task( async fn type_c_service_task( service: &'static Service<'static>, wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], - power_policy_context: &'static policy::Context< + power_policy_context: &'static power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, cfu_client: &'static CfuClient, ) { @@ -234,26 +233,26 @@ async fn main(spawner: Spawner) { // Create power policy service static POWER_SERVICE_CONTEXT: StaticCell< - policy::Context< + power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service_context = POWER_SERVICE_CONTEXT.init(policy::Context::new()); + let power_service_context = POWER_SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); static POWER_SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service = POWER_SERVICE.init(power_policy_service::PowerPolicy::new( + let power_service = POWER_SERVICE.init(power_policy_service::service::Service::new( power_service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); - static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); - let controller_context = CONTROLLER_CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); + let controller_context = CONTROLLER_CONTEXT.init(type_c_service::type_c::controller::Context::new()); static CONTROLLER_LIST: StaticCell = StaticCell::new(); let controller_list = CONTROLLER_LIST.init(IntrusiveList::new()); @@ -273,12 +272,14 @@ async fn main(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL0: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL0: StaticCell> = + StaticCell::new(); let policy_channel0 = POLICY_CHANNEL0.init(Channel::new()); let policy_sender0 = policy_channel0.dyn_sender(); let policy_receiver0 = policy_channel0.dyn_receiver(); - static POLICY_CHANNEL1: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL1: StaticCell> = + StaticCell::new(); let policy_channel1 = POLICY_CHANNEL1.init(Channel::new()); let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); @@ -287,8 +288,8 @@ async fn main(spawner: Spawner) { ReferencedStorage< TPS66994_NUM_PORTS, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced = REFERENCED.init( @@ -310,7 +311,7 @@ async fn main(spawner: Spawner) { // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot static POWER_POLICY_CHANNEL: StaticCell< - PubSubChannel, + PubSubChannel, > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); diff --git a/examples/std/Cargo.lock b/examples/std/Cargo.lock index f2659ecf..92cb2bfe 100644 --- a/examples/std/Cargo.lock +++ b/examples/std/Cargo.lock @@ -166,6 +166,7 @@ dependencies = [ "heapless", "log", "mctp-rs", + "power-policy-interface", "zerocopy", ] @@ -796,7 +797,6 @@ dependencies = [ "embassy-futures", "embassy-sync", "embassy-time", - "embedded-batteries-async", "embedded-cfu-protocol", "embedded-hal-async", "embedded-io", @@ -1384,16 +1384,34 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "power-policy-interface" +version = "0.1.0" +dependencies = [ + "bitfield 0.17.0", + "embassy-futures", + "embassy-sync", + "embedded-batteries-async", + "embedded-services", + "heapless", + "log", + "num_enum", +] + [[package]] name = "power-policy-service" version = "0.1.0" dependencies = [ + "bitfield 0.17.0", "embassy-futures", "embassy-sync", "embassy-time", + "embedded-batteries-async", "embedded-services", "heapless", "log", + "num_enum", + "power-policy-interface", ] [[package]] @@ -1649,6 +1667,7 @@ dependencies = [ "env_logger", "heapless", "log", + "power-policy-interface", "power-policy-service", "static_cell", "thermal-service", @@ -1865,6 +1884,7 @@ version = "0.1.0" dependencies = [ "bitfield 0.17.0", "bitflags 2.9.4", + "bitvec", "cfu-service", "embassy-futures", "embassy-sync", @@ -1877,6 +1897,8 @@ dependencies = [ "embedded-usb-pd", "heapless", "log", + "power-policy-interface", + "power-policy-service", "tps6699x", ] diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index ef102cee..8c661ca9 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -29,6 +29,9 @@ embedded-services = { path = "../../embedded-service", features = ["log"] } power-policy-service = { path = "../../power-policy-service", features = [ "log", ] } +power-policy-interface = { path = "../../power-policy-interface", features = [ + "log", +] } cfu-service = { path = "../../cfu-service", features = ["log"] } embedded-cfu-protocol = { git = "https://github.com/OpenDevicePartnership/embedded-cfu" } diff --git a/examples/std/src/bin/power_policy.rs b/examples/std/src/bin/power_policy.rs index 50d0030a..f6150926 100644 --- a/examples/std/src/bin/power_policy.rs +++ b/examples/std/src/bin/power_policy.rs @@ -6,18 +6,12 @@ use embassy_sync::{ pubsub::PubSubChannel, }; use embassy_time::{self as _, Timer}; -use embedded_services::{ - GlobalRawMutex, - broadcaster::immediate as broadcaster, - power::{ - self, - policy::{ - self, ConsumerPowerCapability, Error, PowerCapability, ProviderPowerCapability, device::DeviceTrait, flags, - }, - }, -}; +use embedded_services::{GlobalRawMutex, broadcaster::immediate as broadcaster}; use log::*; -use power_policy_service::PowerPolicy; +use power_policy_interface::capability::{ + ConsumerFlags, ConsumerPowerCapability, PowerCapability, ProviderPowerCapability, +}; +use power_policy_interface::psu::{Error, Psu}; use static_cell::StaticCell; const LOW_POWER: PowerCapability = PowerCapability { @@ -30,32 +24,36 @@ const HIGH_POWER: PowerCapability = PowerCapability { current_ma: 3000, }; -const DEVICE0_ID: policy::DeviceId = policy::DeviceId(0); -const DEVICE1_ID: policy::DeviceId = policy::DeviceId(1); +const DEVICE0_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(0); +const DEVICE1_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(1); const PER_CALL_DELAY_MS: u64 = 1000; struct ExampleDevice<'a> { - sender: channel::DynamicSender<'a, policy::policy::RequestData>, + sender: channel::DynamicSender<'a, power_policy_interface::psu::event::RequestData>, } impl<'a> ExampleDevice<'a> { - fn new(sender: channel::DynamicSender<'a, policy::policy::RequestData>) -> Self { + fn new(sender: channel::DynamicSender<'a, power_policy_interface::psu::event::RequestData>) -> Self { Self { sender } } pub async fn simulate_attach(&mut self) { - self.sender.send(policy::policy::RequestData::Attached).await; + self.sender + .send(power_policy_interface::psu::event::RequestData::Attached) + .await; } pub async fn simulate_update_consumer_power_capability(&mut self, capability: Option) { self.sender - .send(policy::policy::RequestData::UpdatedConsumerCapability(capability)) + .send(power_policy_interface::psu::event::RequestData::UpdatedConsumerCapability(capability)) .await; } pub async fn simulate_detach(&mut self) { - self.sender.send(policy::policy::RequestData::Detached).await; + self.sender + .send(power_policy_interface::psu::event::RequestData::Detached) + .await; } pub async fn simulate_update_requested_provider_power_capability( @@ -63,12 +61,12 @@ impl<'a> ExampleDevice<'a> { capability: Option, ) { self.sender - .send(policy::policy::RequestData::RequestedProviderCapability(capability)) + .send(power_policy_interface::psu::event::RequestData::RequestedProviderCapability(capability)) .await } } -impl DeviceTrait for ExampleDevice<'_> { +impl Psu for ExampleDevice<'_> { async fn disconnect(&mut self) -> Result<(), Error> { debug!("ExampleDevice disconnect"); Ok(()) @@ -90,61 +88,63 @@ async fn run(spawner: Spawner) { embedded_services::init().await; info!("Creating device 0"); - static DEVICE0_EVENT_CHANNEL: StaticCell> = StaticCell::new(); + static DEVICE0_EVENT_CHANNEL: StaticCell> = + StaticCell::new(); let device0_event_channel = DEVICE0_EVENT_CHANNEL.init(Channel::new()); static DEVICE0: StaticCell> = StaticCell::new(); let device0 = DEVICE0.init(Mutex::new(ExampleDevice::new(device0_event_channel.dyn_sender()))); static DEVICE0_REGISTRATION: StaticCell< - policy::device::Device< + power_policy_interface::psu::RegistrationEntry< 'static, Mutex, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let device0_registration = DEVICE0_REGISTRATION.init(policy::device::Device::new( + let device0_registration = DEVICE0_REGISTRATION.init(power_policy_interface::psu::RegistrationEntry::new( DEVICE0_ID, device0, device0_event_channel.dyn_receiver(), )); info!("Creating device 1"); - static DEVICE1_EVENT_CHANNEL: StaticCell> = StaticCell::new(); + static DEVICE1_EVENT_CHANNEL: StaticCell> = + StaticCell::new(); let device1_event_channel = DEVICE1_EVENT_CHANNEL.init(Channel::new()); static DEVICE1: StaticCell> = StaticCell::new(); let device1 = DEVICE1.init(Mutex::new(ExampleDevice::new(device1_event_channel.dyn_sender()))); static DEVICE1_REGISTRATION: StaticCell< - policy::device::Device< + power_policy_interface::psu::RegistrationEntry< 'static, Mutex, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let device1_registration = DEVICE1_REGISTRATION.init(policy::device::Device::new( + let device1_registration = DEVICE1_REGISTRATION.init(power_policy_interface::psu::RegistrationEntry::new( DEVICE1_ID, device1, device1_event_channel.dyn_receiver(), )); static SERVICE_CONTEXT: StaticCell< - power::policy::policy::Context< + power_policy_service::service::context::Context< Mutex>, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let service_context = SERVICE_CONTEXT.init(power::policy::policy::Context::new()); + let service_context = SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); - service_context.register_device(device0_registration).unwrap(); - service_context.register_device(device1_registration).unwrap(); + service_context.register_psu(device0_registration).unwrap(); + service_context.register_psu(device1_registration).unwrap(); static SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let service = SERVICE.init(power_policy_service::PowerPolicy::new( + let service = SERVICE.init(power_policy_service::service::Service::new( service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); spawner.must_spawn(power_policy_task(service)); @@ -157,7 +157,7 @@ async fn run(spawner: Spawner) { dev0.simulate_attach().await; dev0.simulate_update_consumer_power_capability(Some(ConsumerPowerCapability { capability: LOW_POWER, - flags: flags::Consumer::none().with_unconstrained_power(), + flags: ConsumerFlags::none().with_unconstrained_power(), })) .await; } @@ -272,19 +272,22 @@ async fn run(spawner: Spawner) { #[embassy_executor::task] async fn receiver_task( - service: &'static power_policy_service::PowerPolicy< + service: &'static power_policy_service::service::Service< 'static, Mutex>, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { - static CHANNEL: StaticCell> = StaticCell::new(); + static CHANNEL: StaticCell< + PubSubChannel, + > = StaticCell::new(); let channel = CHANNEL.init(PubSubChannel::new()); let publisher = channel.dyn_immediate_publisher(); let mut subscriber = channel.dyn_subscriber().unwrap(); - static RECEIVER: StaticCell> = StaticCell::new(); + static RECEIVER: StaticCell> = + StaticCell::new(); let receiver = RECEIVER.init(broadcaster::Receiver::new(publisher)); service.context.register_message_receiver(receiver).unwrap(); @@ -303,13 +306,13 @@ async fn receiver_task( #[embassy_executor::task] async fn power_policy_task( - power_policy: &'static PowerPolicy< + power_policy: &'static power_policy_service::service::Service< 'static, Mutex>, - channel::DynamicReceiver<'static, policy::policy::RequestData>, + channel::DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { - power_policy_service::task::task(power_policy).await.unwrap(); + power_policy_service::service::task::task(power_policy).await.unwrap(); } fn main() { diff --git a/examples/std/src/bin/type_c/basic.rs b/examples/std/src/bin/type_c/basic.rs index c1d32842..1bdbb604 100644 --- a/examples/std/src/bin/type_c/basic.rs +++ b/examples/std/src/bin/type_c/basic.rs @@ -2,19 +2,19 @@ use embassy_executor::{Executor, Spawner}; use embassy_sync::once_lock::OnceLock; use embassy_time::Timer; use embedded_services::IntrusiveList; -use embedded_services::type_c::{Cached, ControllerId, controller}; use embedded_usb_pd::ucsi::lpm; use embedded_usb_pd::{GlobalPortId, PdError as Error}; use log::*; use static_cell::StaticCell; +use type_c_service::type_c::{Cached, ControllerId, controller}; const CONTROLLER0_ID: ControllerId = ControllerId(0); const PORT0_ID: GlobalPortId = GlobalPortId(0); const PORT1_ID: GlobalPortId = GlobalPortId(1); mod test_controller { - use embedded_services::type_c::controller::{ControllerStatus, PortStatus}; use embedded_usb_pd::ucsi; + use type_c_service::type_c::controller::{ControllerStatus, PortStatus}; use super::*; diff --git a/examples/std/src/bin/type_c/external.rs b/examples/std/src/bin/type_c/external.rs index 7ea0f5ea..4804731c 100644 --- a/examples/std/src/bin/type_c/external.rs +++ b/examples/std/src/bin/type_c/external.rs @@ -4,23 +4,19 @@ use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; use embassy_sync::mutex::Mutex; use embassy_sync::pubsub::PubSubChannel; use embassy_time::Timer; -use embedded_services::power::policy::policy; -use embedded_services::type_c::controller; -use embedded_services::{ - GlobalRawMutex, IntrusiveList, power, - type_c::{Cached, ControllerId, controller::Context}, -}; +use embedded_services::{GlobalRawMutex, IntrusiveList}; use embedded_usb_pd::GlobalPortId; use log::*; use static_cell::StaticCell; use std_examples::type_c::mock_controller::{self, Wrapper}; use type_c_service::service::{Service, config::Config}; +use type_c_service::type_c::{Cached, ControllerId, controller, controller::Context}; use type_c_service::wrapper::backing::Storage; const NUM_PD_CONTROLLERS: usize = 1; const CONTROLLER0_ID: ControllerId = ControllerId(0); const PORT0_ID: GlobalPortId = GlobalPortId(0); -const POWER0_ID: power::policy::DeviceId = power::policy::DeviceId(0); +const POWER0_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(0); #[embassy_executor::task] async fn controller_task(wrapper: &'static Wrapper<'static>) { @@ -105,8 +101,9 @@ async fn service_task( info!("Starting type-c task"); // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot - static POWER_POLICY_CHANNEL: StaticCell> = - StaticCell::new(); + static POWER_POLICY_CHANNEL: StaticCell< + PubSubChannel, + > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); let power_policy_publisher = power_policy_channel.dyn_immediate_publisher(); @@ -153,7 +150,8 @@ fn create_wrapper(controller_context: &'static Context) -> &'static mut Wrapper< .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL: StaticCell> = + StaticCell::new(); let policy_channel = POLICY_CHANNEL.init(Channel::new()); let policy_sender = policy_channel.dyn_sender(); @@ -163,8 +161,8 @@ fn create_wrapper(controller_context: &'static Context) -> &'static mut Wrapper< type_c_service::wrapper::backing::ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced = REFERENCED.init( @@ -193,8 +191,8 @@ fn main() { static CONTROLLER_LIST: StaticCell = StaticCell::new(); let controller_list = CONTROLLER_LIST.init(IntrusiveList::new()); - static CONTEXT: StaticCell = StaticCell::new(); - let context = CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTEXT: StaticCell = StaticCell::new(); + let context = CONTEXT.init(type_c_service::type_c::controller::Context::new()); let wrapper = create_wrapper(context); diff --git a/examples/std/src/bin/type_c/service.rs b/examples/std/src/bin/type_c/service.rs index e6647778..189f6ad6 100644 --- a/examples/std/src/bin/type_c/service.rs +++ b/examples/std/src/bin/type_c/service.rs @@ -5,21 +5,19 @@ use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; use embassy_sync::pubsub::PubSubChannel; use embassy_time::Timer; -use embedded_services::power::policy::policy; -use embedded_services::power::{self}; -use embedded_services::type_c::ControllerId; -use embedded_services::type_c::controller::Context; use embedded_services::{GlobalRawMutex, IntrusiveList}; use embedded_usb_pd::GlobalPortId; use embedded_usb_pd::ado::Ado; use embedded_usb_pd::type_c::Current; use log::*; -use power_policy_service::PowerPolicy; +use power_policy_service::service::Service as PowerPolicyService; use static_cell::StaticCell; use std_examples::type_c::mock_controller; use std_examples::type_c::mock_controller::Wrapper; use type_c_service::service::Service; use type_c_service::service::config::Config; +use type_c_service::type_c::controller::Context; +use type_c_service::type_c::{ControllerId, power_capability_from_current}; use type_c_service::wrapper::backing::Storage; use type_c_service::wrapper::message::*; use type_c_service::wrapper::proxy::PowerProxyDevice; @@ -27,7 +25,7 @@ use type_c_service::wrapper::proxy::PowerProxyDevice; const NUM_PD_CONTROLLERS: usize = 1; const CONTROLLER0_ID: ControllerId = ControllerId(0); const PORT0_ID: GlobalPortId = GlobalPortId(0); -const POWER0_ID: power::policy::DeviceId = power::policy::DeviceId(0); +const POWER0_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(0); const DELAY_MS: u64 = 1000; #[embassy_executor::task] @@ -65,33 +63,34 @@ async fn task(spawner: Spawner) { // Create power policy service static POWER_SERVICE_CONTEXT: StaticCell< - power::policy::policy::Context< + power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service_context = POWER_SERVICE_CONTEXT.init(power::policy::policy::Context::new()); + let power_service_context = POWER_SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); - static CONTEXT: StaticCell = StaticCell::new(); - let controller_context = CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTEXT: StaticCell = StaticCell::new(); + let controller_context = CONTEXT.init(type_c_service::type_c::controller::Context::new()); let (wrapper, controller, state) = create_wrapper(controller_context); static POWER_SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service = POWER_SERVICE.init(power_policy_service::PowerPolicy::new( + let power_service = POWER_SERVICE.init(power_policy_service::service::Service::new( power_service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); // Create type-c service // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot - static POWER_POLICY_CHANNEL: StaticCell> = - StaticCell::new(); + static POWER_POLICY_CHANNEL: StaticCell< + PubSubChannel, + > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); let power_policy_publisher = power_policy_channel.dyn_immediate_publisher(); @@ -125,7 +124,9 @@ async fn task(spawner: Spawner) { Timer::after_millis(1000).await; info!("Simulating connection"); - state.connect_sink(Current::UsbDefault.into(), false).await; + state + .connect_sink(power_capability_from_current(Current::UsbDefault), false) + .await; Timer::after_millis(DELAY_MS).await; info!("Simulating PD alert"); @@ -147,13 +148,13 @@ async fn task(spawner: Spawner) { #[embassy_executor::task] async fn power_policy_service_task( - service: &'static PowerPolicy< + service: &'static PowerPolicyService< 'static, Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { - power_policy_service::task::task(service) + power_policy_service::service::task::task(service) .await .expect("Failed to start power policy service task"); } @@ -162,9 +163,9 @@ async fn power_policy_service_task( async fn type_c_service_task( service: &'static Service<'static>, wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], - power_policy_context: &'static policy::Context< + power_policy_context: &'static power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, cfu_client: &'static CfuClient, ) { @@ -198,7 +199,8 @@ fn create_wrapper( .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL: StaticCell> = + StaticCell::new(); let policy_channel = POLICY_CHANNEL.init(Channel::new()); let policy_sender = policy_channel.dyn_sender(); @@ -208,8 +210,8 @@ fn create_wrapper( type_c_service::wrapper::backing::ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced = REFERENCED.init( diff --git a/examples/std/src/bin/type_c/ucsi.rs b/examples/std/src/bin/type_c/ucsi.rs index 47594060..7bb5c144 100644 --- a/examples/std/src/bin/type_c/ucsi.rs +++ b/examples/std/src/bin/type_c/ucsi.rs @@ -7,11 +7,6 @@ use embassy_sync::once_lock::OnceLock; use embassy_sync::pubsub::PubSubChannel; use embedded_services::GlobalRawMutex; use embedded_services::IntrusiveList; -use embedded_services::power::policy::PowerCapability; -use embedded_services::power::policy::policy; -use embedded_services::type_c::ControllerId; -use embedded_services::type_c::controller::Context; -use embedded_services::type_c::external::UcsiResponseResult; use embedded_usb_pd::GlobalPortId; use embedded_usb_pd::ucsi::lpm::get_connector_capability::OperationModeFlags; use embedded_usb_pd::ucsi::ppm::ack_cc_ci::Ack; @@ -19,11 +14,15 @@ use embedded_usb_pd::ucsi::ppm::get_capability::ResponseData as UcsiCapabilities use embedded_usb_pd::ucsi::ppm::set_notification_enable::NotificationEnable; use embedded_usb_pd::ucsi::{Command, lpm, ppm}; use log::*; -use power_policy_service::PowerPolicy; +use power_policy_interface::capability::PowerCapability; +use power_policy_service::service::Service as PowerPolicyService; use static_cell::StaticCell; use std_examples::type_c::mock_controller; use type_c_service::service::Service; use type_c_service::service::config::Config; +use type_c_service::type_c::ControllerId; +use type_c_service::type_c::controller::Context; +use type_c_service::type_c::external::UcsiResponseResult; use type_c_service::wrapper::backing::Storage; use type_c_service::wrapper::proxy::PowerProxyDevice; @@ -31,9 +30,9 @@ const NUM_PD_CONTROLLERS: usize = 2; const CONTROLLER0_ID: ControllerId = ControllerId(0); const CONTROLLER1_ID: ControllerId = ControllerId(1); const PORT0_ID: GlobalPortId = GlobalPortId(0); -const POWER0_ID: embedded_services::power::policy::DeviceId = embedded_services::power::policy::DeviceId(0); +const POWER0_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(0); const PORT1_ID: GlobalPortId = GlobalPortId(1); -const POWER1_ID: embedded_services::power::policy::DeviceId = embedded_services::power::policy::DeviceId(1); +const POWER1_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(1); const CFU0_ID: u8 = 0x00; const CFU1_ID: u8 = 0x01; @@ -178,13 +177,13 @@ async fn wrapper_task(wrapper: &'static mock_controller::Wrapper<'static>) { #[embassy_executor::task] async fn power_policy_service_task( - service: &'static PowerPolicy< + service: &'static PowerPolicyService< 'static, Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { - power_policy_service::task::task(service) + power_policy_service::service::task::task(service) .await .expect("Failed to start power policy service task"); } @@ -193,9 +192,9 @@ async fn power_policy_service_task( async fn type_c_service_task( service: &'static Service<'static>, wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], - power_policy_context: &'static policy::Context< + power_policy_context: &'static power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, cfu_client: &'static CfuClient, ) { @@ -211,26 +210,26 @@ async fn task(spawner: Spawner) { // Create power policy service static POWER_SERVICE_CONTEXT: StaticCell< - policy::Context< + power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service_context = POWER_SERVICE_CONTEXT.init(policy::Context::new()); + let power_service_context = POWER_SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); static POWER_SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service = POWER_SERVICE.init(power_policy_service::PowerPolicy::new( + let power_service = POWER_SERVICE.init(power_policy_service::service::Service::new( power_service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); - static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); - let controller_context = CONTROLLER_CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); + let controller_context = CONTROLLER_CONTEXT.init(type_c_service::type_c::controller::Context::new()); static CONTROLLER_LIST: StaticCell = StaticCell::new(); let controller_list = CONTROLLER_LIST.init(IntrusiveList::new()); @@ -246,7 +245,8 @@ async fn task(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL0: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL0: StaticCell> = + StaticCell::new(); let policy_channel0 = POLICY_CHANNEL0.init(Channel::new()); let policy_sender0 = policy_channel0.dyn_sender(); let policy_receiver0 = policy_channel0.dyn_receiver(); @@ -255,8 +255,8 @@ async fn task(spawner: Spawner) { type_c_service::wrapper::backing::ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced0 = REFERENCED0.init( @@ -285,7 +285,8 @@ async fn task(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL1: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL1: StaticCell> = + StaticCell::new(); let policy_channel1 = POLICY_CHANNEL1.init(Channel::new()); let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); @@ -294,8 +295,8 @@ async fn task(spawner: Spawner) { type_c_service::wrapper::backing::ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced1 = REFERENCED1.init( @@ -317,7 +318,7 @@ async fn task(spawner: Spawner) { // Create type-c service // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot static POWER_POLICY_CHANNEL: StaticCell< - PubSubChannel, + PubSubChannel, > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); diff --git a/examples/std/src/bin/type_c/unconstrained.rs b/examples/std/src/bin/type_c/unconstrained.rs index c8ccf0bb..5913bbbc 100644 --- a/examples/std/src/bin/type_c/unconstrained.rs +++ b/examples/std/src/bin/type_c/unconstrained.rs @@ -8,17 +8,15 @@ use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; use embassy_sync::pubsub::PubSubChannel; use embassy_time::Timer; -use embedded_services::power::policy::PowerCapability; -use embedded_services::power::policy::policy; -use embedded_services::power::{self}; -use embedded_services::type_c::ControllerId; use embedded_services::{GlobalRawMutex, IntrusiveList}; use embedded_usb_pd::GlobalPortId; use log::*; -use power_policy_service::PowerPolicy; +use power_policy_interface::capability::PowerCapability; +use power_policy_service::service::Service as PowerPolicyService; use static_cell::StaticCell; use std_examples::type_c::mock_controller; use type_c_service::service::Service; +use type_c_service::type_c::ControllerId; const NUM_PD_CONTROLLERS: usize = 3; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; @@ -26,17 +24,17 @@ use type_c_service::wrapper::proxy::PowerProxyDevice; const CONTROLLER0_ID: ControllerId = ControllerId(0); const PORT0_ID: GlobalPortId = GlobalPortId(0); -const POWER0_ID: power::policy::DeviceId = power::policy::DeviceId(0); +const POWER0_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(0); const CFU0_ID: u8 = 0x00; const CONTROLLER1_ID: ControllerId = ControllerId(1); const PORT1_ID: GlobalPortId = GlobalPortId(1); -const POWER1_ID: power::policy::DeviceId = power::policy::DeviceId(1); +const POWER1_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(1); const CFU1_ID: u8 = 0x01; const CONTROLLER2_ID: ControllerId = ControllerId(2); const PORT2_ID: GlobalPortId = GlobalPortId(2); -const POWER2_ID: power::policy::DeviceId = power::policy::DeviceId(2); +const POWER2_ID: power_policy_interface::psu::DeviceId = power_policy_interface::psu::DeviceId(2); const CFU2_ID: u8 = 0x02; const DELAY_MS: u64 = 1000; @@ -56,29 +54,29 @@ async fn task(spawner: Spawner) { // Create power policy service static POWER_SERVICE_CONTEXT: StaticCell< - policy::Context< + power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service_context = POWER_SERVICE_CONTEXT.init(policy::Context::new()); + let power_service_context = POWER_SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); - static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); - let controller_context = CONTROLLER_CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTROLLER_CONTEXT: StaticCell = StaticCell::new(); + let controller_context = CONTROLLER_CONTEXT.init(type_c_service::type_c::controller::Context::new()); static POWER_SERVICE: StaticCell< - power_policy_service::PowerPolicy< + power_policy_service::service::Service< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); - let power_service = POWER_SERVICE.init(power_policy_service::PowerPolicy::new( + let power_service = POWER_SERVICE.init(power_policy_service::service::Service::new( power_service_context, - power_policy_service::config::Config::default(), + power_policy_service::service::config::Config::default(), )); - static CONTEXT: StaticCell = StaticCell::new(); - let context = CONTEXT.init(embedded_services::type_c::controller::Context::new()); + static CONTEXT: StaticCell = StaticCell::new(); + let context = CONTEXT.init(type_c_service::type_c::controller::Context::new()); static CONTROLLER_LIST: StaticCell = StaticCell::new(); let controller_list = CONTROLLER_LIST.init(IntrusiveList::new()); @@ -91,7 +89,8 @@ async fn task(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL0: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL0: StaticCell> = + StaticCell::new(); let policy_channel0 = POLICY_CHANNEL0.init(Channel::new()); let policy_sender0 = policy_channel0.dyn_sender(); let policy_receiver0 = policy_channel0.dyn_receiver(); @@ -100,8 +99,8 @@ async fn task(spawner: Spawner) { ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced0 = REFERENCED0.init( @@ -134,7 +133,8 @@ async fn task(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL1: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL1: StaticCell> = + StaticCell::new(); let policy_channel1 = POLICY_CHANNEL1.init(Channel::new()); let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); @@ -143,8 +143,8 @@ async fn task(spawner: Spawner) { ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced1 = REFERENCED1.init( @@ -177,7 +177,8 @@ async fn task(spawner: Spawner) { .expect("Failed to create intermediate storage"), ); - static POLICY_CHANNEL2: StaticCell> = StaticCell::new(); + static POLICY_CHANNEL2: StaticCell> = + StaticCell::new(); let policy_channel2 = POLICY_CHANNEL2.init(Channel::new()); let policy_sender2 = policy_channel2.dyn_sender(); let policy_receiver2 = policy_channel2.dyn_receiver(); @@ -186,8 +187,8 @@ async fn task(spawner: Spawner) { ReferencedStorage< 1, GlobalRawMutex, - DynamicSender<'_, policy::RequestData>, - DynamicReceiver<'_, policy::RequestData>, + DynamicSender<'_, power_policy_interface::psu::event::RequestData>, + DynamicReceiver<'_, power_policy_interface::psu::event::RequestData>, >, > = StaticCell::new(); let referenced2 = REFERENCED2.init( @@ -214,7 +215,7 @@ async fn task(spawner: Spawner) { // Create type-c service // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot static POWER_POLICY_CHANNEL: StaticCell< - PubSubChannel, + PubSubChannel, > = StaticCell::new(); let power_policy_channel = POWER_POLICY_CHANNEL.init(PubSubChannel::new()); @@ -298,13 +299,13 @@ async fn task(spawner: Spawner) { #[embassy_executor::task] async fn power_policy_service_task( - service: &'static PowerPolicy< + service: &'static PowerPolicyService< 'static, Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, ) { - power_policy_service::task::task(service) + power_policy_service::service::task::task(service) .await .expect("Failed to start power policy service task"); } @@ -313,9 +314,9 @@ async fn power_policy_service_task( async fn type_c_service_task( service: &'static Service<'static>, wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], - power_policy_context: &'static policy::Context< + power_policy_context: &'static power_policy_service::service::context::Context< Mutex>, - DynamicReceiver<'static, policy::RequestData>, + DynamicReceiver<'static, power_policy_interface::psu::event::RequestData>, >, cfu_client: &'static CfuClient, ) { diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index a3cda41b..45dd0478 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -1,22 +1,22 @@ use embassy_sync::{channel, mutex::Mutex, signal::Signal}; use embedded_cfu_protocol::protocol_definitions::{FwUpdateOfferResponse, HostToken}; -use embedded_services::{ - GlobalRawMutex, - power::policy::{PowerCapability, policy}, - type_c::{ - controller::{ - AttnVdm, ControllerStatus, DpConfig, DpPinConfig, DpStatus, OtherVdm, PdStateMachineConfig, PortStatus, - RetimerFwUpdateState, SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, - }, - event::PortEvent, - }, -}; +use embedded_services::GlobalRawMutex; use embedded_usb_pd::{Error, 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}; use log::{debug, info, trace}; +use power_policy_interface::capability::PowerCapability; +use type_c_service::type_c::{ + controller::{ + AttnVdm, ControllerStatus, DpConfig, DpPinConfig, DpStatus, OtherVdm, PdStateMachineConfig, PortStatus, + RetimerFwUpdateState, SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, + }, + event::PortEvent, + power_capability_from_current, +}; + pub struct ControllerState { events: Signal, status: Mutex, @@ -77,7 +77,8 @@ impl ControllerState { /// Simulate a debug accessory source connecting pub async fn connect_debug_accessory_source(&self, current: Current) { - self.connect(PowerRole::Source, current.into(), true, false).await; + self.connect(PowerRole::Source, power_capability_from_current(current), true, false) + .await; } /// Simulate a PD alert @@ -115,7 +116,7 @@ impl<'a> Controller<'a> { } } -impl embedded_services::type_c::controller::Controller for Controller<'_> { +impl type_c_service::type_c::controller::Controller for Controller<'_> { type BusError = (); async fn wait_port_event(&mut self) -> Result<(), Error> { @@ -341,7 +342,7 @@ pub type Wrapper<'a> = type_c_service::wrapper::ControllerWrapper< 'a, GlobalRawMutex, Mutex>, - channel::DynamicSender<'a, policy::RequestData>, - channel::DynamicReceiver<'a, policy::RequestData>, + channel::DynamicSender<'a, power_policy_interface::psu::event::RequestData>, + channel::DynamicReceiver<'a, power_policy_interface::psu::event::RequestData>, Validator, >; diff --git a/power-policy-interface/Cargo.toml b/power-policy-interface/Cargo.toml new file mode 100644 index 00000000..81935f91 --- /dev/null +++ b/power-policy-interface/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "power-policy-interface" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +defmt = { workspace = true, optional = true } +embassy-sync.workspace = true +embedded-services.workspace = true +embassy-futures.workspace = true +num_enum.workspace = true +bitfield.workspace = true +log = { workspace = true, optional = true } +heapless.workspace = true +embedded-batteries-async.workspace = true + +[features] +default = [] +defmt = ["dep:defmt", "embedded-services/defmt", "embassy-sync/defmt"] +log = ["dep:log", "embedded-services/log", "embassy-sync/log"] diff --git a/embedded-service/src/power/policy/flags.rs b/power-policy-interface/src/capability.rs similarity index 66% rename from embedded-service/src/power/policy/flags.rs rename to power-policy-interface/src/capability.rs index b9fbcc4d..d53698b1 100644 --- a/embedded-service/src/power/policy/flags.rs +++ b/power-policy-interface/src/capability.rs @@ -1,8 +1,84 @@ -//! Consumer and provider flags, these are used to signal additional information about a consumer/provider request - +//! Power capability definitions and related flags use bitfield::bitfield; use num_enum::{IntoPrimitive, TryFromPrimitive}; +/// Amount of power that a device can provider or consume +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PowerCapability { + /// Available voltage in mV + pub voltage_mv: u16, + /// Max available current in mA + pub current_ma: u16, +} + +impl PowerCapability { + /// Calculate maximum power + pub fn max_power_mw(&self) -> u32 { + self.voltage_mv as u32 * self.current_ma as u32 / 1000 + } +} + +impl PartialOrd for PowerCapability { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for PowerCapability { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.max_power_mw().cmp(&other.max_power_mw()) + } +} + +/// Power capability with consumer flags +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ConsumerPowerCapability { + /// Power capability + pub capability: PowerCapability, + /// Consumer flags + pub flags: ConsumerFlags, +} + +impl From for ConsumerPowerCapability { + fn from(capability: PowerCapability) -> Self { + Self { + capability, + flags: ConsumerFlags::none(), + } + } +} + +/// Power capability with provider flags +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ProviderPowerCapability { + /// Power capability + pub capability: PowerCapability, + /// Provider flags + pub flags: ProviderFlags, +} + +impl From for ProviderPowerCapability { + fn from(capability: PowerCapability) -> Self { + Self { + capability, + flags: ProviderFlags::none(), + } + } +} + +/// Combined power capability with flags enum +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum PowerCapabilityFlags { + /// Consumer flags + Consumer(ConsumerPowerCapability), + /// Provider flags + Provider(ProviderPowerCapability), +} + /// PSU type #[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)] #[num_enum(error_type(name = InvalidPsuType, constructor = InvalidPsuType))] @@ -37,7 +113,7 @@ bitfield! { /// Raw consumer flags bit field #[derive(Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] - struct ConsumerRaw(u32); + struct ConsumerFlagsRaw(u32); impl Debug; /// Unconstrained power, indicates that we are drawing power from something like an outlet and not a limited source like a battery pub bool, unconstrained_power, set_unconstrained_power: 0; @@ -48,12 +124,12 @@ bitfield! { /// Type safe wrapper for consumer flags #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Consumer(ConsumerRaw); +pub struct ConsumerFlags(ConsumerFlagsRaw); -impl Consumer { +impl ConsumerFlags { /// Create a new consumer with no flags set pub const fn none() -> Self { - Self(ConsumerRaw(0)) + Self(ConsumerFlagsRaw(0)) } /// Builder method to set the unconstrained power flag @@ -102,9 +178,9 @@ bitfield! { /// Type safe wrapper for provider flags #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Provider(ProviderRaw); +pub struct ProviderFlags(ProviderRaw); -impl Provider { +impl ProviderFlags { /// Create a new provider with no flags set pub const fn none() -> Self { Self(ProviderRaw(0)) @@ -158,24 +234,24 @@ mod tests { } #[test] - fn test_consumer_unconstrained() { - let mut consumer = Consumer::none().with_unconstrained_power(); + fn test_consumer_flags_unconstrained() { + let mut consumer = ConsumerFlags::none().with_unconstrained_power(); assert_eq!(consumer.0.0, 0x1); consumer.set_unconstrained_power(false); assert_eq!(consumer.0.0, 0x0); } #[test] - fn test_consumer_psu_type() { - let mut consumer = Consumer::none().with_psu_type(PsuType::TypeC); + fn test_consumer_flags_psu_type() { + let mut consumer = ConsumerFlags::none().with_psu_type(PsuType::TypeC); assert_eq!(consumer.0.0, 0x100); consumer.set_psu_type(PsuType::Unknown); assert_eq!(consumer.0.0, 0x0); } #[test] - fn test_provider_psu_type() { - let mut provider = Provider::none().with_psu_type(PsuType::TypeC); + fn test_provider_flags_psu_type() { + let mut provider = ProviderFlags::none().with_psu_type(PsuType::TypeC); assert_eq!(provider.0.0, 0x100); provider.set_psu_type(PsuType::Unknown); assert_eq!(provider.0.0, 0x0); diff --git a/power-policy-service/src/charger.rs b/power-policy-interface/src/charger.rs similarity index 50% rename from power-policy-service/src/charger.rs rename to power-policy-interface/src/charger.rs index 72e8a292..f338ca66 100644 --- a/power-policy-service/src/charger.rs +++ b/power-policy-interface/src/charger.rs @@ -1,39 +1,271 @@ -use embassy_sync::mutex::Mutex; -use embedded_services::GlobalRawMutex; +//! Charger device struct and controller +use core::{future::Future, ops::DerefMut}; use embassy_futures::select::select; -use embedded_services::{ - debug, error, info, - power::policy::charger::{ - self, ChargeController, ChargerEvent, ChargerResponse, InternalState, PolicyEvent, PoweredSubstate, State, - }, - trace, warn, -}; +use embassy_sync::{channel::Channel, mutex::Mutex}; +use embedded_services::{GlobalRawMutex, debug, error, info, intrusive_list, trace, warn}; + +use crate::capability::{ConsumerPowerCapability, PowerCapability}; + +/// Charger controller trait that device drivers may use to integrate with internal messaging system +pub trait ChargeController: embedded_batteries_async::charger::Charger { + /// Type of error returned by the bus + type ChargeControllerError; + + /// Returns with pending events + fn wait_event(&mut self) -> impl Future; + /// Initialize charger hardware, after this returns the charger should be ready to charge + fn init_charger(&mut self) -> impl Future>; + /// Returns if the charger hardware detects if a PSU is attached + fn is_psu_attached(&mut self) -> impl Future>; + /// Called after power policy attaches to a power port. + fn attach_handler( + &mut self, + capability: ConsumerPowerCapability, + ) -> impl Future>; + /// Called after power policy detaches from a power port, either to switch consumers, + /// or because PSU was disconnected. + fn detach_handler(&mut self) -> impl Future>; + /// Called when a charger CheckReady request (PolicyEvent::CheckReady) is sent to the power policy. + /// Upon successful return of this method, the charger is assumed to be powered and ready to communicate, + /// transitioning state from unpowered to powered. + /// + /// If the charger is powered, an Ok(()) does nothing. An Err(_) will put the charger into an + /// unpowered state, meaning another PolicyEvent::CheckReady must be sent to re-establish communications + /// with the charger. Upon successful return, the charger must be re-initialized by sending a + /// `PolicyEvent::InitRequest`. + fn is_ready(&mut self) -> impl Future> { + core::future::ready(Ok(())) + } +} + +/// Charger Device ID new type +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ChargerId(pub u8); + +/// PSU state as determined by charger device +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum PsuState { + /// Charger detected PSU attached + Attached, + /// Charger detected PSU detached + Detached, +} + +impl From for PsuState { + fn from(value: bool) -> Self { + match value { + true => PsuState::Attached, + false => PsuState::Detached, + } + } +} + +/// Data for a device request +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ChargerEvent { + /// Charger finished initialization sequence + Initialized(PsuState), + /// PSU state changed + PsuStateChange(PsuState), + /// A timeout of some sort was detected + Timeout, + /// An error occured on the bus + BusError, +} + +/// Charger state errors +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ChargerError { + /// Charger received command in an invalid state + InvalidState(State), + /// Charger hardware timed out responding + Timeout, + /// Charger underlying bus error + BusError, +} + +impl From for crate::psu::Error { + fn from(value: ChargerError) -> Self { + Self::Charger(value) + } +} + +/// Data for a device request +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum PolicyEvent { + /// Request to initialize charger hardware + InitRequest, + /// New power policy detected + PolicyConfiguration(ConsumerPowerCapability), + /// Request to check if the charger hardware is ready to receive communications. + /// For example, if the charger is powered. + CheckReady, +} + +/// Data for a device request +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ChargerResponseData { + /// Command completed + Ack, + /// Charger Unpowered, but we are still Ok + UnpoweredAck, +} + +/// Response for charger requests from policy commands +pub type ChargerResponse = Result; + +/// Current state of the charger +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum State { + /// Device is unpowered + Unpowered, + /// Device is powered + Powered(PoweredSubstate), +} + +/// Powered state substates +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum PoweredSubstate { + /// Device is initializing + Init, + /// PSU is attached and device can charge if desired + PsuAttached, + /// PSU is detached + PsuDetached, +} + +/// Current state of the charger +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct InternalState { + /// Charger device state + pub state: State, + /// Current charger capability + pub capability: Option, +} + +/// Channel size for device requests +pub const CHARGER_CHANNEL_SIZE: usize = 1; + +/// Device struct +pub struct Device { + /// Intrusive list node + node: intrusive_list::Node, + /// Device ID + id: ChargerId, + /// Current state of the device + state: Mutex, + /// Channel for requests to the device + commands: Channel, + /// Channel for responses from the device + response: Channel, +} + +impl Device { + /// Create a new device + pub fn new(id: ChargerId) -> Self { + Self { + node: intrusive_list::Node::uninit(), + id, + state: Mutex::new(InternalState { + state: State::Unpowered, + capability: None, + }), + commands: Channel::new(), + response: Channel::new(), + } + } + + /// Get the device ID + pub fn id(&self) -> ChargerId { + self.id + } + + /// Returns the current state of the device + pub async fn state(&self) -> InternalState { + *self.state.lock().await + } + + /// Set the state of the device + pub async fn set_state(&self, new_state: InternalState) { + let mut lock = self.state.lock().await; + let current_state = lock.deref_mut(); + *current_state = new_state; + } + + /// Wait for a command from policy + pub async fn wait_command(&self) -> PolicyEvent { + self.commands.receive().await + } + + /// Send a command to the charger + pub async fn send_command(&self, policy_event: PolicyEvent) { + self.commands.send(policy_event).await + } + + /// Send a response to the power policy + pub async fn send_response(&self, response: ChargerResponse) { + self.response.send(response).await + } + + /// Send a command and wait for a response from the charger + pub async fn execute_command(&self, policy_event: PolicyEvent) -> ChargerResponse { + self.send_command(policy_event).await; + self.response.receive().await + } +} + +impl intrusive_list::NodeContainer for Device { + fn get_node(&self) -> &intrusive_list::Node { + &self.node + } +} + +/// Trait for any container that holds a device +pub trait ChargerContainer { + /// Get the underlying device struct + fn get_charger(&self) -> &Device; +} + +impl ChargerContainer for Device { + fn get_charger(&self) -> &Device { + self + } +} pub struct Wrapper<'a, C: ChargeController> where - charger::ChargerError: From<::ChargeControllerError>, + ChargerError: From<::ChargeControllerError>, { - charger_policy_state: &'a charger::Device, + charger_policy_state: &'a Device, controller: Mutex, } impl<'a, C: ChargeController> Wrapper<'a, C> where - charger::ChargerError: From<::ChargeControllerError>, + ChargerError: From<::ChargeControllerError>, { - pub fn new(charger_policy_state: &'a charger::Device, controller: C) -> Self { + pub fn new(charger_policy_state: &'a Device, controller: C) -> Self { Self { charger_policy_state, controller: Mutex::new(controller), } } - pub async fn get_state(&self) -> charger::InternalState { + pub async fn get_state(&self) -> InternalState { self.charger_policy_state.state().await } - pub async fn set_state(&self, new_state: charger::InternalState) { + pub async fn set_state(&self, new_state: InternalState) { self.charger_policy_state.set_state(new_state).await } @@ -50,8 +282,8 @@ where ChargerEvent::Initialized(psu_state) => { self.set_state(InternalState { state: match psu_state { - charger::PsuState::Attached => State::Powered(PoweredSubstate::PsuAttached), - charger::PsuState::Detached => State::Powered(PoweredSubstate::PsuDetached), + PsuState::Attached => State::Powered(PoweredSubstate::PsuAttached), + PsuState::Detached => State::Powered(PoweredSubstate::PsuDetached), }, capability: state.capability, }) @@ -61,7 +293,7 @@ where _ => (), }, PoweredSubstate::PsuAttached => match event { - ChargerEvent::PsuStateChange(charger::PsuState::Detached) => { + ChargerEvent::PsuStateChange(PsuState::Detached) => { self.set_state(InternalState { state: State::Powered(PoweredSubstate::PsuDetached), capability: state.capability, @@ -78,7 +310,7 @@ where _ => (), }, PoweredSubstate::PsuDetached => match event { - ChargerEvent::PsuStateChange(charger::PsuState::Attached) => { + ChargerEvent::PsuStateChange(PsuState::Attached) => { self.set_state(InternalState { state: State::Powered(PoweredSubstate::PsuAttached), capability: state.capability, @@ -108,7 +340,7 @@ where PolicyEvent::InitRequest => { if state.state == State::Unpowered { error!("Charger received request to initialize but it's unpowered!"); - Err(charger::ChargerError::InvalidState(State::Unpowered)) + Err(ChargerError::InvalidState(State::Unpowered)) } else { if state.state == State::Powered(PoweredSubstate::Init) { info!("Charger received request to initialize."); @@ -120,7 +352,7 @@ where error!("Charger failed initialzation sequence."); Err(err.into()) } else { - Ok(charger::ChargerResponseData::Ack) + Ok(ChargerResponseData::Ack) } } } @@ -131,14 +363,12 @@ where // from completing it's connect_consumer() call, as there might be cases where we don't want // chargers to be powered or the charger can't be powered. error!("Charger detected new power policy configuration but it's unpowered!"); - Ok(charger::ChargerResponseData::UnpoweredAck) + Ok(ChargerResponseData::UnpoweredAck) } State::Powered(substate) => match substate { PoweredSubstate::Init => { error!("Charger detected new power policy configuration but charger is still initializing."); - Err(charger::ChargerError::InvalidState(State::Powered( - PoweredSubstate::Init, - ))) + Err(ChargerError::InvalidState(State::Powered(PoweredSubstate::Init))) } PoweredSubstate::PsuAttached | PoweredSubstate::PsuDetached => { if power_capability.capability.current_ma == 0 { @@ -160,7 +390,7 @@ where capability: None, }) .await; - Ok(charger::ChargerResponseData::Ack) + Ok(ChargerResponseData::Ack) } } else { // Policy detected an attach @@ -181,7 +411,7 @@ where capability: Some(power_capability.capability), }) .await; - Ok(charger::ChargerResponseData::Ack) + Ok(ChargerResponseData::Ack) } } } @@ -201,7 +431,7 @@ where .await; Err(e.into()) } else { - Ok(charger::ChargerResponseData::Ack) + Ok(ChargerResponseData::Ack) } } State::Unpowered => { @@ -213,7 +443,7 @@ where capability: None, }) .await; - Ok(charger::ChargerResponseData::Ack) + Ok(ChargerResponseData::Ack) } } } diff --git a/power-policy-interface/src/lib.rs b/power-policy-interface/src/lib.rs new file mode 100644 index 00000000..41be3824 --- /dev/null +++ b/power-policy-interface/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +pub mod capability; +pub mod charger; +pub mod psu; +pub mod service; diff --git a/power-policy-interface/src/psu/event.rs b/power-policy-interface/src/psu/event.rs new file mode 100644 index 00000000..9ac19ede --- /dev/null +++ b/power-policy-interface/src/psu/event.rs @@ -0,0 +1,55 @@ +//! Messages originating from a PSU +use crate::capability::{ConsumerPowerCapability, ProviderPowerCapability}; + +/// Data for a power policy request +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RequestData { + /// Notify that a device has attached + Attached, + /// Notify that available power for consumption has changed + UpdatedConsumerCapability(Option), + /// Request the given amount of power to provider + RequestedProviderCapability(Option), + /// Notify that a device cannot consume or provide power anymore + Disconnected, + /// Notify that a device has detached + Detached, +} + +/// Request to the power policy service +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Request { + /// Device that sent this request + pub id: super::DeviceId, + /// Request data + pub data: RequestData, +} + +/// Data for a power policy response +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ResponseData { + /// The request was completed successfully + Complete, +} + +impl ResponseData { + /// Returns an InvalidResponse error if the response is not complete + pub fn complete_or_err(self) -> Result<(), super::Error> { + match self { + ResponseData::Complete => Ok(()), + } + } +} + +/// Response from the power policy service +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Response { + /// Target device + pub id: super::DeviceId, + /// Response data + pub data: ResponseData, +} diff --git a/embedded-service/src/power/policy/device.rs b/power-policy-interface/src/psu/mod.rs similarity index 83% rename from embedded-service/src/power/policy/device.rs rename to power-policy-interface/src/psu/mod.rs index b93d5a39..8f045559 100644 --- a/embedded-service/src/power/policy/device.rs +++ b/power-policy-interface/src/psu/mod.rs @@ -1,12 +1,43 @@ //! Device struct and methods use embassy_sync::mutex::Mutex; -use super::{DeviceId, Error}; -use crate::event::Receiver; -use crate::power::policy::policy::RequestData; -use crate::power::policy::{ConsumerPowerCapability, ProviderPowerCapability}; -use crate::sync::Lockable; -use crate::{GlobalRawMutex, intrusive_list}; +use crate::capability::{ConsumerPowerCapability, PowerCapability, ProviderPowerCapability}; +use embedded_services::event::Receiver; +use embedded_services::sync::Lockable; +use embedded_services::{GlobalRawMutex, intrusive_list}; + +pub mod event; + +/// Error type +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// The requested device does not exist + InvalidDevice, + /// The provide request was denied, contains maximum available power + CannotProvide(Option), + /// The consume request was denied, contains maximum available power + CannotConsume(Option), + /// The device is not in the correct state (expected, actual) + InvalidState(&'static [StateKind], StateKind), + /// Invalid response + InvalidResponse, + /// Busy, the device cannot respond to the request at this time + Busy, + /// Timeout + Timeout, + /// Bus error + Bus, + /// Charger specific error, underlying error should have more context + Charger(crate::charger::ChargerError), + /// Generic failure + Failed, +} + +/// Device ID new type +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DeviceId(pub u8); /// Most basic device states #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -254,7 +285,7 @@ pub struct Response { } /// Trait for PSU devices -pub trait DeviceTrait { +pub trait Psu { /// Disconnect power from this device fn disconnect(&mut self) -> impl Future>; /// Connect this device to provide power to an external connection @@ -264,9 +295,9 @@ pub trait DeviceTrait { } /// PSU registration struct -pub struct Device<'a, D: Lockable, R: Receiver> +pub struct RegistrationEntry<'a, D: Lockable, R: Receiver> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Intrusive list node node: intrusive_list::Node, @@ -280,9 +311,9 @@ where pub receiver: Mutex, } -impl<'a, D: Lockable, R: Receiver> Device<'a, D, R> +impl<'a, D: Lockable, R: Receiver> RegistrationEntry<'a, D, R> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Create a new device pub fn new(id: DeviceId, device: &'a D, receiver: R) -> Self { @@ -333,29 +364,30 @@ where } } -impl + 'static> intrusive_list::NodeContainer for Device<'static, D, R> +impl + 'static> intrusive_list::NodeContainer + for RegistrationEntry<'static, D, R> where - D::Inner: DeviceTrait, + D::Inner: Psu, { - fn get_node(&self) -> &crate::Node { + fn get_node(&self) -> &intrusive_list::Node { &self.node } } /// Trait for any container that holds a device -pub trait DeviceContainer> +pub trait PsuContainer> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Get the underlying device struct - fn get_power_policy_device(&self) -> &Device<'_, D, R>; + fn get_power_policy_device(&self) -> &RegistrationEntry<'_, D, R>; } -impl> DeviceContainer for Device<'_, D, R> +impl> PsuContainer for RegistrationEntry<'_, D, R> where - D::Inner: DeviceTrait, + D::Inner: Psu, { - fn get_power_policy_device(&self) -> &Device<'_, D, R> { + fn get_power_policy_device(&self) -> &RegistrationEntry<'_, D, R> { self } } diff --git a/power-policy-interface/src/service/event.rs b/power-policy-interface/src/service/event.rs new file mode 100644 index 00000000..ca09844d --- /dev/null +++ b/power-policy-interface/src/service/event.rs @@ -0,0 +1,29 @@ +use crate::{ + capability::{ConsumerPowerCapability, ProviderPowerCapability}, + psu::DeviceId, + service::UnconstrainedState, +}; + +/// Data to send with the comms service +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CommsData { + /// Consumer disconnected + ConsumerDisconnected(DeviceId), + /// Consumer connected + ConsumerConnected(DeviceId, ConsumerPowerCapability), + /// Provider disconnected + ProviderDisconnected(DeviceId), + /// Provider connected + ProviderConnected(DeviceId, ProviderPowerCapability), + /// Unconstrained state changed + Unconstrained(UnconstrainedState), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Message to send with the comms service +pub struct CommsMessage { + /// Message data + pub data: CommsData, +} diff --git a/power-policy-interface/src/service/mod.rs b/power-policy-interface/src/service/mod.rs new file mode 100644 index 00000000..a87dfe0b --- /dev/null +++ b/power-policy-interface/src/service/mod.rs @@ -0,0 +1,21 @@ +pub mod event; + +/// Unconstrained state information +#[derive(Debug, Clone, Default, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct UnconstrainedState { + /// Unconstrained state + pub unconstrained: bool, + /// Available unconstrained devices + pub available: usize, +} + +impl UnconstrainedState { + /// Create a new unconstrained state + pub fn new(unconstrained: bool, available: usize) -> Self { + Self { + unconstrained, + available, + } + } +} diff --git a/power-policy-service/Cargo.toml b/power-policy-service/Cargo.toml index 9be53aed..404b150f 100644 --- a/power-policy-service/Cargo.toml +++ b/power-policy-service/Cargo.toml @@ -16,8 +16,12 @@ embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true embedded-services.workspace = true +embedded-batteries-async.workspace = true +num_enum.workspace = true +bitfield.workspace = true log = { workspace = true, optional = true } heapless.workspace = true +power-policy-interface.workspace = true [dev-dependencies] static_cell.workspace = true @@ -32,12 +36,14 @@ default = [] defmt = [ "dep:defmt", "embedded-services/defmt", + "power-policy-interface/defmt", "embassy-time/defmt", "embassy-sync/defmt", ] log = [ "dep:log", "embedded-services/log", + "power-policy-interface/log", "embassy-time/log", "embassy-sync/log", ] diff --git a/power-policy-service/src/lib.rs b/power-policy-service/src/lib.rs index f583f8af..de4e4958 100644 --- a/power-policy-service/src/lib.rs +++ b/power-policy-service/src/lib.rs @@ -1,216 +1,2 @@ #![no_std] -use core::ops::DerefMut; -use embassy_sync::mutex::Mutex; -use embedded_services::GlobalRawMutex; -use embedded_services::event::Receiver; -use embedded_services::power::policy::device::{Device, DeviceTrait, State}; -use embedded_services::power::policy::policy::RequestData; -use embedded_services::power::policy::{policy, *}; -use embedded_services::sync::Lockable; -use embedded_services::{comms, error, info}; - -pub mod config; -pub mod consumer; -pub mod provider; -pub mod task; - -pub use config::Config; -pub mod charger; - -const MAX_CONNECTED_PROVIDERS: usize = 4; - -#[derive(Clone, Default)] -struct InternalState { - /// Current consumer state, if any - current_consumer_state: Option, - /// Current provider global state - current_provider_state: provider::State, - /// System unconstrained power - unconstrained: UnconstrainedState, - /// Connected providers - connected_providers: heapless::FnvIndexSet, -} - -/// Power policy state -pub struct PowerPolicy<'a, D: Lockable, R: Receiver> -where - D::Inner: DeviceTrait, -{ - /// Power policy context - pub context: &'a policy::Context, - /// State - state: Mutex, - /// Comms endpoint - tp: comms::Endpoint, - /// Config - config: config::Config, -} - -impl<'a, D: Lockable + 'static, R: Receiver + 'static> PowerPolicy<'a, D, R> -where - D::Inner: DeviceTrait, -{ - /// Create a new power policy - pub fn new(context: &'a policy::Context, config: config::Config) -> Self { - Self { - context, - state: Mutex::new(InternalState::default()), - tp: comms::Endpoint::uninit(comms::EndpointID::Internal(comms::Internal::Power)), - config, - } - } - - async fn process_notify_attach(&self, device: &Device<'_, D, R>) { - if let Err(e) = device.state.lock().await.attach() { - error!("Device{}: Invalid state for attach: {:#?}", device.id().0, e); - } - } - - async fn process_notify_detach(&self, device: &Device<'_, D, R>) -> Result<(), Error> { - device.state.lock().await.detach(); - self.update_current_consumer().await - } - - async fn process_notify_consumer_power_capability( - &self, - device: &Device<'_, D, R>, - capability: Option, - ) -> Result<(), Error> { - if let Err(e) = device.state.lock().await.update_consumer_power_capability(capability) { - error!( - "Device{}: Invalid state for notify consumer capability, catching up: {:#?}", - device.id().0, - e, - ); - } - - self.update_current_consumer().await - } - - async fn process_request_provider_power_capabilities( - &self, - device: &Device<'_, D, R>, - capability: Option, - ) -> Result<(), Error> { - if let Err(e) = device - .state - .lock() - .await - .update_requested_provider_power_capability(capability) - { - error!( - "Device{}: Invalid state for notify consumer capability, catching up: {:#?}", - device.id().0, - e, - ); - } - - self.connect_provider(device.id()).await - } - - async fn process_notify_disconnect(&self, device: &Device<'_, D, R>) -> Result<(), Error> { - if let Err(e) = device.state.lock().await.disconnect(true) { - error!( - "Device{}: Invalid state for notify disconnect, catching up: {:#?}", - device.id().0, - e, - ); - } - - if self - .state - .lock() - .await - .current_consumer_state - .is_some_and(|current| current.device_id == device.id()) - { - info!("Device{}: Connected consumer disconnected", device.id().0); - self.disconnect_chargers().await?; - - self.comms_notify(CommsMessage { - data: CommsData::ConsumerDisconnected(device.id()), - }) - .await; - } - - self.remove_connected_provider(device.id()).await; - self.update_current_consumer().await?; - Ok(()) - } - - /// Send a notification with the comms service - async fn comms_notify(&self, message: CommsMessage) { - self.context.broadcast_message(message).await; - let _ = self - .tp - .send(comms::EndpointID::Internal(comms::Internal::Battery), &message) - .await; - } - - /// Common logic for when a provider is disconnected - /// - /// Returns true if the device was operating as a provider - async fn remove_connected_provider(&self, device_id: DeviceId) -> bool { - if self.state.lock().await.connected_providers.remove(&device_id) { - self.comms_notify(CommsMessage { - data: CommsData::ProviderDisconnected(device_id), - }) - .await; - true - } else { - false - } - } - - async fn wait_request(&self) -> policy::Request { - self.context.wait_request().await - } - - async fn process_request(&self, request: policy::Request) -> Result<(), Error> { - let device = self.context.get_device(request.id)?; - - match request.data { - policy::RequestData::Attached => { - info!("Received notify attached from device {}", device.id().0); - self.process_notify_attach(device).await; - Ok(()) - } - policy::RequestData::Detached => { - info!("Received notify detached from device {}", device.id().0); - self.process_notify_detach(device).await - } - policy::RequestData::UpdatedConsumerCapability(capability) => { - info!( - "Device{}: Received notify consumer capability: {:#?}", - device.id().0, - capability, - ); - self.process_notify_consumer_power_capability(device, capability).await - } - policy::RequestData::RequestedProviderCapability(capability) => { - info!( - "Device{}: Received request provider capability: {:#?}", - device.id().0, - capability, - ); - self.process_request_provider_power_capabilities(device, capability) - .await - } - policy::RequestData::Disconnected => { - info!("Received notify disconnect from device {}", device.id().0); - self.process_notify_disconnect(device).await - } - } - } - - /// Top-level event loop function - pub async fn process(&self) -> Result<(), Error> { - let request = self.wait_request().await; - self.process_request(request).await - } -} - -impl + 'static> comms::MailboxDelegate for PowerPolicy<'_, D, R> where - D::Inner: DeviceTrait -{ -} +pub mod service; diff --git a/power-policy-service/src/config.rs b/power-policy-service/src/service/config.rs similarity index 95% rename from power-policy-service/src/config.rs rename to power-policy-service/src/service/config.rs index 4ee3fce9..854739e6 100644 --- a/power-policy-service/src/config.rs +++ b/power-policy-service/src/service/config.rs @@ -1,6 +1,6 @@ //! Configuration types for the power policy service -use embedded_services::power::policy::PowerCapability; +use power_policy_interface::capability::PowerCapability; #[derive(Clone, Copy)] pub struct Config { diff --git a/power-policy-service/src/consumer.rs b/power-policy-service/src/service/consumer.rs similarity index 91% rename from power-policy-service/src/consumer.rs rename to power-policy-service/src/service/consumer.rs index 58dd8a20..9210011d 100644 --- a/power-policy-service/src/consumer.rs +++ b/power-policy-service/src/service/consumer.rs @@ -1,10 +1,13 @@ use core::cmp::Ordering; -use embedded_services::debug; -use embedded_services::power::policy::charger::Device as ChargerDevice; -use embedded_services::power::policy::charger::PolicyEvent; +use core::ops::DerefMut; +use embedded_services::{debug, error}; use super::*; +use power_policy_interface::capability::ConsumerFlags; +use power_policy_interface::charger::Device as ChargerDevice; +use power_policy_interface::{capability::ConsumerPowerCapability, charger::PolicyEvent, psu::State}; + /// State of the current consumer #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -29,17 +32,17 @@ fn cmp_consumer_capability( (a.capability, a_is_current).cmp(&(b.capability, b_is_current)) } -impl + 'static> PowerPolicy<'_, D, R> +impl + 'static> Service<'_, D, R> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Iterate over all devices to determine what is best power port provides the highest power async fn find_best_consumer(&self, state: &InternalState) -> Result, Error> { let mut best_consumer = None; let current_consumer_id = state.current_consumer_state.map(|f| f.device_id); - for node in self.context.devices() { - let device = node.data::>().ok_or(Error::InvalidDevice)?; + for node in self.context.psu_devices() { + let device = node.data::>().ok_or(Error::InvalidDevice)?; let consumer_capability = device.consumer_capability().await; // Don't consider consumers below minimum threshold @@ -92,8 +95,8 @@ where async fn update_unconstrained_state(&self, state: &mut InternalState) -> Result<(), Error> { // Count how many available unconstrained devices we have let mut unconstrained_new = UnconstrainedState::default(); - for node in self.context.devices() { - let device = node.data::>().ok_or(Error::InvalidDevice)?; + for node in self.context.psu_devices() { + let device = node.data::>().ok_or(Error::InvalidDevice)?; if let Some(capability) = device.consumer_capability().await { if capability.flags.unconstrained_power() { unconstrained_new.available += 1; @@ -128,10 +131,10 @@ where embassy_time::Timer::after_millis(800).await; // If no chargers are registered, they won't receive the new power capability. - for node in self.context.chargers() { + for node in self.context.charger_devices() { let device = node.data::().ok_or(Error::InvalidDevice)?; // Chargers should be powered at this point, but in case they are not... - if let embedded_services::power::policy::charger::ChargerResponseData::UnpoweredAck = device + if let power_policy_interface::charger::ChargerResponseData::UnpoweredAck = device .execute_command(PolicyEvent::PolicyConfiguration( connected_consumer.consumer_power_capability, )) @@ -162,15 +165,15 @@ where /// Disconnect all chargers pub(super) async fn disconnect_chargers(&self) -> Result<(), Error> { - for node in self.context.chargers() { + for node in self.context.charger_devices() { let device = node.data::().ok_or(Error::InvalidDevice)?; - if let embedded_services::power::policy::charger::ChargerResponseData::UnpoweredAck = device + if let power_policy_interface::charger::ChargerResponseData::UnpoweredAck = device .execute_command(PolicyEvent::PolicyConfiguration(ConsumerPowerCapability { capability: PowerCapability { voltage_mv: 0, current_ma: 0, }, - flags: flags::Consumer::none(), + flags: ConsumerFlags::none(), })) .await? { @@ -198,7 +201,7 @@ where } state.current_consumer_state = None; - let consumer_device = self.context.get_device(current_consumer.device_id)?; + let consumer_device = self.context.get_psu(current_consumer.device_id)?; let mut locked_state = consumer_device.state.lock().await; let mut locked_device = consumer_device.device.lock().await; @@ -231,7 +234,7 @@ where } info!("Device {}, connecting new consumer", new_consumer.device_id.0); - let device = self.context.get_device(new_consumer.device_id)?; + let device = self.context.get_psu(new_consumer.device_id)?; let mut locked_device = device.device.lock().await; let mut locked_state = device.state.lock().await; diff --git a/embedded-service/src/power/policy/policy.rs b/power-policy-service/src/service/context.rs similarity index 56% rename from embedded-service/src/power/policy/policy.rs rename to power-policy-service/src/service/context.rs index e000630d..4ec21181 100644 --- a/embedded-service/src/power/policy/policy.rs +++ b/power-policy-service/src/service/context.rs @@ -2,79 +2,26 @@ use core::marker::PhantomData; use core::pin::pin; -use crate::broadcaster::immediate as broadcaster; -use crate::event::Receiver; -use crate::power::policy::device::DeviceTrait; -use crate::power::policy::{CommsMessage, ConsumerPowerCapability, ProviderPowerCapability}; -use crate::sync::Lockable; use embassy_futures::select::select_slice; - -use super::charger::ChargerResponse; -use super::device::{self}; -use super::{DeviceId, Error, charger}; -use crate::power::policy::charger::ChargerResponseData::Ack; -use crate::{error, intrusive_list}; - -/// Data for a power policy request -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RequestData { - /// Notify that a device has attached - Attached, - /// Notify that available power for consumption has changed - UpdatedConsumerCapability(Option), - /// Request the given amount of power to provider - RequestedProviderCapability(Option), - /// Notify that a device cannot consume or provide power anymore - Disconnected, - /// Notify that a device has detached - Detached, -} - -/// Request to the power policy service -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Request { - /// Device that sent this request - pub id: DeviceId, - /// Request data - pub data: RequestData, -} - -/// Data for a power policy response -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum ResponseData { - /// The request was completed successfully - Complete, -} - -impl ResponseData { - /// Returns an InvalidResponse error if the response is not complete - pub fn complete_or_err(self) -> Result<(), Error> { - match self { - ResponseData::Complete => Ok(()), - } - } -} - -/// Response from the power policy service -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Response { - /// Target device - pub id: DeviceId, - /// Response data - pub data: ResponseData, -} +use embedded_services::broadcaster::immediate as broadcaster; +use embedded_services::event::Receiver; +use embedded_services::sync::Lockable; +use power_policy_interface::charger; +use power_policy_interface::psu::Psu; +use power_policy_interface::psu::event::Request; + +use embedded_services::{error, intrusive_list}; +use power_policy_interface::charger::ChargerResponse; +use power_policy_interface::psu::{self, DeviceId, Error, event::RequestData}; +use power_policy_interface::service::event::CommsMessage; /// Power policy context pub struct Context> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Registered devices - power_devices: intrusive_list::IntrusiveList, + psu_devices: intrusive_list::IntrusiveList, /// Registered chargers charger_devices: intrusive_list::IntrusiveList, /// Message broadcaster @@ -84,7 +31,7 @@ where impl + 'static> Default for Context where - D::Inner: DeviceTrait, + D::Inner: Psu, { fn default() -> Self { Self::new() @@ -93,12 +40,12 @@ where impl + 'static> Context where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Construct a new power policy Context pub const fn new() -> Self { Self { - power_devices: intrusive_list::IntrusiveList::new(), + psu_devices: intrusive_list::IntrusiveList::new(), charger_devices: intrusive_list::IntrusiveList::new(), broadcaster: broadcaster::Immediate::new(), _phantom: PhantomData, @@ -106,34 +53,31 @@ where } /// Register a power device with the service - pub fn register_device( - &self, - device: &'static impl device::DeviceContainer, - ) -> Result<(), intrusive_list::Error> { - let device = device.get_power_policy_device(); - if self.get_device(device.id()).is_ok() { + pub fn register_psu(&self, psu: &'static impl psu::PsuContainer) -> Result<(), intrusive_list::Error> { + let psu = psu.get_power_policy_device(); + if self.get_psu(psu.id()).is_ok() { return Err(intrusive_list::Error::NodeAlreadyInList); } - self.power_devices.push(device) + self.psu_devices.push(psu) } /// Register a charger with the power policy service pub fn register_charger( &self, - device: &'static impl charger::ChargerContainer, + charger: &'static impl charger::ChargerContainer, ) -> Result<(), intrusive_list::Error> { - let device = device.get_charger(); - if self.get_charger(device.id()).is_ok() { + let charger = charger.get_charger(); + if self.get_charger(charger.id()).is_ok() { return Err(intrusive_list::Error::NodeAlreadyInList); } - self.charger_devices.push(device) + self.charger_devices.push(charger) } - /// Get a device by its ID - pub fn get_device(&self, id: DeviceId) -> Result<&'static device::Device<'static, D, R>, Error> { - for device in &self.power_devices { - if let Some(data) = device.data::>() { + /// Get a PSU by its ID + pub fn get_psu(&self, id: DeviceId) -> Result<&'static psu::RegistrationEntry<'static, D, R>, Error> { + for psu in &self.psu_devices { + if let Some(data) = psu.data::>() { if data.id() == id { return Ok(data); } @@ -148,9 +92,9 @@ where /// Returns the total amount of power that is being supplied to external devices pub async fn compute_total_provider_power_mw(&self) -> u32 { let mut total = 0; - for device in self.power_devices.iter_only::>() { - if let Some(capability) = device.provider_capability().await { - if device.is_provider().await { + for psu in self.psu_devices.iter_only::>() { + if let Some(capability) = psu.provider_capability().await { + if psu.is_provider().await { total += capability.capability.max_power_mw(); } } @@ -183,7 +127,7 @@ where } } - Ok(Ack) + Ok(charger::ChargerResponseData::Ack) } /// Check if charger hardware is ready for communications. @@ -195,7 +139,7 @@ where .inspect_err(|e| error!("Charger {:?} failed CheckReady: {:?}", data.id(), e))?; } } - Ok(Ack) + Ok(charger::ChargerResponseData::Ack) } /// Register a message receiver for power policy messages @@ -216,13 +160,13 @@ where Ok(()) } - /// Provides access to the device list - pub fn devices(&self) -> &intrusive_list::IntrusiveList { - &self.power_devices + /// Provides access to the PSU device list + pub fn psu_devices(&self) -> &intrusive_list::IntrusiveList { + &self.psu_devices } /// Provides access to the charger list - pub fn chargers(&self) -> &intrusive_list::IntrusiveList { + pub fn charger_devices(&self) -> &intrusive_list::IntrusiveList { &self.charger_devices } @@ -234,10 +178,10 @@ where /// Get the next pending device event pub async fn wait_request(&self) -> Request { let mut futures = heapless::Vec::<_, 16>::new(); - for device in self.devices().iter_only::>() { + for psu in self.psu_devices().iter_only::>() { // TODO: Validate Vec size at compile time if futures - .push(async { device.receiver.lock().await.wait_next().await }) + .push(async { psu.receiver.lock().await.wait_next().await }) .is_err() { error!("Futures vec overflow"); @@ -247,13 +191,13 @@ where let (event, index) = select_slice(pin!(&mut futures)).await; // Panic safety: The index is guaranteed to be within bounds since it comes from the select_slice result #[allow(clippy::unwrap_used)] - let device = self - .devices() - .iter_only::>() + let psu = self + .psu_devices() + .iter_only::>() .nth(index) .unwrap(); Request { - id: device.id(), + id: psu.id(), data: event, } } diff --git a/power-policy-service/src/service/mod.rs b/power-policy-service/src/service/mod.rs new file mode 100644 index 00000000..4cb96fed --- /dev/null +++ b/power-policy-service/src/service/mod.rs @@ -0,0 +1,220 @@ +//! Power policy related data structures and messages +pub mod config; +pub mod consumer; +pub mod context; +pub mod provider; +pub mod task; + +pub use context::init; +use embassy_sync::mutex::Mutex; +use embedded_services::{GlobalRawMutex, comms, error, event::Receiver, info, sync::Lockable}; + +use power_policy_interface::{ + capability::{ConsumerPowerCapability, PowerCapability, ProviderPowerCapability}, + psu::{ + DeviceId, Error, Psu, RegistrationEntry, + event::{Request, RequestData}, + }, + service::{ + UnconstrainedState, + event::{CommsData, CommsMessage}, + }, +}; + +const MAX_CONNECTED_PROVIDERS: usize = 4; + +#[derive(Clone, Default)] +struct InternalState { + /// Current consumer state, if any + current_consumer_state: Option, + /// Current provider global state + current_provider_state: provider::State, + /// System unconstrained power + unconstrained: UnconstrainedState, + /// Connected providers + connected_providers: heapless::FnvIndexSet, +} + +/// Power policy service +pub struct Service<'a, D: Lockable, R: Receiver> +where + D::Inner: Psu, +{ + /// Power policy context + pub context: &'a context::Context, + /// State + state: Mutex, + /// Comms endpoint + tp: comms::Endpoint, + /// Config + config: config::Config, +} + +impl<'a, D: Lockable + 'static, R: Receiver + 'static> Service<'a, D, R> +where + D::Inner: Psu, +{ + /// Create a new power policy + pub fn new(context: &'a context::Context, config: config::Config) -> Self { + Self { + context, + state: Mutex::new(InternalState::default()), + tp: comms::Endpoint::uninit(comms::EndpointID::Internal(comms::Internal::Power)), + config, + } + } + + async fn process_notify_attach(&self, device: &RegistrationEntry<'_, D, R>) { + if let Err(e) = device.state.lock().await.attach() { + error!("Device{}: Invalid state for attach: {:#?}", device.id().0, e); + } + } + + async fn process_notify_detach(&self, device: &RegistrationEntry<'_, D, R>) -> Result<(), Error> { + device.state.lock().await.detach(); + self.update_current_consumer().await + } + + async fn process_notify_consumer_power_capability( + &self, + device: &RegistrationEntry<'_, D, R>, + capability: Option, + ) -> Result<(), Error> { + if let Err(e) = device.state.lock().await.update_consumer_power_capability(capability) { + error!( + "Device{}: Invalid state for notify consumer capability, catching up: {:#?}", + device.id().0, + e, + ); + } + + self.update_current_consumer().await + } + + async fn process_request_provider_power_capabilities( + &self, + device: &RegistrationEntry<'_, D, R>, + capability: Option, + ) -> Result<(), Error> { + if let Err(e) = device + .state + .lock() + .await + .update_requested_provider_power_capability(capability) + { + error!( + "Device{}: Invalid state for notify consumer capability, catching up: {:#?}", + device.id().0, + e, + ); + } + + self.connect_provider(device.id()).await + } + + async fn process_notify_disconnect(&self, device: &RegistrationEntry<'_, D, R>) -> Result<(), Error> { + if let Err(e) = device.state.lock().await.disconnect(true) { + error!( + "Device{}: Invalid state for notify disconnect, catching up: {:#?}", + device.id().0, + e, + ); + } + + if self + .state + .lock() + .await + .current_consumer_state + .is_some_and(|current| current.device_id == device.id()) + { + info!("Device{}: Connected consumer disconnected", device.id().0); + self.disconnect_chargers().await?; + + self.comms_notify(CommsMessage { + data: CommsData::ConsumerDisconnected(device.id()), + }) + .await; + } + + self.remove_connected_provider(device.id()).await; + self.update_current_consumer().await?; + Ok(()) + } + + /// Send a notification with the comms service + async fn comms_notify(&self, message: CommsMessage) { + self.context.broadcast_message(message).await; + let _ = self + .tp + .send(comms::EndpointID::Internal(comms::Internal::Battery), &message) + .await; + } + + /// Common logic for when a provider is disconnected + /// + /// Returns true if the device was operating as a provider + async fn remove_connected_provider(&self, device_id: DeviceId) -> bool { + if self.state.lock().await.connected_providers.remove(&device_id) { + self.comms_notify(CommsMessage { + data: CommsData::ProviderDisconnected(device_id), + }) + .await; + true + } else { + false + } + } + + async fn wait_request(&self) -> Request { + self.context.wait_request().await + } + + async fn process_request(&self, request: Request) -> Result<(), Error> { + let device = self.context.get_psu(request.id)?; + + match request.data { + RequestData::Attached => { + info!("Received notify attached from device {}", device.id().0); + self.process_notify_attach(device).await; + Ok(()) + } + RequestData::Detached => { + info!("Received notify detached from device {}", device.id().0); + self.process_notify_detach(device).await + } + RequestData::UpdatedConsumerCapability(capability) => { + info!( + "Device{}: Received notify consumer capability: {:#?}", + device.id().0, + capability, + ); + self.process_notify_consumer_power_capability(device, capability).await + } + RequestData::RequestedProviderCapability(capability) => { + info!( + "Device{}: Received request provider capability: {:#?}", + device.id().0, + capability, + ); + self.process_request_provider_power_capabilities(device, capability) + .await + } + RequestData::Disconnected => { + info!("Received notify disconnect from device {}", device.id().0); + self.process_notify_disconnect(device).await + } + } + } + + /// Top-level event loop function + pub async fn process(&self) -> Result<(), Error> { + let request = self.wait_request().await; + self.process_request(request).await + } +} + +impl + 'static> comms::MailboxDelegate for Service<'_, D, R> where + D::Inner: Psu +{ +} diff --git a/power-policy-service/src/provider.rs b/power-policy-service/src/service/provider.rs similarity index 81% rename from power-policy-service/src/provider.rs rename to power-policy-service/src/service/provider.rs index 7187f011..4179d81b 100644 --- a/power-policy-service/src/provider.rs +++ b/power-policy-service/src/service/provider.rs @@ -1,9 +1,12 @@ //! This file implements logic to determine how much power to provide to each connected device. -//! When total provided power is below [limited_power_threshold_mw](super::Config::limited_power_threshold_mw) -//! the system is in unlimited power state. In this mode up to [provider_unlimited](super::Config::provider_unlimited) +//! When total provided power is below [limited_power_threshold_mw](super::config::Config::limited_power_threshold_mw) +//! the system is in unlimited power state. In this mode up to [provider_unlimited](super::config::Config::provider_unlimited) //! is provided to each device. Above this threshold, the system is in limited power state. -//! In this mode [provider_limited](super::Config::provider_limited) is provided to each device -use embedded_services::{debug, event::Receiver, power::policy::policy::RequestData, trace}; +//! In this mode [provider_limited](super::config::Config::provider_limited) is provided to each device +use embedded_services::error; +use embedded_services::{debug, event::Receiver, trace}; + +use power_policy_interface::psu; use super::*; @@ -25,14 +28,14 @@ pub(super) struct State { state: PowerState, } -impl + 'static> PowerPolicy<'_, D, R> +impl + 'static> Service<'_, D, R> where - D::Inner: DeviceTrait, + D::Inner: Psu, { /// Attempt to connect the requester as a provider pub(super) async fn connect_provider(&self, requester_id: DeviceId) -> Result<(), Error> { trace!("Device{}: Attempting to connect as provider", requester_id.0); - let requester = self.context.get_device(requester_id)?; + let requester = self.context.get_psu(requester_id)?; let requested_power_capability = match requester.requested_provider_capability().await { Some(cap) => cap, // Requester is no longer requesting power @@ -45,14 +48,18 @@ where let mut total_power_mw = 0; // Determine total requested power draw - for device in self.context.devices().iter_only::>() { - let target_provider_cap = if device.id() == requester_id { + for psu in self + .context + .psu_devices() + .iter_only::>() + { + let target_provider_cap = if psu.id() == requester_id { // Use the requester's requested power capability // this handles both new connections and upgrade requests Some(requested_power_capability) } else { // Use the device's current working provider capability - device.provider_capability().await + psu.provider_capability().await }; total_power_mw += target_provider_cap.map_or(0, |cap| cap.capability.max_power_mw()); } @@ -84,14 +91,14 @@ where } }; - let device = self.context.get_device(requester_id)?; - let mut locked_state = device.state.lock().await; - let mut locked_device = device.device.lock().await; + let psu = self.context.get_psu(requester_id)?; + let mut locked_state = psu.state.lock().await; + let mut locked_device = psu.device.lock().await; if let e @ Err(_) = locked_state.connect_provider(target_power) { error!( "Device{}: Cannot provide, device is in state {:#?}", - device.id().0, + psu.id().0, locked_state.state() ); e diff --git a/power-policy-service/src/task.rs b/power-policy-service/src/service/task.rs similarity index 76% rename from power-policy-service/src/task.rs rename to power-policy-service/src/service/task.rs index 4c9c8f1e..20f7aef9 100644 --- a/power-policy-service/src/task.rs +++ b/power-policy-service/src/service/task.rs @@ -1,12 +1,8 @@ -use embedded_services::{ - comms, error, - event::Receiver, - info, - power::policy::{device::DeviceTrait, policy::RequestData}, - sync::Lockable, -}; +use embedded_services::{comms, error, event::Receiver, info, sync::Lockable}; -use crate::PowerPolicy; +use power_policy_interface::psu::{Psu, event::RequestData}; + +use super::Service; #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -21,10 +17,10 @@ pub enum InitError { /// Runs the power policy task. pub async fn task + 'static>( - policy: &'static PowerPolicy<'static, D, R>, + policy: &'static Service<'static, D, R>, ) -> Result where - D::Inner: DeviceTrait, + D::Inner: Psu, { info!("Starting power policy task"); if comms::register_endpoint(policy, &policy.tp).await.is_err() { diff --git a/power-policy-service/tests/common/mock.rs b/power-policy-service/tests/common/mock.rs index f4e00cb7..0244229c 100644 --- a/power-policy-service/tests/common/mock.rs +++ b/power-policy-service/tests/common/mock.rs @@ -1,10 +1,10 @@ #![allow(clippy::unwrap_used)] use embassy_sync::signal::Signal; -use embedded_services::power::policy::device::{DeviceTrait, InternalState}; -use embedded_services::power::policy::flags::Consumer; -use embedded_services::power::policy::policy::RequestData; -use embedded_services::power::policy::{ConsumerPowerCapability, Error, PowerCapability, ProviderPowerCapability}; use embedded_services::{GlobalRawMutex, event, info}; +use power_policy_interface::{ + capability::{ConsumerFlags, ConsumerPowerCapability, PowerCapability, ProviderPowerCapability}, + psu::{Error, InternalState, Psu, event::RequestData}, +}; #[derive(Debug, Clone, PartialEq, Eq)] #[allow(dead_code)] @@ -47,7 +47,7 @@ impl<'a, S: event::Sender> Mock<'a, S> { let capability = Some(ConsumerPowerCapability { capability, - flags: Consumer::none(), + flags: ConsumerFlags::none(), }); self.state.update_consumer_power_capability(capability).unwrap(); self.sender @@ -61,7 +61,7 @@ impl<'a, S: event::Sender> Mock<'a, S> { } } -impl<'a, S: event::Sender> DeviceTrait for Mock<'a, S> { +impl<'a, S: event::Sender> Psu for Mock<'a, S> { async fn connect_consumer(&mut self, capability: ConsumerPowerCapability) -> Result<(), Error> { info!("Connect consumer {:#?}", capability); self.record_fn_call(FnCall::ConnectConsumer(capability)); diff --git a/power-policy-service/tests/common/mod.rs b/power-policy-service/tests/common/mod.rs index 482ca33a..3707dc19 100644 --- a/power-policy-service/tests/common/mod.rs +++ b/power-policy-service/tests/common/mod.rs @@ -9,11 +9,12 @@ use embassy_sync::{ signal::Signal, }; use embassy_time::{Duration, with_timeout}; -use embedded_services::{ - GlobalRawMutex, - power::policy::{self, DeviceId, PowerCapability, device, policy::RequestData}, -}; -use power_policy_service::PowerPolicy; +use embedded_services::GlobalRawMutex; +use power_policy_interface::capability::PowerCapability; +use power_policy_interface::psu; +use power_policy_interface::psu::DeviceId; +use power_policy_interface::psu::event::RequestData; +use power_policy_service::service::Service; pub mod mock; @@ -39,7 +40,7 @@ const EVENT_CHANNEL_SIZE: usize = 4; async fn power_policy_task( completion_signal: &'static Signal, - power_policy: &'static PowerPolicy< + power_policy: &'static Service< 'static, Mutex>>, DynamicReceiver<'static, RequestData>, @@ -50,19 +51,19 @@ async fn power_policy_task( } } -pub type RegistrationType = device::Device< +pub type RegistrationType = psu::RegistrationEntry< 'static, Mutex>>, DynamicReceiver<'static, RequestData>, >; -pub type ServiceType = PowerPolicy< +pub type ServiceType = Service< 'static, Mutex>>, DynamicReceiver<'static, RequestData>, >; -pub type ServiceContext = policy::policy::Context< +pub type ServiceContext = power_policy_service::service::context::Context< Mutex>>, DynamicReceiver<'static, RequestData>, >; @@ -91,7 +92,8 @@ pub async fn run_test>( let device0 = DEVICE0.init(Mutex::new(Mock::new(device0_sender, device0_signal))); static DEVICE0_REGISTRATION: StaticCell = StaticCell::new(); - let device0_registration = DEVICE0_REGISTRATION.init(device::Device::new(DeviceId(0), device0, device0_receiver)); + let device0_registration = + DEVICE0_REGISTRATION.init(psu::RegistrationEntry::new(DeviceId(0), device0, device0_receiver)); static DEVICE1_EVENT_CHANNEL: StaticCell> = StaticCell::new(); @@ -105,16 +107,17 @@ pub async fn run_test>( let device1 = DEVICE1.init(Mutex::new(Mock::new(device1_sender, device1_signal))); static DEVICE1_REGISTRATION: StaticCell = StaticCell::new(); - let device1_registration = DEVICE1_REGISTRATION.init(device::Device::new(DeviceId(1), device1, device1_receiver)); + let device1_registration = + DEVICE1_REGISTRATION.init(psu::RegistrationEntry::new(DeviceId(1), device1, device1_receiver)); static SERVICE_CONTEXT: StaticCell = StaticCell::new(); - let service_context = SERVICE_CONTEXT.init(policy::policy::Context::new()); + let service_context = SERVICE_CONTEXT.init(power_policy_service::service::context::Context::new()); - service_context.register_device(device0_registration).unwrap(); - service_context.register_device(device1_registration).unwrap(); + service_context.register_psu(device0_registration).unwrap(); + service_context.register_psu(device1_registration).unwrap(); static POWER_POLICY: StaticCell = StaticCell::new(); - let power_policy = POWER_POLICY.init(power_policy_service::PowerPolicy::new( + let power_policy = POWER_POLICY.init(power_policy_service::service::Service::new( service_context, Default::default(), )); diff --git a/power-policy-service/tests/consumer.rs b/power-policy-service/tests/consumer.rs index bf104cbc..91c4950e 100644 --- a/power-policy-service/tests/consumer.rs +++ b/power-policy-service/tests/consumer.rs @@ -1,10 +1,9 @@ #![allow(clippy::unwrap_used)] use embassy_sync::{channel::DynamicSender, mutex::Mutex, signal::Signal}; use embassy_time::{Duration, TimeoutError, with_timeout}; -use embedded_services::{ - GlobalRawMutex, - power::policy::{ConsumerPowerCapability, flags::Consumer, policy::RequestData}, -}; +use embedded_services::GlobalRawMutex; +use power_policy_interface::capability::{ConsumerFlags, ConsumerPowerCapability}; +use power_policy_interface::psu::event::RequestData; mod common; @@ -33,7 +32,7 @@ async fn test_single( 1, FnCall::ConnectConsumer(ConsumerPowerCapability { capability: LOW_POWER, - flags: Consumer::none(), + flags: ConsumerFlags::none(), }) ) ); @@ -69,7 +68,7 @@ async fn test_swap_higher( 1, FnCall::ConnectConsumer(ConsumerPowerCapability { capability: LOW_POWER, - flags: Consumer::none(), + flags: ConsumerFlags::none(), }) ) ); @@ -91,7 +90,7 @@ async fn test_swap_higher( 1, FnCall::ConnectConsumer(ConsumerPowerCapability { capability: HIGH_POWER, - flags: Consumer::none(), + flags: ConsumerFlags::none(), }) ) ); @@ -113,7 +112,7 @@ async fn test_swap_higher( 1, FnCall::ConnectConsumer(ConsumerPowerCapability { capability: LOW_POWER, - flags: Consumer::none(), + flags: ConsumerFlags::none(), }) ) ); diff --git a/time-alarm-service-messages/Cargo.toml b/time-alarm-service-messages/Cargo.toml index 04e172f7..7d883b7a 100644 --- a/time-alarm-service-messages/Cargo.toml +++ b/time-alarm-service-messages/Cargo.toml @@ -13,7 +13,7 @@ log = { workspace = true, optional = true } embedded-mcu-hal.workspace = true embedded-services.workspace = true num_enum.workspace = true -zerocopy.workspace = true +zerocopy = { workspace = true, features = ["derive"] } [features] defmt = ["dep:defmt", "embedded-mcu-hal/defmt"] diff --git a/type-c-service/Cargo.toml b/type-c-service/Cargo.toml index 75f6e1eb..5b3fb5bd 100644 --- a/type-c-service/Cargo.toml +++ b/type-c-service/Cargo.toml @@ -27,6 +27,9 @@ heapless.workspace = true log = { workspace = true, optional = true } tps6699x = { workspace = true, features = ["embassy"] } cfu-service.workspace = true +power-policy-interface.workspace = true +power-policy-service = { path = "../power-policy-service" } +bitvec.workspace = true [dev-dependencies] embassy-time = { workspace = true, features = ["std", "generic-queue-8"] } @@ -47,6 +50,8 @@ defmt = [ "tps6699x/defmt", "embedded-usb-pd/defmt", "cfu-service/defmt", + "power-policy-interface/defmt", + "power-policy-service/defmt", ] log = [ "dep:log", @@ -55,4 +60,6 @@ log = [ "embassy-sync/log", "tps6699x/log", "cfu-service/log", + "power-policy-interface/log", + "power-policy-service/log", ] diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index c6c1f8e1..8470af87 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -1,3 +1,10 @@ +use crate::type_c; +use crate::type_c::ATTN_VDM_LEN; +use crate::type_c::controller::{ + self, AttnVdm, Controller, ControllerStatus, DpPinConfig, OtherVdm, PortStatus, SendVdm, TbtConfig, + TypeCStateMachineState, UsbControlConfig, +}; +use crate::type_c::event::PortEvent; use ::tps6699x::registers::field_sets::IntEventBus1; use ::tps6699x::registers::{PdCcPullUp, PpExtVbusSw, PpIntVbusSw}; use ::tps6699x::{PORT0, PORT1, TPS66993_NUM_PORTS, TPS66994_NUM_PORTS}; @@ -9,14 +16,7 @@ use core::iter::zip; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_time::Delay; use embedded_hal_async::i2c::I2c; -use embedded_services::power::policy::PowerCapability; -use embedded_services::type_c::ATTN_VDM_LEN; -use embedded_services::type_c::controller::{ - self, AttnVdm, Controller, ControllerStatus, DpPinConfig, OtherVdm, PortStatus, SendVdm, TbtConfig, - TypeCStateMachineState, UsbControlConfig, -}; -use embedded_services::type_c::event::PortEvent; -use embedded_services::{debug, error, trace, type_c, warn}; +use embedded_services::{debug, error, trace, warn}; use embedded_usb_pd::ado::Ado; use embedded_usb_pd::pdinfo::PowerPathStatus; use embedded_usb_pd::pdo::{Common, Contract, Rdo, sink, source}; @@ -36,6 +36,9 @@ use tps6699x::command::{ use tps6699x::fw_update::UpdateConfig as FwUpdateConfig; use tps6699x::registers::port_config::TypeCStateMachine; +use crate::type_c::power_capability_from_current; +use crate::type_c::power_capability_try_from_contract; + type Updater<'a, M, B> = BorrowedUpdaterInProgress>; /// Firmware update state @@ -275,9 +278,8 @@ impl Controller for Tps6699x<'_, M, B> { /// /// Drop safety: All state changes happen after await point async fn clear_port_events(&mut self, port: LocalPortId) -> Result> { - Ok(core::mem::replace( + Ok(core::mem::take( self.port_events.get_mut(port.0 as usize).ok_or(PdError::InvalidPort)?, - PortEvent::none(), )) } @@ -314,7 +316,8 @@ impl Controller for Tps6699x<'_, M, B> { let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); - port_status.available_source_contract = Contract::from_source(pdo, rdo).try_into().ok(); + port_status.available_source_contract = + power_capability_try_from_contract(Contract::from_source(pdo, rdo)); port_status.dual_power = pdo.dual_role_power(); } else { // active_rdo_contract doesn't contain the full picture @@ -337,7 +340,8 @@ impl Controller for Tps6699x<'_, M, B> { let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); - port_status.available_sink_contract = Contract::from_sink(pdo, rdo).try_into().ok(); + port_status.available_sink_contract = + power_capability_try_from_contract(Contract::from_sink(pdo, rdo)); port_status.dual_power = source_pdos[0].dual_role_power(); port_status.unconstrained_power = source_pdos[0].unconstrained_power(); } @@ -345,8 +349,7 @@ impl Controller for Tps6699x<'_, M, B> { // Implicit source contract let current = TypecCurrent::try_from(port_control.typec_current()).map_err(Error::Pd)?; debug!("Port{} type-C source current: {:#?}", port.0, current); - let new_contract = Some(PowerCapability::from(current)); - port_status.available_source_contract = new_contract; + port_status.available_source_contract = Some(power_capability_from_current(current)); } else { // Implicit sink contract let pull = pd_status.cc_pull_up(); @@ -357,7 +360,7 @@ impl Controller for Tps6699x<'_, M, B> { } else { let current = TypecCurrent::try_from(pd_status.cc_pull_up()).map_err(Error::Pd)?; debug!("Port{} type-C sink current: {:#?}", port.0, current); - Some(PowerCapability::from(current)) + Some(power_capability_from_current(current)) }; port_status.available_sink_contract = new_contract; } diff --git a/type-c-service/src/lib.rs b/type-c-service/src/lib.rs index b1d0a5f1..c2bb5340 100644 --- a/type-c-service/src/lib.rs +++ b/type-c-service/src/lib.rs @@ -2,13 +2,12 @@ pub mod driver; pub mod service; pub mod task; +pub mod type_c; pub mod wrapper; use core::future::Future; -use embedded_services::type_c::event::{ - PortEvent, PortNotification, PortNotificationSingle, PortPendingIter, PortStatusChanged, -}; +use type_c::event::{PortEvent, PortNotification, PortNotificationSingle, PortPendingIter, PortStatusChanged}; /// Enum to contain all port event variants #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -123,7 +122,7 @@ impl PortEventStreamer { mod tests { use core::sync::atomic::AtomicBool; - use embedded_services::type_c::event::PortPending; + use crate::type_c::event::PortPending; use super::*; diff --git a/type-c-service/src/service/controller.rs b/type-c-service/src/service/controller.rs index f4034e7c..408fc2ef 100644 --- a/type-c-service/src/service/controller.rs +++ b/type-c-service/src/service/controller.rs @@ -1,12 +1,10 @@ -use embedded_services::{ - debug, error, - type_c::{ - ControllerId, - external::{self, ControllerCommandData}, - }, -}; +use embedded_services::{debug, error}; use super::*; +use crate::type_c::{ + ControllerId, + external::{self, ControllerCommandData}, +}; impl<'a> Service<'a> { /// Process external controller status command diff --git a/type-c-service/src/service/mod.rs b/type-c-service/src/service/mod.rs index 90163392..449e695c 100644 --- a/type-c-service/src/service/mod.rs +++ b/type-c-service/src/service/mod.rs @@ -4,24 +4,18 @@ use embassy_sync::{ pubsub::{DynImmediatePublisher, DynSubscriber}, }; use embedded_services::{ - GlobalRawMutex, debug, error, - event::Receiver, - info, intrusive_list, - ipc::deferred, - power::policy::policy, - sync::Lockable, - trace, - type_c::{ - self, comms, - controller::PortStatus, - event::{PortNotificationSingle, PortStatusChanged}, - external, - }, + GlobalRawMutex, debug, error, event::Receiver, info, intrusive_list, ipc::deferred, sync::Lockable, trace, }; -use embedded_services::{power::policy as power_policy, type_c::Cached}; use embedded_usb_pd::GlobalPortId; use embedded_usb_pd::PdError as Error; +use crate::type_c::{ + self, Cached, comms, + controller::PortStatus, + event::{PortNotificationSingle, PortStatusChanged}, + external, +}; + use crate::{PortEventStreamer, PortEventVariant}; pub mod config; @@ -62,12 +56,14 @@ pub struct Service<'a> { /// /// This is the corresponding publisher to [`Self::power_policy_event_subscriber`], power policy events /// will be buffered in the channel until they are brought into the event loop with the subscriber. - power_policy_event_publisher: embedded_services::broadcaster::immediate::Receiver<'a, power_policy::CommsMessage>, + power_policy_event_publisher: + embedded_services::broadcaster::immediate::Receiver<'a, power_policy_interface::service::event::CommsMessage>, /// Power policy event subscriber /// /// This is the corresponding subscriber to [`Self::power_policy_event_publisher`], needs to be a mutex because getting a message /// from the channel requires mutable access. - power_policy_event_subscriber: Mutex>, + power_policy_event_subscriber: + Mutex>, } /// Power policy events @@ -76,7 +72,7 @@ pub struct Service<'a> { // But there's currently not a way to do look-ups between power policy device IDs and GlobalPortIds pub enum PowerPolicyEvent { /// Unconstrained state changed - Unconstrained(power_policy::UnconstrainedState), + Unconstrained(power_policy_interface::service::UnconstrainedState), /// Consumer disconnected ConsumerDisconnected, /// Consumer connected @@ -99,10 +95,10 @@ impl<'a> Service<'a> { /// Create a new service the given configuration pub fn create( config: config::Config, - context: &'a embedded_services::type_c::controller::Context, + context: &'a crate::type_c::controller::Context, controller_list: &'a intrusive_list::IntrusiveList, - power_policy_publisher: DynImmediatePublisher<'a, power_policy::CommsMessage>, - power_policy_subscriber: DynSubscriber<'a, power_policy::CommsMessage>, + power_policy_publisher: DynImmediatePublisher<'a, power_policy_interface::service::event::CommsMessage>, + power_policy_subscriber: DynSubscriber<'a, power_policy_interface::service::event::CommsMessage>, ) -> Self { Self { context, @@ -256,12 +252,15 @@ impl<'a> Service<'a> { } /// Register the Type-C service with the power policy service - pub fn register_comms + 'static>( + pub fn register_comms< + PD: Lockable + 'static, + PR: Receiver + 'static, + >( &'static self, - power_policy_context: &power_policy::policy::Context, + power_policy_context: &power_policy_service::service::context::Context, ) -> Result<(), intrusive_list::Error> where - PD::Inner: embedded_services::power::policy::device::DeviceTrait, + PD::Inner: power_policy_interface::psu::Psu, { power_policy_context.register_message_receiver(&self.power_policy_event_publisher) } diff --git a/type-c-service/src/service/port.rs b/type-c-service/src/service/port.rs index 80517dc8..b138e82b 100644 --- a/type-c-service/src/service/port.rs +++ b/type-c-service/src/service/port.rs @@ -1,16 +1,14 @@ -use embedded_services::{ - debug, error, - type_c::{ - controller::{DpConfig, PdStateMachineConfig, TbtConfig, TypeCStateMachineState, UsbControlConfig}, - external, - }, -}; +use embedded_services::{debug, error}; use embedded_usb_pd::GlobalPortId; use super::*; use crate::PortEventStreamer; -use embedded_services::type_c::controller::SendVdm; +use crate::type_c::controller::SendVdm; +use crate::type_c::{ + controller::{DpConfig, PdStateMachineConfig, TbtConfig, TypeCStateMachineState, UsbControlConfig}, + external, +}; impl<'a> Service<'a> { /// Wait for port flags diff --git a/type-c-service/src/service/power.rs b/type-c-service/src/service/power.rs index 64c77a8c..72e7a6c0 100644 --- a/type-c-service/src/service/power.rs +++ b/type-c-service/src/service/power.rs @@ -1,5 +1,5 @@ use embassy_sync::pubsub::WaitResult; -use embedded_services::power::policy as power_policy; +use power_policy_interface::service as power_policy; use super::*; @@ -13,13 +13,13 @@ impl<'a> Service<'a> { error!("Power policy {} event(s) lagged", lagged); } WaitResult::Message(message) => match message.data { - power_policy::CommsData::Unconstrained(state) => { + power_policy_interface::service::event::CommsData::Unconstrained(state) => { return Event::PowerPolicy(PowerPolicyEvent::Unconstrained(state)); } - power_policy::CommsData::ConsumerDisconnected(_) => { + power_policy_interface::service::event::CommsData::ConsumerDisconnected(_) => { return Event::PowerPolicy(PowerPolicyEvent::ConsumerDisconnected); } - power_policy::CommsData::ConsumerConnected(_, _) => { + power_policy_interface::service::event::CommsData::ConsumerConnected(_, _) => { return Event::PowerPolicy(PowerPolicyEvent::ConsumerConnected); } _ => { diff --git a/type-c-service/src/service/vdm.rs b/type-c-service/src/service/vdm.rs index 43e97e5e..adc46f4e 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 crate::type_c::controller::{AttnVdm, OtherVdm}; use embedded_services::intrusive_list; -use embedded_services::type_c::controller::{AttnVdm, OtherVdm}; use embedded_usb_pd::{GlobalPortId, PdError}; use super::Service; diff --git a/type-c-service/src/task.rs b/type-c-service/src/task.rs index 8f47d0eb..aea7981f 100644 --- a/type-c-service/src/task.rs +++ b/type-c-service/src/task.rs @@ -1,6 +1,8 @@ use core::future::Future; use embassy_sync::mutex::Mutex; -use embedded_services::{error, event, info, power::policy::policy, sync::Lockable}; +use embedded_services::{error, event, info, sync::Lockable}; + +use power_policy_service::service::context::Context as PowerPolicyContext; use crate::{ service::Service, @@ -11,16 +13,16 @@ use crate::{ pub async fn task_closure<'a, M, D, S, R, V, Fut: Future, F: Fn(&'a Service) -> Fut, const N: usize>( service: &'static Service<'a>, wrappers: [&'a ControllerWrapper<'a, M, D, S, R, V>; N], - power_policy_context: &policy::Context>, R>, + power_policy_context: &PowerPolicyContext>, R>, cfu_client: &'a cfu_service::CfuClient, f: F, ) where M: embassy_sync::blocking_mutex::raw::RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: crate::wrapper::FwOfferValidator, - D::Inner: embedded_services::type_c::controller::Controller, + D::Inner: crate::type_c::controller::Controller, { info!("Starting type-c task"); @@ -48,15 +50,15 @@ pub async fn task_closure<'a, M, D, S, R, V, Fut: Future, F: Fn(&'a pub async fn task<'a, M, D, S, R, V, const N: usize>( service: &'static Service<'a>, wrappers: [&'a ControllerWrapper<'a, M, D, S, R, V>; N], - power_policy_context: &policy::Context>, R>, + power_policy_context: &PowerPolicyContext>, R>, cfu_client: &'a cfu_service::CfuClient, ) where M: embassy_sync::blocking_mutex::raw::RawMutex, D: embedded_services::sync::Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: crate::wrapper::FwOfferValidator, - ::Inner: embedded_services::type_c::controller::Controller, + ::Inner: crate::type_c::controller::Controller, { task_closure( service, diff --git a/embedded-service/src/type_c/comms.rs b/type-c-service/src/type_c/comms.rs similarity index 100% rename from embedded-service/src/type_c/comms.rs rename to type-c-service/src/type_c/comms.rs diff --git a/embedded-service/src/type_c/controller.rs b/type-c-service/src/type_c/controller.rs similarity index 99% rename from embedded-service/src/type_c/controller.rs rename to type-c-service/src/type_c/controller.rs index 380987d0..6f20fd8f 100644 --- a/embedded-service/src/type_c/controller.rs +++ b/type-c-service/src/type_c/controller.rs @@ -12,12 +12,13 @@ use embedded_usb_pd::{ }; use super::{ATTN_VDM_LEN, ControllerId, OTHER_VDM_LEN, external}; -use crate::ipc::deferred; -use crate::power::policy; use crate::type_c::Cached; use crate::type_c::comms::CommsMessage; use crate::type_c::event::{PortEvent, PortPending}; -use crate::{GlobalRawMutex, IntrusiveNode, broadcaster::immediate as broadcaster, error, intrusive_list, trace}; +use embedded_services::ipc::deferred; +use embedded_services::{ + GlobalRawMutex, IntrusiveNode, broadcaster::immediate as broadcaster, error, intrusive_list, trace, +}; /// maximum number of data objects in a VDM pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each @@ -27,9 +28,9 @@ pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PortStatus { /// Current available source contract - pub available_source_contract: Option, + pub available_source_contract: Option, /// Current available sink contract - pub available_sink_contract: Option, + pub available_sink_contract: Option, /// Current connection state pub connection_state: Option, /// Port partner supports dual-power roles diff --git a/embedded-service/src/type_c/event.rs b/type-c-service/src/type_c/event.rs similarity index 99% rename from embedded-service/src/type_c/event.rs rename to type-c-service/src/type_c/event.rs index df7dbd4b..eb951079 100644 --- a/embedded-service/src/type_c/event.rs +++ b/type-c-service/src/type_c/event.rs @@ -4,9 +4,9 @@ //! Processing these events typically requires acessing similar registers so they are grouped together. //! [`PortNotification`] contains events that are typically more message-like (PD alerts, VDMs, etc) and can be processed independently. //! Consequently [`PortNotification`] implements iterator traits to allow for processing these events as a stream. -use super::error; use bitfield::bitfield; use bitvec::BitArr; +use embedded_services::error; bitfield! { /// Raw bitfield of possible port status events diff --git a/embedded-service/src/type_c/external.rs b/type-c-service/src/type_c/external.rs similarity index 98% rename from embedded-service/src/type_c/external.rs rename to type-c-service/src/type_c/external.rs index 7216efd2..ef253db2 100644 --- a/embedded-service/src/type_c/external.rs +++ b/type-c-service/src/type_c/external.rs @@ -1,19 +1,18 @@ //! Message definitions for external type-C commands use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError, ucsi}; -use crate::{ - intrusive_list, - type_c::{ - Cached, - controller::{Context, PdStateMachineConfig, TbtConfig, TypeCStateMachineState, UsbControlConfig}, - }, -}; +use embedded_services::intrusive_list; use super::{ ControllerId, controller::{ControllerStatus, DpConfig, DpStatus, PortStatus, RetimerFwUpdateState, SendVdm, lookup_controller}, }; +use crate::type_c::{ + Cached, + controller::{Context, PdStateMachineConfig, TbtConfig, TypeCStateMachineState, UsbControlConfig}, +}; + /// Data for controller-specific commands #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/type-c-service/src/type_c/mod.rs b/type-c-service/src/type_c/mod.rs new file mode 100644 index 00000000..a5100bf1 --- /dev/null +++ b/type-c-service/src/type_c/mod.rs @@ -0,0 +1,68 @@ +//! Type-C service +use embedded_usb_pd::pdo::{Common, Contract}; +use embedded_usb_pd::type_c; + +pub mod comms; +pub mod controller; +pub mod event; +pub mod external; + +/// Controller ID +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControllerId(pub u8); + +/// 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; + +pub fn power_capability_try_from_contract( + contract: Contract, +) -> Option { + Some(power_policy_interface::capability::PowerCapability { + voltage_mv: contract.pdo.max_voltage_mv(), + current_ma: contract.operating_current_ma()?, + }) +} + +pub fn power_capability_from_current(current: type_c::Current) -> power_policy_interface::capability::PowerCapability { + power_policy_interface::capability::PowerCapability { + voltage_mv: 5000, + // Assume higher power for now + current_ma: current.to_ma(false), + } +} + +/// Type-C USB2 power capability 5V@500mA +pub const POWER_CAPABILITY_USB_DEFAULT_USB2: power_policy_interface::capability::PowerCapability = + power_policy_interface::capability::PowerCapability { + voltage_mv: 5000, + current_ma: 500, + }; + +/// Type-C USB3 power capability 5V@900mA +pub const POWER_CAPABILITY_USB_DEFAULT_USB3: power_policy_interface::capability::PowerCapability = + power_policy_interface::capability::PowerCapability { + voltage_mv: 5000, + current_ma: 900, + }; + +/// Type-C power capability 5V@1.5A +pub const POWER_CAPABILITY_5V_1A5: power_policy_interface::capability::PowerCapability = + power_policy_interface::capability::PowerCapability { + voltage_mv: 5000, + current_ma: 1500, + }; + +/// Type-C power capability 5V@3A +pub const POWER_CAPABILITY_5V_3A0: power_policy_interface::capability::PowerCapability = + power_policy_interface::capability::PowerCapability { + voltage_mv: 5000, + current_ma: 3000, + }; + +/// Newtype to help clarify arguments to port status commands +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Cached(pub bool); diff --git a/type-c-service/src/wrapper/backing.rs b/type-c-service/src/wrapper/backing.rs index d93f0353..ceed5aae 100644 --- a/type-c-service/src/wrapper/backing.rs +++ b/type-c-service/src/wrapper/backing.rs @@ -1,64 +1,6 @@ //! Various types of state and objects required for [`crate::wrapper::ControllerWrapper`]. //! -//! The wrapper needs per-port state which ultimately needs to come from something like an array. -//! We need to erase the generic `N` parameter from that storage so as not to monomorphize the entire -//! wrapper over it. This module provides the necessary types and traits to do so. Things required by -//! the wrapper can be split into two categories: objects used for service registration (which must be immutable), -//! and mutable state. These are represented by the [`Registration`] and [`DynPortState`] respectively. The later -//! is a trait intended to be used as a trait object to erase the generic port count. -//! -//! [`Storage`] is the base storage type and is generic over the number of ports. However, there are additional -//! objects that need to reference the storage. To avoid a self-referential -//! struct, [`ReferencedStorage`] contains these. This struct is still generic over the number of ports. -//! -//! Lastly, [`Backing`] contains references to the registration and type-erased state and is what is passed -//! to the wrapper. -//! -//! Example usage: -//! ``` -//! use embassy_sync::blocking_mutex::raw::NoopRawMutex; -//! use static_cell::StaticCell; -//! use embedded_services::type_c::ControllerId; -//! use embedded_services::power; -//! use embedded_usb_pd::GlobalPortId; -//! use type_c_service::wrapper::backing::{Storage, IntermediateStorage, ReferencedStorage}; -//! use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; -//! use embedded_services::power::policy::policy; -//! -//! fn init(context: &'static embedded_services::type_c::controller::Context) { -//! static STORAGE: StaticCell> = StaticCell::new(); -//! let storage = STORAGE.init(Storage::new( -//! context, -//! ControllerId(0), -//! 0x0, // CFU component ID (unused) -//! [GlobalPortId(0)], -//! )); -//! -//! static INTERMEDIATE: StaticCell> = -//! StaticCell::new(); -//! let intermediate = INTERMEDIATE.init(storage.try_create_intermediate().expect("Failed to create intermediate storage")); -//! -//! static POLICY_CHANNEL: StaticCell> = StaticCell::new(); -//! let policy_channel = POLICY_CHANNEL.init(Channel::new()); -//! -//! let policy_sender = policy_channel.dyn_sender(); -//! let policy_receiver = policy_channel.dyn_receiver(); -//! -//! static REFERENCED: StaticCell< -//! type_c_service::wrapper::backing::ReferencedStorage< -//! 1, -//! NoopRawMutex, -//! DynamicSender<'_, policy::RequestData>, -//! DynamicReceiver<'_, policy::RequestData>, -//! >, -//! > = StaticCell::new(); -//! let referenced = REFERENCED.init( -//! intermediate -//! .try_create_referenced([(power::policy::DeviceId(0), policy_sender, policy_receiver)]) -//! .expect("Failed to create referenced storage"), -//! ); -//! } -//! ``` +//! TODO: Update as part of type-C refactoring use core::{ array::from_fn, cell::{RefCell, RefMut}, @@ -72,20 +14,16 @@ use embassy_sync::{ }; use embassy_time::Instant; use embedded_cfu_protocol::protocol_definitions::ComponentId; -use embedded_services::{ - event, - power::{ - self, - policy::{DeviceId, policy}, - }, - type_c::{ - ControllerId, - controller::PortStatus, - event::{PortEvent, PortStatusChanged}, - }, -}; +use embedded_services::event; use embedded_usb_pd::{GlobalPortId, ado::Ado}; +use crate::type_c::{ + ControllerId, + controller::PortStatus, + event::{PortEvent, PortStatusChanged}, +}; +use power_policy_interface::psu::DeviceId; + use crate::{ PortEventStreamer, wrapper::{ @@ -129,13 +67,13 @@ impl Default for ControllerState { } /// Internal state containing all per-port and per-controller state -struct InternalState<'a, const N: usize, S: event::Sender> { +struct InternalState<'a, const N: usize, S: event::Sender> { controller_state: ControllerState, port_states: [PortState<'a>; N], port_power: [PortPower; N], } -impl<'a, const N: usize, S: event::Sender> InternalState<'a, N, S> { +impl<'a, const N: usize, S: event::Sender> InternalState<'a, N, S> { fn try_new(storage: &'a Storage, power_events: [S; N]) -> Option { let port_states = storage.pd_alerts.each_ref().map(|pd_alert| { Some(PortState { @@ -164,7 +102,9 @@ impl<'a, const N: usize, S: event::Sender> InternalState<'a } } -impl<'a, const N: usize, S: event::Sender> DynPortState<'a, S> for InternalState<'a, N, S> { +impl<'a, const N: usize, S: event::Sender> DynPortState<'a, S> + for InternalState<'a, N, S> +{ fn num_ports(&self) -> usize { self.port_states.len() } @@ -195,7 +135,7 @@ impl<'a, const N: usize, S: event::Sender> DynPortState<'a, } /// Trait to erase the generic port count argument -pub trait DynPortState<'a, S: event::Sender> { +pub trait DynPortState<'a, S: event::Sender> { fn num_ports(&self) -> usize; fn port_states(&self) -> &[PortState<'a>]; @@ -209,14 +149,14 @@ pub trait DynPortState<'a, S: event::Sender> { } /// Service registration objects -pub struct Registration<'a, M: RawMutex, R: event::Receiver> { - pub context: &'a embedded_services::type_c::controller::Context, - pub pd_controller: &'a embedded_services::type_c::controller::Device<'a>, +pub struct Registration<'a, M: RawMutex, R: event::Receiver> { + pub context: &'a crate::type_c::controller::Context, + pub pd_controller: &'a crate::type_c::controller::Device<'a>, pub cfu_device: &'a CfuDevice, - pub power_devices: &'a [embedded_services::power::policy::device::Device<'a, Mutex>, R>], + pub power_devices: &'a [power_policy_interface::psu::RegistrationEntry<'a, Mutex>, R>], } -impl<'a, M: RawMutex, R: event::Receiver> Registration<'a, M, R> { +impl<'a, M: RawMutex, R: event::Receiver> Registration<'a, M, R> { pub fn num_ports(&self) -> usize { self.power_devices.len() } @@ -225,15 +165,15 @@ impl<'a, M: RawMutex, R: event::Receiver> Registration<'a, /// PD alerts should be fairly uncommon, four seems like a reasonable number to start with. const MAX_BUFFERED_PD_ALERTS: usize = 4; -pub struct PortPower> { +pub struct PortPower> { pub sender: S, - pub state: power::policy::device::InternalState, + pub state: power_policy_interface::psu::InternalState, } /// Base storage pub struct Storage<'a, const N: usize, M: RawMutex> { // Registration-related - context: &'a embedded_services::type_c::controller::Context, + context: &'a crate::type_c::controller::Context, controller_id: ControllerId, pd_ports: [GlobalPortId; N], cfu_device: CfuDevice, @@ -245,7 +185,7 @@ pub struct Storage<'a, const N: usize, M: RawMutex> { impl<'a, const N: usize, M: RawMutex> Storage<'a, N, M> { pub fn new( - context: &'a embedded_services::type_c::controller::Context, + context: &'a crate::type_c::controller::Context, controller_id: ControllerId, cfu_id: ComponentId, pd_ports: [GlobalPortId; N], @@ -295,7 +235,11 @@ impl<'a, const N: usize, M: RawMutex> IntermediateStorage<'a, N, M> { } /// Create referenced storage from this intermediate storage - pub fn try_create_referenced<'b, S: event::Sender, R: event::Receiver>( + pub fn try_create_referenced< + 'b, + S: event::Sender, + R: event::Receiver, + >( &'b self, policy_args: [(DeviceId, S, R); N], ) -> Option> @@ -314,17 +258,22 @@ pub struct ReferencedStorage< 'a, const N: usize, M: RawMutex, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, > { intermediate: &'a IntermediateStorage<'a, N, M>, state: RefCell>, - pd_controller: embedded_services::type_c::controller::Device<'a>, - power_devices: [embedded_services::power::policy::device::Device<'a, Mutex>, R>; N], + pd_controller: crate::type_c::controller::Device<'a>, + power_devices: [power_policy_interface::psu::RegistrationEntry<'a, Mutex>, R>; N], } -impl<'a, const N: usize, M: RawMutex, S: event::Sender, R: event::Receiver> - ReferencedStorage<'a, N, M, S, R> +impl< + 'a, + const N: usize, + M: RawMutex, + S: event::Sender, + R: event::Receiver, +> ReferencedStorage<'a, N, M, S, R> { /// Create a new referenced storage from the given intermediate storage fn try_from_intermediate( @@ -337,7 +286,7 @@ impl<'a, const N: usize, M: RawMutex, S: event::Sender, R: for (i, (device_id, policy_sender, policy_receiver)) in policy_args.into_iter().enumerate() { power_senders.push(policy_sender).ok()?; power_devices - .push(embedded_services::power::policy::device::Device::new( + .push(power_policy_interface::psu::RegistrationEntry::new( device_id, intermediate.power_proxy_devices.get(i)?, policy_receiver, @@ -352,7 +301,7 @@ impl<'a, const N: usize, M: RawMutex, S: event::Sender, R: // Safe because both have N elements power_senders.into_array().ok()?, )?), - pd_controller: embedded_services::type_c::controller::Device::new( + pd_controller: crate::type_c::controller::Device::new( intermediate.storage.controller_id, intermediate.storage.pd_ports.as_slice(), ), @@ -379,7 +328,12 @@ impl<'a, const N: usize, M: RawMutex, S: event::Sender, R: } /// Wrapper around registration and type-erased state -pub struct Backing<'a, M: RawMutex, S: event::Sender, R: event::Receiver> { +pub struct Backing< + 'a, + M: RawMutex, + S: event::Sender, + R: event::Receiver, +> { pub(crate) registration: Registration<'a, M, R>, pub(crate) state: RefMut<'a, dyn DynPortState<'a, S>>, pub(crate) power_receivers: &'a [Mutex>], diff --git a/type-c-service/src/wrapper/cfu.rs b/type-c-service/src/wrapper/cfu.rs index b7d1910b..d82f0c38 100644 --- a/type-c-service/src/wrapper/cfu.rs +++ b/type-c-service/src/wrapper/cfu.rs @@ -1,11 +1,9 @@ //! CFU message bridge //! TODO: remove this once we have a more generic FW update implementation +use crate::type_c::controller::Controller; use cfu_service::component::{InternalResponseData, RequestData}; use embassy_futures::select::{Either, select}; use embedded_cfu_protocol::protocol_definitions::*; -use embedded_services::power; -use embedded_services::power::policy::policy; -use embedded_services::type_c::controller::Controller; use embedded_services::{debug, error}; use super::message::EventCfu; @@ -34,8 +32,8 @@ impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where @@ -151,9 +149,12 @@ where let controller_id = self.registration.pd_controller.id(); for power in state.port_power_mut() { info!("Controller{}: checking power device", controller_id.0); - if power.state.state() != power::policy::device::State::Detached { + if power.state.state() != power_policy_interface::psu::State::Detached { info!("Controller{}: Detaching power device", controller_id.0); - power.sender.send(policy::RequestData::Detached).await; + power + .sender + .send(power_policy_interface::psu::event::RequestData::Detached) + .await; } } diff --git a/type-c-service/src/wrapper/dp.rs b/type-c-service/src/wrapper/dp.rs index d54fb7b1..0f634473 100644 --- a/type-c-service/src/wrapper/dp.rs +++ b/type-c-service/src/wrapper/dp.rs @@ -1,15 +1,16 @@ use super::{ControllerWrapper, FwOfferValidator}; +use crate::type_c::controller::Controller; use crate::wrapper::message::OutputDpStatusChanged; use embassy_sync::blocking_mutex::raw::RawMutex; -use embedded_services::{event, power::policy::policy, sync::Lockable, trace, type_c::controller::Controller}; +use embedded_services::{event, sync::Lockable, trace}; use embedded_usb_pd::{Error, LocalPortId}; impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where diff --git a/type-c-service/src/wrapper/message.rs b/type-c-service/src/wrapper/message.rs index c9b1b66f..c49d3147 100644 --- a/type-c-service/src/wrapper/message.rs +++ b/type-c-service/src/wrapper/message.rs @@ -1,15 +1,12 @@ //! [`crate::wrapper::ControllerWrapper`] message types -use embedded_services::{ - GlobalRawMutex, - ipc::deferred, - power::policy, - type_c::{ - controller::{self, DpStatus, PortStatus}, - event::{PortNotificationSingle, PortStatusChanged}, - }, -}; +use embedded_services::{GlobalRawMutex, ipc::deferred}; use embedded_usb_pd::{LocalPortId, ado::Ado}; +use crate::type_c::{ + controller::{self, DpStatus, PortStatus}, + event::{PortNotificationSingle, PortStatusChanged}, +}; + /// Port status changed event data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -35,7 +32,7 @@ pub struct EventPowerPolicyCommand { /// Port ID pub port: LocalPortId, /// Power policy request - pub request: policy::device::CommandData, + pub request: power_policy_interface::psu::CommandData, } /// CFU events @@ -91,7 +88,7 @@ pub struct OutputPowerPolicyCommand { /// Port ID pub port: LocalPortId, /// Response - pub response: policy::device::InternalResponseData, + pub response: power_policy_interface::psu::InternalResponseData, } /// Controller command output data @@ -105,7 +102,7 @@ pub struct OutputControllerCommand<'a> { pub mod vdm { //! Events and output for vendor-defined messaging. use super::LocalPortId; - use embedded_services::type_c::controller::{AttnVdm, OtherVdm}; + use crate::type_c::controller::{AttnVdm, OtherVdm}; /// The kind of output from processing a vendor-defined message. #[derive(Copy, Clone, Debug)] diff --git a/type-c-service/src/wrapper/mod.rs b/type-c-service/src/wrapper/mod.rs index e58ff41e..15dd4d25 100644 --- a/type-c-service/src/wrapper/mod.rs +++ b/type-c-service/src/wrapper/mod.rs @@ -1,9 +1,8 @@ //! This module contains the [`ControllerWrapper`] struct. This struct serves as a bridge between various service messages -//! and the actual controller functions provided by [`embedded_services::type_c::controller::Controller`]. +//! and the actual controller functions provided by [`crate::type_c::controller::Controller`]. //! # Supported service messaging //! This struct current currently supports messages from the following services: -//! * Type-C: [`embedded_services::type_c::controller::Command`] -//! * Power policy: [`embedded_services::power::policy::device::Command`] +//! * Type-C: [`crate::type_c::controller::Command`] //! * CFU: [`cfu_service::Request`] //! # Event loop //! This struct follows a standard wait/process/finalize event loop. @@ -21,6 +20,8 @@ use core::cell::RefMut; use core::future::pending; use core::ops::DerefMut; +use crate::type_c::controller::{self, Controller, PortStatus}; +use crate::type_c::event::{PortEvent, PortNotificationSingle, PortPending, PortStatusChanged}; use cfu_service::CfuClient; use embassy_futures::select::{Either, Either5, select, select_array, select5}; use embassy_sync::blocking_mutex::raw::RawMutex; @@ -28,10 +29,7 @@ use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; use embassy_time::Instant; use embedded_cfu_protocol::protocol_definitions::{FwUpdateOffer, FwUpdateOfferResponse, FwVersion}; -use embedded_services::power::policy::policy; use embedded_services::sync::Lockable; -use embedded_services::type_c::controller::{self, Controller, PortStatus}; -use embedded_services::type_c::event::{PortEvent, PortNotificationSingle, PortPending, PortStatusChanged}; use embedded_services::{debug, error, info, trace, warn}; use embedded_services::{event, intrusive_list}; use embedded_usb_pd::ado::Ado; @@ -69,13 +67,13 @@ pub trait FwOfferValidator { /// Maximum number of supported ports pub const MAX_SUPPORTED_PORTS: usize = 2; -/// Common functionality implemented on top of [`embedded_services::type_c::controller::Controller`] +/// Common functionality implemented on top of [`crate::type_c::controller::Controller`] pub struct ControllerWrapper< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > where D::Inner: Controller, @@ -101,8 +99,8 @@ impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where @@ -205,10 +203,16 @@ where info!("Plug event"); if status.is_connected() { info!("Plug inserted"); - power.sender.send(policy::RequestData::Attached).await; + power + .sender + .send(power_policy_interface::psu::event::RequestData::Attached) + .await; } else { info!("Plug removed"); - power.sender.send(policy::RequestData::Detached).await; + power + .sender + .send(power_policy_interface::psu::event::RequestData::Detached) + .await; } Ok(()) @@ -607,14 +611,11 @@ where pub fn register( &'static self, controllers: &intrusive_list::IntrusiveList, - power_policy_context: &embedded_services::power::policy::policy::Context< - Mutex>, - R, - >, + power_policy_context: &power_policy_service::service::context::Context>, R>, cfu_client: &'static CfuClient, ) -> Result<(), Error<::BusError>> { for device in self.registration.power_devices { - power_policy_context.register_device(device).map_err(|_| { + power_policy_context.register_psu(device).map_err(|_| { error!( "Controller{}: Failed to register power device {}", self.registration.pd_controller.id().0, @@ -648,8 +649,8 @@ impl< 'device, M: RawMutex, C: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > Lockable for ControllerWrapper<'device, M, C, S, R, V> where diff --git a/type-c-service/src/wrapper/pd.rs b/type-c-service/src/wrapper/pd.rs index a47fd93e..6a306d18 100644 --- a/type-c-service/src/wrapper/pd.rs +++ b/type-c-service/src/wrapper/pd.rs @@ -1,12 +1,12 @@ +use crate::type_c::Cached; +use crate::type_c::controller::{InternalResponseData, Response}; use embassy_futures::yield_now; use embassy_sync::pubsub::WaitResult; use embassy_time::{Duration, Timer}; use embedded_services::debug; -use embedded_services::power::policy::device::State; -use embedded_services::type_c::Cached; -use embedded_services::type_c::controller::{InternalResponseData, Response}; use embedded_usb_pd::constants::{T_PS_TRANSITION_EPR_MS, T_PS_TRANSITION_SPR_MS}; use embedded_usb_pd::ucsi::{self, lpm}; +use power_policy_interface::psu::State; use super::*; @@ -14,8 +14,8 @@ impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where @@ -148,7 +148,10 @@ where "Port{}: Disconnecting consumer before setting max sink voltage", local_port.0 ); - port_power.sender.send(policy::RequestData::Disconnected).await; + port_power + .sender + .send(power_policy_interface::psu::event::RequestData::Disconnected) + .await; } } diff --git a/type-c-service/src/wrapper/power.rs b/type-c-service/src/wrapper/power.rs index 2c226719..e778b504 100644 --- a/type-c-service/src/wrapper/power.rs +++ b/type-c-service/src/wrapper/power.rs @@ -2,17 +2,12 @@ use core::pin::pin; use embassy_futures::select::select_slice; -use embedded_services::{ - debug, - power::policy::{ - ConsumerPowerCapability, ProviderPowerCapability, - device::{CommandData, InternalResponseData, ResponseData}, - flags::PsuType, - }, -}; +use embedded_services::debug; -use embedded_services::power::policy::Error as PowerError; -use embedded_services::power::policy::device::CommandData as PowerCommand; +use power_policy_interface::capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}; +use power_policy_interface::psu::CommandData as PowerCommand; +use power_policy_interface::psu::Error as PowerError; +use power_policy_interface::psu::{CommandData, InternalResponseData, ResponseData}; use crate::wrapper::config::UnconstrainedSink; @@ -22,8 +17,8 @@ impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where @@ -50,7 +45,7 @@ where power .sender - .send(policy::RequestData::UpdatedConsumerCapability(available_sink_contract)) + .send(power_policy_interface::psu::event::RequestData::UpdatedConsumerCapability(available_sink_contract)) .await; Ok(()) } @@ -64,13 +59,15 @@ where info!("Process New provider contract"); power .sender - .send(policy::RequestData::RequestedProviderCapability( - status.available_source_contract.map(|caps| { - let mut caps = ProviderPowerCapability::from(caps); - caps.flags.set_psu_type(PsuType::TypeC); - caps - }), - )) + .send( + power_policy_interface::psu::event::RequestData::RequestedProviderCapability( + status.available_source_contract.map(|caps| { + let mut caps = ProviderPowerCapability::from(caps); + caps.flags.set_psu_type(PsuType::TypeC); + caps + }), + ), + ) .await; Ok(()) } diff --git a/type-c-service/src/wrapper/proxy.rs b/type-c-service/src/wrapper/proxy.rs index 252247e8..c8f95110 100644 --- a/type-c-service/src/wrapper/proxy.rs +++ b/type-c-service/src/wrapper/proxy.rs @@ -1,9 +1,6 @@ use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; -use embedded_services::power; -use embedded_services::power::policy::device::{ - CommandData as PolicyCommandData, DeviceTrait, InternalResponseData as PolicyResponseData, -}; +use power_policy_interface::psu::{CommandData as PolicyCommandData, InternalResponseData as PolicyResponseData, Psu}; pub struct PowerProxyChannel { command_channel: Channel, @@ -74,15 +71,15 @@ impl<'a> PowerProxyDevice<'a> { } } -impl<'a> DeviceTrait for PowerProxyDevice<'a> { - async fn disconnect(&mut self) -> Result<(), power::policy::Error> { +impl<'a> Psu for PowerProxyDevice<'a> { + async fn disconnect(&mut self) -> Result<(), power_policy_interface::psu::Error> { self.execute(PolicyCommandData::Disconnect).await?.complete_or_err() } async fn connect_provider( &mut self, - capability: power::policy::ProviderPowerCapability, - ) -> Result<(), power::policy::Error> { + capability: power_policy_interface::capability::ProviderPowerCapability, + ) -> Result<(), power_policy_interface::psu::Error> { self.execute(PolicyCommandData::ConnectAsProvider(capability)) .await? .complete_or_err() @@ -90,8 +87,8 @@ impl<'a> DeviceTrait for PowerProxyDevice<'a> { async fn connect_consumer( &mut self, - capability: power::policy::ConsumerPowerCapability, - ) -> Result<(), power::policy::Error> { + capability: power_policy_interface::capability::ConsumerPowerCapability, + ) -> Result<(), power_policy_interface::psu::Error> { self.execute(PolicyCommandData::ConnectAsConsumer(capability)) .await? .complete_or_err() diff --git a/type-c-service/src/wrapper/vdm.rs b/type-c-service/src/wrapper/vdm.rs index 9f8a6b4f..1ca951b5 100644 --- a/type-c-service/src/wrapper/vdm.rs +++ b/type-c-service/src/wrapper/vdm.rs @@ -1,26 +1,22 @@ use embassy_sync::blocking_mutex::raw::RawMutex; -use embedded_services::{ - event, - power::policy::policy, - sync::Lockable, - trace, - type_c::{ - controller::Controller, - event::{PortPending, VdmNotification}, - }, -}; +use embedded_services::{event, sync::Lockable, trace}; use embedded_usb_pd::{Error, LocalPortId, PdError}; use crate::wrapper::{DynPortState, message::vdm::OutputKind}; +use crate::type_c::{ + controller::Controller, + event::{PortPending, VdmNotification}, +}; + use super::{ControllerWrapper, FwOfferValidator, message::vdm::Output}; impl< 'device, M: RawMutex, D: Lockable, - S: event::Sender, - R: event::Receiver, + S: event::Sender, + R: event::Receiver, V: FwOfferValidator, > ControllerWrapper<'device, M, D, S, R, V> where