From 0cb93bd62f2e4820a8e981c8a30a11c22f748a39 Mon Sep 17 00:00:00 2001 From: Mike Panetta Date: Sat, 23 Dec 2023 22:29:32 -0500 Subject: [PATCH] Add some more fields and VDO's. --- usb-pd/src/message.rs | 14 ++-- usb-pd/src/pdo.rs | 183 +++++++++++++++++++++++++++++++++++++++++- usb-pd/src/sink.rs | 10 ++- 3 files changed, 193 insertions(+), 14 deletions(-) diff --git a/usb-pd/src/message.rs b/usb-pd/src/message.rs index 0b5ed21..e94090e 100644 --- a/usb-pd/src/message.rs +++ b/usb-pd/src/message.rs @@ -19,7 +19,7 @@ pub enum Message { Reject, Ready, SourceCapabilities(Vec), - VendorDefined(VDMHeader), // TODO: Incomplete + VendorDefined((VDMHeader, Vec)), // TODO: Incomplete SoftReset, Unknown, } @@ -57,9 +57,9 @@ impl Message { ), MessageType::Data(DataMessageType::VendorDefined) => { // Keep for now... - // let len = payload.len(); - // let num_obj = header.num_objects(); - //debug!("VENDOR: {:?}, {:?}, {:?}", len, num_obj, payload); + let len = payload.len(); + let num_obj = header.num_objects(); + trace!("VENDOR: {:?}, {:?}, {:x}", len, num_obj, payload); let header = { let raw = VDMHeaderRaw(LittleEndian::read_u32(&payload[..4])); @@ -71,7 +71,9 @@ impl Message { } }; - trace!("VDM RX: {:?}", header); + let data = payload[4..].chunks_exact(4).take(7).map(|buf| LittleEndian::read_u32(buf)).collect::>(); + + trace!("VDM RX: {:?} {:?}", header, data); // trace!("HEADER: VDM:: TYPE: {:?}, VERS: {:?}", header.vdm_type(), // header.vdm_version()); trace!("HEADER: CMD:: TYPE: {:?}, CMD: // {:?}", header.command_type(), header.command()); @@ -83,7 +85,7 @@ impl Message { // .map(|i| i[0]) // .collect::>(); - Message::VendorDefined(header) + Message::VendorDefined((header, data)) } _ => { warn!("unknown message type"); diff --git a/usb-pd/src/pdo.rs b/usb-pd/src/pdo.rs index fd4710b..bda0437 100644 --- a/usb-pd/src/pdo.rs +++ b/usb-pd/src/pdo.rs @@ -190,6 +190,7 @@ pub enum VDMCommand { DisplayPortStatus, DisplayPortConfig, } + impl From for u8 { fn from(value: VDMCommand) -> Self { match value { @@ -252,6 +253,13 @@ pub enum VDMHeader { Unstructured(VDMHeaderUnstructured), } +#[derive(Clone, Copy, Format)] +pub enum VendorDataObject { + IDHeader(VDMIdentityHeader), + CertStat(CertStatVDO), + Product(ProductVDO), +} + bitfield! { #[derive(Clone, Copy, PartialEq, Eq, Format)] pub struct VDMHeaderRaw(pub u32): Debug, FromRaw, IntoRaw { @@ -276,7 +284,8 @@ bitfield! { /// VDM Type (Unstructured/Structured) pub vdm_type: bool [VDMType] @ 15, /// Structured VDM Version - pub vdm_version: u8 @ 13..=14, + pub vdm_version_major: u8 @ 13..=14, + pub vdm_version_minor: u8 @ 11..=12, /// Object Position pub object_position: u8 @ 8..=10, /// Command Type @@ -292,6 +301,56 @@ impl VDMHeaderStructured { } } +#[derive(Clone, Copy, Format)] +pub enum VDMVersionMajor { + Version10, + Version2x, +} + +impl From for u8 { + fn from(value: VDMVersionMajor) -> Self { + match value { + VDMVersionMajor::Version10 => 0b00, + VDMVersionMajor::Version2x => 0b01, + } + } +} + +impl From for VDMVersionMajor { + fn from(value: u8) -> Self { + match value { + 0b00 => VDMVersionMajor::Version10, + 0b01 => VDMVersionMajor::Version2x, + _ => panic!("Cannot convert {:} to VDMVersionMajor", value), // Illegal values shall panic. + } + } +} + +#[derive(Clone, Copy, Format)] +pub enum VDMVersionMinor { + Version20, + Version21, +} + +impl From for u8 { + fn from(value: VDMVersionMinor) -> Self { + match value { + VDMVersionMinor::Version20 => 0b00, + VDMVersionMinor::Version21 => 0b01, + } + } +} + +impl From for VDMVersionMinor { + fn from(value: u8) -> Self { + match value { + 0b00 => VDMVersionMinor::Version20, + 0b01 => VDMVersionMinor::Version21, + _ => panic!("Cannot convert {:} to VDMVersionMinor", value), // Illegal values shall panic. + } + } +} + bitfield! { #[derive(Clone, Copy, PartialEq, Eq, Format)] pub struct VDMHeaderUnstructured(pub u32): Debug, FromRaw, IntoRaw { @@ -318,13 +377,13 @@ bitfield! { /// Device data capable pub device_data: bool @ 30, /// Product type UFP - pub product_type_ufp: u8 @ 27..=29, + pub product_type_ufp: u8 [SOPProductTypeUFP] @ 27..=29, /// Modal Operation Supported pub modal_supported: bool @ 26, /// Product type DFP - pub product_type_dfp: u8 @ 23..=25, + pub product_type_dfp: u8 [SOPProductTypeDFP] @ 23..=25, /// Connector type - pub connector_type: u8 @ 21..=22, + pub connector_type: u8 [ConnectorType] @ 21..=22, /// VID pub vid: u16 @ 0..=15, } @@ -336,6 +395,122 @@ impl VDMIdentityHeader { } } +#[derive(Clone, Copy, Format)] +pub enum SOPProductTypeUFP { + NotUFP, + PDUSBHub, + PDUSBPeripheral, + PSD, +} + +impl From for u8 { + fn from(value: SOPProductTypeUFP) -> Self { + match value { + SOPProductTypeUFP::NotUFP => 0b000, + SOPProductTypeUFP::PDUSBHub => 0b001, + SOPProductTypeUFP::PDUSBPeripheral => 0b010, + SOPProductTypeUFP::PSD => 0b011, + } + } +} + +impl From for SOPProductTypeUFP { + fn from(value: u8) -> Self { + match value { + 0b000 => SOPProductTypeUFP::NotUFP, + 0b001 => SOPProductTypeUFP::PDUSBHub, + 0b010 => SOPProductTypeUFP::PDUSBPeripheral, + 0b011 => SOPProductTypeUFP::PSD, + + _ => panic!("Cannot convert {:} to SOPProductTypeUFP", value), // Illegal values shall panic. + } + } +} + +#[derive(Clone, Copy, Format)] +pub enum SOPProductTypeDFP { + NotDFP, + PDUSBHub, + PDUSBHost, + PowerBrick, +} + +impl From for u8 { + fn from(value: SOPProductTypeDFP) -> Self { + match value { + SOPProductTypeDFP::NotDFP => 0b000, + SOPProductTypeDFP::PDUSBHub => 0b001, + SOPProductTypeDFP::PDUSBHost => 0b010, + SOPProductTypeDFP::PowerBrick => 0b011, + } + } +} + +impl From for SOPProductTypeDFP { + fn from(value: u8) -> Self { + match value { + 0b000 => SOPProductTypeDFP::NotDFP, + 0b001 => SOPProductTypeDFP::PDUSBHub, + 0b010 => SOPProductTypeDFP::PDUSBHost, + 0b011 => SOPProductTypeDFP::PowerBrick, + + _ => panic!("Cannot convert {:} to SOPProductTypeDFP", value), // Illegal values shall panic. + } + } +} + +pub enum ConnectorType { + USBTypeCReceptacle, + USBTypeCPlug, +} + +impl From for u8 { + fn from(value: ConnectorType) -> Self { + match value { + ConnectorType::USBTypeCReceptacle => 0b10, + ConnectorType::USBTypeCPlug => 0b11, + } + } +} + +impl From for ConnectorType { + fn from(value: u8) -> Self { + match value { + 0b10 => ConnectorType::USBTypeCReceptacle, + 0b11 => ConnectorType::USBTypeCPlug, + _ => panic!("Cannot convert {:} to ConnectorType", value), // Illegal values shall panic. + } + } +} +bitfield! { + #[derive(Clone, Copy, PartialEq, Eq, Format)] + pub struct CertStatVDO(pub u32): FromRaw, IntoRaw { + /// XID + pub xid: u32 @ 0..=31, + } +} + +impl CertStatVDO { + pub fn to_bytes(&self, buf: &mut [u8]) { + LittleEndian::write_u32(buf, self.0); + } +} + +bitfield! { + #[derive(Clone, Copy, PartialEq, Eq, Format)] + pub struct ProductVDO(pub u32): FromRaw, IntoRaw { + /// USB Product ID + pub pid: u16 @ 16..=31, + pub bcd_device: u16 @ 0..=15, + } +} + +impl ProductVDO { + pub fn to_bytes(&self, buf: &mut [u8]) { + LittleEndian::write_u32(buf, self.0); + } +} + bitfield! { #[derive(Clone, Copy, PartialEq, Eq, Format)] pub struct DisplayPortCapabilities(pub u32): Debug, FromRaw, IntoRaw { diff --git a/usb-pd/src/sink.rs b/usb-pd/src/sink.rs index 1227e85..175e81b 100644 --- a/usb-pd/src/sink.rs +++ b/usb-pd/src/sink.rs @@ -2,7 +2,7 @@ use { crate::{ header::{DataMessageType, Header, SpecificationRevision}, message::Message, - pdo::{FixedVariableRequestDataObject, PowerDataObject}, + pdo::{FixedVariableRequestDataObject, PowerDataObject, VDMHeader}, PowerRole, }, core::future::Future, @@ -38,6 +38,8 @@ pub enum Event { PowerRejected, /// Requested power is now ready PowerReady, + /// VDM received + VDMReceived((VDMHeader, Vec)), } /// Requests made to sink @@ -158,8 +160,8 @@ impl Sink { Some(Event::PowerReady) } Message::SourceCapabilities(caps) => Some(Event::SourceCapabilitiesChanged(caps)), - Message::VendorDefined(payload) => { - match payload { + Message::VendorDefined((hdr, data)) => { + match hdr { crate::pdo::VDMHeader::Structured(hdr) => { warn!( "UNHANDLED: Structured VDM! CMD_TYPE: {:?}, CMD: @@ -177,7 +179,7 @@ impl Sink { ); } } - None + Some(Event::VDMReceived((hdr, data))) } Message::SoftReset => { warn!("UNHANDLED: Soft RESET request.");