use heapless::Vec;
use proc_bitfield::bitfield;
use uom::si::electric_current::centiampere;
use crate::_50millivolts_mod::_50millivolts;
use crate::_250milliwatts_mod::_250milliwatts;
use crate::units::{ElectricCurrent, ElectricPotential, Power};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FastRoleSwapCurrent {
#[default]
NotSupported = 0b00,
DefaultUsbPower = 0b01,
Current1_5A = 0b10,
Current3_0A = 0b11,
}
impl From<u8> for FastRoleSwapCurrent {
fn from(value: u8) -> Self {
match value & 0b11 {
0b00 => Self::NotSupported,
0b01 => Self::DefaultUsbPower,
0b10 => Self::Current1_5A,
0b11 => Self::Current3_0A,
_ => unreachable!(),
}
}
}
bitfield! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedSupply(pub u32): Debug, FromStorage, IntoStorage {
pub kind: u8 @ 30..=31,
pub dual_role_power: bool @ 29,
pub higher_capability: bool @ 28,
pub unconstrained_power: bool @ 27,
pub usb_communications_capable: bool @ 26,
pub dual_role_data: bool @ 25,
pub raw_fast_role_swap: u8 @ 23..=24,
pub reserved: u8 @ 20..=22,
pub raw_voltage: u16 @ 10..=19,
pub raw_operational_current: u16 @ 0..=9,
}
}
#[allow(clippy::derivable_impls)]
impl Default for FixedSupply {
fn default() -> Self {
Self(0)
}
}
impl FixedSupply {
pub fn new_vsafe5v(operational_current_10ma: u16) -> Self {
Self::default()
.with_kind(0b00)
.with_raw_voltage(100) .with_raw_operational_current(operational_current_10ma)
}
pub fn new(voltage_50mv: u16, operational_current_10ma: u16) -> Self {
Self::default()
.with_kind(0b00)
.with_raw_voltage(voltage_50mv)
.with_raw_operational_current(operational_current_10ma)
}
pub fn voltage(&self) -> ElectricPotential {
ElectricPotential::new::<_50millivolts>(self.raw_voltage().into())
}
pub fn operational_current(&self) -> ElectricCurrent {
ElectricCurrent::new::<centiampere>(self.raw_operational_current().into())
}
pub fn fast_role_swap(&self) -> FastRoleSwapCurrent {
FastRoleSwapCurrent::from(self.raw_fast_role_swap())
}
}
bitfield! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Battery(pub u32): Debug, FromStorage, IntoStorage {
pub kind: u8 @ 30..=31,
pub raw_max_voltage: u16 @ 20..=29,
pub raw_min_voltage: u16 @ 10..=19,
pub raw_operational_power: u16 @ 0..=9,
}
}
impl Battery {
pub fn new(min_voltage_50mv: u16, max_voltage_50mv: u16, operational_power_250mw: u16) -> Self {
Self::default()
.with_kind(0b01)
.with_raw_min_voltage(min_voltage_50mv)
.with_raw_max_voltage(max_voltage_50mv)
.with_raw_operational_power(operational_power_250mw)
}
pub fn max_voltage(&self) -> ElectricPotential {
ElectricPotential::new::<_50millivolts>(self.raw_max_voltage().into())
}
pub fn min_voltage(&self) -> ElectricPotential {
ElectricPotential::new::<_50millivolts>(self.raw_min_voltage().into())
}
pub fn operational_power(&self) -> Power {
Power::new::<_250milliwatts>(self.raw_operational_power().into())
}
}
#[allow(clippy::derivable_impls)]
impl Default for Battery {
fn default() -> Self {
Self(0)
}
}
bitfield! {
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariableSupply(pub u32): Debug, FromStorage, IntoStorage {
pub kind: u8 @ 30..=31,
pub raw_max_voltage: u16 @ 20..=29,
pub raw_min_voltage: u16 @ 10..=19,
pub raw_operational_current: u16 @ 0..=9,
}
}
impl VariableSupply {
pub fn new(min_voltage_50mv: u16, max_voltage_50mv: u16, operational_current_10ma: u16) -> Self {
Self::default()
.with_kind(0b10)
.with_raw_min_voltage(min_voltage_50mv)
.with_raw_max_voltage(max_voltage_50mv)
.with_raw_operational_current(operational_current_10ma)
}
pub fn max_voltage(&self) -> ElectricPotential {
ElectricPotential::new::<_50millivolts>(self.raw_max_voltage().into())
}
pub fn min_voltage(&self) -> ElectricPotential {
ElectricPotential::new::<_50millivolts>(self.raw_min_voltage().into())
}
pub fn operational_current(&self) -> ElectricCurrent {
ElectricCurrent::new::<centiampere>(self.raw_operational_current().into())
}
}
#[allow(clippy::derivable_impls)]
impl Default for VariableSupply {
fn default() -> Self {
Self(0)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SinkPowerDataObject {
FixedSupply(FixedSupply),
Battery(Battery),
VariableSupply(VariableSupply),
}
impl SinkPowerDataObject {
pub fn to_raw(&self) -> u32 {
match self {
SinkPowerDataObject::FixedSupply(f) => f.0,
SinkPowerDataObject::Battery(b) => b.0,
SinkPowerDataObject::VariableSupply(v) => v.0,
}
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SinkCapabilities(pub Vec<SinkPowerDataObject, 7>);
impl SinkCapabilities {
pub fn new_vsafe5v_only(operational_current_10ma: u16) -> Self {
let mut pdos = Vec::new();
pdos.push(SinkPowerDataObject::FixedSupply(FixedSupply::new_vsafe5v(
operational_current_10ma,
)))
.ok();
Self(pdos)
}
pub fn new(pdos: Vec<SinkPowerDataObject, 7>) -> Self {
Self(pdos)
}
pub fn pdos(&self) -> &[SinkPowerDataObject] {
&self.0
}
pub fn num_objects(&self) -> u8 {
self.0.len() as u8
}
pub fn to_bytes(&self, buffer: &mut [u8]) -> usize {
let mut offset = 0;
for pdo in &self.0 {
let raw = pdo.to_raw();
buffer[offset..offset + 4].copy_from_slice(&raw.to_le_bytes());
offset += 4;
}
offset
}
}