From b8a151590d0b96bfd4c79fb07c6cbf3bad3f6e35 Mon Sep 17 00:00:00 2001 From: Ferdia McKeogh Date: Mon, 20 May 2024 21:52:20 +0100 Subject: [PATCH 1/2] PoC unit implementation --- Cargo.lock | 37 ++++++++++++++++++++++ pd-interceptor/src/main.rs | 18 ++++++----- usb-pd/Cargo.toml | 1 + usb-pd/src/messages/pdo.rs | 65 ++++++++++++++++++++++---------------- 4 files changed, 86 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c77ef9e..dba4b8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -571,6 +571,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[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-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -805,12 +824,29 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "uom" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd36e5350a65d112584053ee91843955826bf9e56ec0d1351214e01f6d7cd9c" +dependencies = [ + "num-rational", + "num-traits", + "typenum", +] + [[package]] name = "usb-pd" version = "0.0.1" @@ -820,6 +856,7 @@ dependencies = [ "embassy-time", "heapless", "proc-bitfield", + "uom", ] [[package]] diff --git a/pd-interceptor/src/main.rs b/pd-interceptor/src/main.rs index 62c1508..034751d 100644 --- a/pd-interceptor/src/main.rs +++ b/pd-interceptor/src/main.rs @@ -109,10 +109,10 @@ fn handle_event(event: Event) -> Option { .filter_map(|(i, cap)| { if let PowerDataObject::FixedSupply(supply) = cap { debug!( - "supply @ {}: {}mV {}mA", + "supply @ {}: {}V {}A", i, - supply.voltage_mv(), - supply.max_current_ma() + supply.voltage().value, + supply.max_current().value ); Some((i, supply)) } else { @@ -122,12 +122,14 @@ fn handle_event(event: Event) -> Option { .max_by(|(_, x), (_, y)| x.raw_voltage().cmp(&y.raw_voltage())) .unwrap(); - info!("requesting supply {:?}@{}", supply, index); - - return Some(Request::RequestPower { + let req = Request::RequestPower { index, - current: supply.max_current_ma(), - }); + current: supply.raw_max_current(), + }; + + info!("requesting {}", req); + + return Some(req); } Event::PowerReady => info!("power ready"), Event::ProtocolChanged => info!("protocol changed"), diff --git a/usb-pd/Cargo.toml b/usb-pd/Cargo.toml index 90c60d1..f8ab262 100644 --- a/usb-pd/Cargo.toml +++ b/usb-pd/Cargo.toml @@ -15,3 +15,4 @@ byteorder = { version = "1.5.0", default-features = false } defmt = "0.3.6" heapless = { version = "0.8.0", features = ["defmt-03"] } embassy-time = "0.3.0" +uom = { version = "0.36.0", default-features = false, features = ["autoconvert", "si", "u16", "u32"] } diff --git a/usb-pd/src/messages/pdo.rs b/usb-pd/src/messages/pdo.rs index 8ec051e..2f15691 100644 --- a/usb-pd/src/messages/pdo.rs +++ b/usb-pd/src/messages/pdo.rs @@ -3,6 +3,13 @@ use { defmt::Format, heapless::Vec, proc_bitfield::bitfield, + uom::si::{ + electric_current::milliampere, + electric_potential::millivolt, + power::{milliwatt, watt}, + u16::{ElectricCurrent, ElectricPotential}, + u32::Power, + }, }; #[derive(Clone, Copy, Debug, Format)] @@ -50,12 +57,12 @@ bitfield! { } impl FixedSupply { - pub fn voltage_mv(&self) -> u16 { - self.raw_voltage() * 50 + pub fn voltage(&self) -> ElectricPotential { + ElectricPotential::new::(self.raw_voltage() * 50) } - pub fn max_current_ma(&self) -> u16 { - self.raw_max_current() * 10 + pub fn max_current(&self) -> ElectricCurrent { + ElectricCurrent::new::(self.raw_max_current() * 10) } } @@ -74,16 +81,16 @@ bitfield! { } impl Battery { - pub fn max_voltage_mv(&self) -> u16 { - u16::from(self.raw_max_voltage()) * 50 + pub fn max_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(self.raw_max_voltage() * 50) } - pub fn min_voltage_mv(&self) -> u16 { - u16::from(self.raw_min_voltage()) * 50 + pub fn min_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(self.raw_min_voltage() * 50) } - pub fn max_power_mw(&self) -> u32 { - u32::from(self.raw_max_power()) * 250 + pub fn max_power(&self) -> Power { + Power::new::(u32::from(self.raw_max_power()) * 250) } } @@ -102,16 +109,16 @@ bitfield! { } impl VariableSupply { - pub fn max_voltage_mv(&self) -> u16 { - u16::from(self.raw_max_voltage()) * 50 + pub fn max_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(self.raw_max_voltage() * 50) } - pub fn min_voltage_mv(&self) -> u16 { - u16::from(self.raw_min_voltage()) * 50 + pub fn min_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(self.raw_min_voltage() * 50) } - pub fn max_current_ma(&self) -> u16 { - u16::from(self.raw_max_current()) * 10 + pub fn max_current(&self) -> ElectricCurrent { + ElectricCurrent::new::(self.raw_max_current() * 10) } } @@ -150,16 +157,16 @@ bitfield! { } impl SPRProgrammablePowerSupply { - pub fn max_voltage_mv(&self) -> u16 { - u16::from(self.raw_max_voltage()) * 100 + pub fn max_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(u16::from(self.raw_max_voltage()) * 100) } - pub fn min_voltage_mv(&self) -> u16 { - u16::from(self.raw_min_voltage()) * 100 + pub fn min_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(u16::from(self.raw_min_voltage()) * 100) } - pub fn max_current_ma(&self) -> u16 { - u16::from(self.raw_max_current()) * 50 + pub fn max_current(&self) -> ElectricCurrent { + ElectricCurrent::new::(u16::from(self.raw_max_current()) * 50) } } @@ -176,17 +183,21 @@ bitfield! { /// Minimum Voltage in 100mV increments pub raw_min_voltage: u8 @ 8..=15, /// PDP in 1W increments - pub pd_power: u8 @ 0..=7, + pub raw_pd_power: u8 @ 0..=7, } } impl EPRAdjustableVoltageSupply { - pub fn max_voltage_mv(&self) -> u16 { - u16::from(self.raw_max_voltage()) * 100 + pub fn max_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(u16::from(self.raw_max_voltage()) * 100) } - pub fn min_voltage_mv(&self) -> u16 { - u16::from(self.raw_min_voltage()) * 100 + pub fn min_voltage(&self) -> ElectricPotential { + ElectricPotential::new::(u16::from(self.raw_min_voltage()) * 100) + } + + pub fn pd_power(&self) -> Power { + Power::new::(u32::from(self.raw_pd_power())) } } From c5139d65da1f5934121585961a297a6acecef724 Mon Sep 17 00:00:00 2001 From: Ferdia McKeogh Date: Tue, 21 May 2024 19:44:06 +0100 Subject: [PATCH 2/2] Add correct unit types for 50mA, 50mV, and 250mW quantities --- Cargo.lock | 1 + pd-interceptor/Cargo.toml | 2 + pd-interceptor/src/main.rs | 7 +-- usb-pd/Cargo.toml | 2 +- usb-pd/src/lib.rs | 3 ++ usb-pd/src/messages/pdo.rs | 94 ++++++++++++++++++++++++-------------- 6 files changed, 70 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dba4b8c..099b62c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -631,6 +631,7 @@ dependencies = [ "embedded-hal-async", "fusb302b", "panic-probe", + "uom", "usb-pd", ] diff --git a/pd-interceptor/Cargo.toml b/pd-interceptor/Cargo.toml index ecef229..529d519 100644 --- a/pd-interceptor/Cargo.toml +++ b/pd-interceptor/Cargo.toml @@ -19,3 +19,5 @@ fusb302b = { path = "../fusb302b" } usb-pd = { path = "../usb-pd" } panic-probe = { version = "0.3.1", features = ["print-defmt"] } aht20-async = "1.0.0" + +uom = { version = "0.36.0", default-features = false, features = ["si"] } diff --git a/pd-interceptor/src/main.rs b/pd-interceptor/src/main.rs index 034751d..f31dd50 100644 --- a/pd-interceptor/src/main.rs +++ b/pd-interceptor/src/main.rs @@ -15,6 +15,7 @@ use { embassy_time::Instant, fusb302b::Fusb302b, panic_probe as _, + uom::si::{electric_current::milliampere, electric_potential::millivolt}, usb_pd::{ messages::pdo::PowerDataObject, sink::{Event, Request, Sink}, @@ -109,10 +110,10 @@ fn handle_event(event: Event) -> Option { .filter_map(|(i, cap)| { if let PowerDataObject::FixedSupply(supply) = cap { debug!( - "supply @ {}: {}V {}A", + "supply @ {}: {}mV {}mA", i, - supply.voltage().value, - supply.max_current().value + supply.voltage().get::(), + supply.max_current().get::(), ); Some((i, supply)) } else { diff --git a/usb-pd/Cargo.toml b/usb-pd/Cargo.toml index f8ab262..9ddd568 100644 --- a/usb-pd/Cargo.toml +++ b/usb-pd/Cargo.toml @@ -15,4 +15,4 @@ byteorder = { version = "1.5.0", default-features = false } defmt = "0.3.6" heapless = { version = "0.8.0", features = ["defmt-03"] } embassy-time = "0.3.0" -uom = { version = "0.36.0", default-features = false, features = ["autoconvert", "si", "u16", "u32"] } +uom = { version = "0.36.0", default-features = false, features = ["autoconvert", "si", "u8", "u16", "u32"] } diff --git a/usb-pd/src/lib.rs b/usb-pd/src/lib.rs index 1d79695..000f4c9 100644 --- a/usb-pd/src/lib.rs +++ b/usb-pd/src/lib.rs @@ -1,5 +1,8 @@ #![no_std] +#[macro_use] +extern crate uom; + pub mod header; pub mod messages; pub mod sink; diff --git a/usb-pd/src/messages/pdo.rs b/usb-pd/src/messages/pdo.rs index 2f15691..c6419e9 100644 --- a/usb-pd/src/messages/pdo.rs +++ b/usb-pd/src/messages/pdo.rs @@ -1,17 +1,41 @@ use { + _250milliwatts_mod::_250milliwatts, + _50milliamperes_mod::_50milliamperes, + _50millivolts_mod::_50millivolts, byteorder::{ByteOrder, LittleEndian}, defmt::Format, heapless::Vec, proc_bitfield::bitfield, - uom::si::{ - electric_current::milliampere, - electric_potential::millivolt, - power::{milliwatt, watt}, - u16::{ElectricCurrent, ElectricPotential}, - u32::Power, - }, + uom::si::{self, electric_current::centiampere, electric_potential::decivolt, power::watt}, }; +mod _50milliamperes_mod { + unit! { + system: uom::si; + quantity: uom::si::electric_current; + + @_50milliamperes: 0.05; "_50mA", "_50milliamps", "_50milliamps"; + } +} + +mod _50millivolts_mod { + unit! { + system: uom::si; + quantity: uom::si::electric_potential; + + @_50millivolts: 0.05; "_50mV", "_50millivolts", "_50millivolts"; + } +} + +mod _250milliwatts_mod { + unit! { + system: uom::si; + quantity: uom::si::power; + + @_250milliwatts: 0.25; "_250mW", "_250milliwatts", "_250milliwatts"; + } +} + #[derive(Clone, Copy, Debug, Format)] pub enum PowerDataObject { FixedSupply(FixedSupply), @@ -57,12 +81,12 @@ bitfield! { } impl FixedSupply { - pub fn voltage(&self) -> ElectricPotential { - ElectricPotential::new::(self.raw_voltage() * 50) + pub fn voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::<_50millivolts>(self.raw_voltage()) } - pub fn max_current(&self) -> ElectricCurrent { - ElectricCurrent::new::(self.raw_max_current() * 10) + pub fn max_current(&self) -> si::u16::ElectricCurrent { + si::u16::ElectricCurrent::new::(self.raw_max_current()) } } @@ -81,16 +105,16 @@ bitfield! { } impl Battery { - pub fn max_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(self.raw_max_voltage() * 50) + pub fn max_voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::<_50millivolts>(self.raw_max_voltage()) } - pub fn min_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(self.raw_min_voltage() * 50) + pub fn min_voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::<_50millivolts>(self.raw_min_voltage()) } - pub fn max_power(&self) -> Power { - Power::new::(u32::from(self.raw_max_power()) * 250) + pub fn max_power(&self) -> si::u16::Power { + si::u16::Power::new::<_250milliwatts>(self.raw_max_power()) } } @@ -109,16 +133,16 @@ bitfield! { } impl VariableSupply { - pub fn max_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(self.raw_max_voltage() * 50) + pub fn max_voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::<_50millivolts>(self.raw_max_voltage()) } - pub fn min_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(self.raw_min_voltage() * 50) + pub fn min_voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::<_50millivolts>(self.raw_min_voltage()) } - pub fn max_current(&self) -> ElectricCurrent { - ElectricCurrent::new::(self.raw_max_current() * 10) + pub fn max_current(&self) -> si::u16::ElectricCurrent { + si::u16::ElectricCurrent::new::(self.raw_max_current()) } } @@ -157,16 +181,16 @@ bitfield! { } impl SPRProgrammablePowerSupply { - pub fn max_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(u16::from(self.raw_max_voltage()) * 100) + pub fn max_voltage(&self) -> si::u8::ElectricPotential { + si::u8::ElectricPotential::new::(self.raw_max_voltage()) } - pub fn min_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(u16::from(self.raw_min_voltage()) * 100) + pub fn min_voltage(&self) -> si::u8::ElectricPotential { + si::u8::ElectricPotential::new::(self.raw_min_voltage()) } - pub fn max_current(&self) -> ElectricCurrent { - ElectricCurrent::new::(u16::from(self.raw_max_current()) * 50) + pub fn max_current(&self) -> si::u8::ElectricCurrent { + si::u8::ElectricCurrent::new::<_50milliamperes>(self.raw_max_current()) } } @@ -188,16 +212,16 @@ bitfield! { } impl EPRAdjustableVoltageSupply { - pub fn max_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(u16::from(self.raw_max_voltage()) * 100) + pub fn max_voltage(&self) -> si::u16::ElectricPotential { + si::u16::ElectricPotential::new::(self.raw_max_voltage()) } - pub fn min_voltage(&self) -> ElectricPotential { - ElectricPotential::new::(u16::from(self.raw_min_voltage()) * 100) + pub fn min_voltage(&self) -> si::u8::ElectricPotential { + si::u8::ElectricPotential::new::(self.raw_min_voltage()) } - pub fn pd_power(&self) -> Power { - Power::new::(u32::from(self.raw_pd_power())) + pub fn pd_power(&self) -> si::u8::Power { + si::u8::Power::new::(self.raw_pd_power()) } }