diff --git a/usb-pd/src/callback.rs b/usb-pd/src/callback.rs deleted file mode 100644 index 88e7378..0000000 --- a/usb-pd/src/callback.rs +++ /dev/null @@ -1,36 +0,0 @@ -use {crate::pdo::PowerDataObject, defmt::Format, heapless::Vec}; - -/// Type of the user's callback function -pub type CallbackFn = &'static (dyn Send + Sync + (Fn(Event) -> Option)); - -/// Callback event types -#[derive(Format)] -pub enum Event { - /// Power delivery protocol has changed - ProtocolChanged, - /// Source capabilities have changed (immediately request power) - SourceCapabilitiesChanged(Vec), - /// Requested power has been accepted (but not ready yet) - PowerAccepted, - /// Requested power has been rejected - PowerRejected, - /// Requested power is now ready - PowerReady, -} - -#[derive(Format)] -pub enum Protocol { - /// No USB-PD communication, USB 2.0 5V only - _20, - /// USB-PD communication - PD, -} - -#[derive(Format)] -pub enum Response { - RequestPower { - /// Index of the desired PowerDataObject - index: usize, - current: u16, - }, -} diff --git a/usb-pd/src/lib.rs b/usb-pd/src/lib.rs index ee99788..9654ec4 100644 --- a/usb-pd/src/lib.rs +++ b/usb-pd/src/lib.rs @@ -2,7 +2,6 @@ use core::ops::Not; -pub mod callback; pub mod header; pub mod message; pub mod pdo; diff --git a/usb-pd/src/sink.rs b/usb-pd/src/sink.rs index 8cad7c7..c681b9e 100644 --- a/usb-pd/src/sink.rs +++ b/usb-pd/src/sink.rs @@ -1,11 +1,11 @@ use crate::{ - callback::{CallbackFn, Event as CallbackEvent, Response}, header::{DataMessageType, Header, SpecificationRevision}, message::Message, pdo::FixedVariableRequestDataObject, Instant, PowerRole, }; use defmt::warn; +use {crate::pdo::PowerDataObject, defmt::Format, heapless::Vec}; pub trait Driver { fn init(&mut self); @@ -19,6 +19,31 @@ pub trait Driver { fn state(&mut self) -> DriverState; } +/// Sink events +#[derive(Format)] +pub enum Event { + /// Power delivery protocol has changed + ProtocolChanged, + /// Source capabilities have changed (immediately request power) + SourceCapabilitiesChanged(Vec), + /// Requested power has been accepted (but not ready yet) + PowerAccepted, + /// Requested power has been rejected + PowerRejected, + /// Requested power is now ready + PowerReady, +} + +/// Requests made to sink +#[derive(Format)] +pub enum Request { + RequestPower { + /// Index of the desired PowerDataObject + index: usize, + current: u16, + }, +} + /// Driver state #[derive(PartialEq, Clone, Copy)] pub enum DriverState { @@ -57,12 +82,10 @@ pub struct Sink { /// Specification revision (of last message) spec_rev: u8, - - callback: CallbackFn, } impl Sink { - pub fn new(driver: DRIVER, callback: CallbackFn) -> Self { + pub fn new(driver: DRIVER) -> Self { Self { driver, protocol: Protocol::Usb20, @@ -71,7 +94,6 @@ impl Sink { active_voltage: 5000, active_max_current: 900, spec_rev: 1, - callback, } } @@ -80,25 +102,30 @@ impl Sink { self.update_protocol(); } - pub fn poll(&mut self, now: Instant) { - // process events from PD controller - loop { - self.driver.poll(now); - - let Some(evt) = self.driver.get_event() else { - break; - }; - - match evt { - DriverEvent::StateChanged => { - if self.update_protocol() { - self.notify(CallbackEvent::ProtocolChanged); - } - } - DriverEvent::MessageReceived(message) => { - self.handle_msg(message); + /// Call continously until `None` is returned. + pub fn poll(&mut self, now: Instant) -> Option { + // poll inner driver + self.driver.poll(now); + + let Some(evt) = self.driver.get_event() else { + return None; + }; + + match evt { + DriverEvent::StateChanged => { + if self.update_protocol() { + Some(Event::ProtocolChanged) + } else { + None } } + DriverEvent::MessageReceived(message) => self.handle_msg(message), + } + } + + pub fn request(&mut self, request: Request) { + match request { + Request::RequestPower { index, current } => self.request_power(current, index), } } @@ -116,55 +143,49 @@ impl Sink { self.protocol != old_protocol } - fn handle_msg(&mut self, message: Message) { + fn handle_msg(&mut self, message: Message) -> Option { match message { - Message::Accept => self.notify(CallbackEvent::PowerAccepted), + Message::Accept => Some(Event::PowerAccepted), Message::Reject => { self.requested_voltage = 0; self.requested_max_current = 0; - self.notify(CallbackEvent::PowerRejected); + Some(Event::PowerRejected) } Message::Ready => { self.active_voltage = self.requested_voltage; self.active_max_current = self.requested_max_current; self.requested_voltage = 0; self.requested_max_current = 0; - self.notify(CallbackEvent::PowerReady); - } - Message::SourceCapabilities(caps) => { - self.notify(CallbackEvent::SourceCapabilitiesChanged(caps)) + Some(Event::PowerReady) } - Message::VendorDefined(payload) => match payload { - crate::pdo::VDMHeader::Structured(hdr) => { - warn!( - "UNHANDLED: Structured VDM! CMD_TYPE: {:?}, CMD: {:?}", - hdr.command_type(), - hdr.command() - ); - } - crate::pdo::VDMHeader::Unstructured(hdr) => { - warn!( - "UNHANDLED: Unstructured VDM! SVID: {:x}, DATA: {:x}", - hdr.standard_or_vid(), - hdr.data() - ); + Message::SourceCapabilities(caps) => Some(Event::SourceCapabilitiesChanged(caps)), + Message::VendorDefined(payload) => { + match payload { + crate::pdo::VDMHeader::Structured(hdr) => { + warn!( + "UNHANDLED: Structured VDM! CMD_TYPE: {:?}, CMD: {:?}", + hdr.command_type(), + hdr.command() + ); + } + crate::pdo::VDMHeader::Unstructured(hdr) => { + warn!( + "UNHANDLED: Unstructured VDM! SVID: {:x}, DATA: {:x}", + hdr.standard_or_vid(), + hdr.data() + ); + } } - }, + None + } Message::SoftReset => { warn!("UNHANDLED: Soft RESET request."); + None } Message::Unknown => unimplemented!(), } } - fn notify(&mut self, event: CallbackEvent) { - if let Some(response) = (self.callback)(event) { - match response { - Response::RequestPower { index, current } => self.request_power(current, index), - } - } - } - fn request_power(&mut self, max_current: u16, index: usize) { // Create 'request' message let mut payload = [0; 4]; @@ -215,7 +236,7 @@ pub enum SupplyType { } /// Power deliver protocol -#[derive(PartialEq, Clone, Copy)] +#[derive(Format, PartialEq, Clone, Copy)] enum Protocol { /// No USB PD communication (5V only) Usb20, diff --git a/zy12pdn/src/main.rs b/zy12pdn/src/main.rs index 2c15469..c512cc2 100644 --- a/zy12pdn/src/main.rs +++ b/zy12pdn/src/main.rs @@ -18,9 +18,8 @@ use { timers::Timer, }, usb_pd::{ - callback::{Event, Response}, pdo::PowerDataObject, - sink::Sink, + sink::{Event, Request, Sink}, }, }; @@ -31,9 +30,10 @@ type PdSink = Sink>, PA9> #[app(device = stm32f0xx_hal::pac, peripherals = true, dispatchers = [SPI1])] mod app { + use crate::handle_event; + use { crate::{ - callback, rgb::{Color, Rgb}, Led, PdSink, }, @@ -121,7 +121,7 @@ mod app { let mut pd = { let clk = Timer::tim3(cx.device.TIM3, 400.khz(), &mut rcc); let i2c = I2cBB::new(scl, sda, clk); - Sink::new(Fusb302b::new(i2c), &callback) + Sink::new(Fusb302b::new(i2c)) }; pd.init(); @@ -138,7 +138,14 @@ mod app { #[idle(local = [pd])] fn idle(cx: idle::Context) -> ! { loop { - cx.local.pd.poll(monotonics::now()); + cx.local + .pd + // poll PD driver + .poll(monotonics::now()) + // handle event if one was returned from sink + .and_then(handle_event) + // make request if one was returned from handler + .map(|req| cx.local.pd.request(req)); } } @@ -154,7 +161,7 @@ mod app { } } -fn callback(event: Event) -> Option { +fn handle_event(event: Event) -> Option { match event { Event::SourceCapabilitiesChanged(caps) => { info!("Capabilities changed: {}", caps.len()); @@ -181,7 +188,7 @@ fn callback(event: Event) -> Option { info!("requesting supply {:?}@{}", supply, index); - return Some(Response::RequestPower { + return Some(Request::RequestPower { index, current: supply.max_current() * 10, });