usb_pd/
sink.rs

1use crate::{
2    callback::{CallbackFn, Event as CallbackEvent, Response},
3    header::{DataMessageType, Header, SpecificationRevision},
4    message::Message,
5    pdo::FixedVariableRequestDataObject,
6    Instant, PowerRole,
7};
8
9pub trait Driver {
10    fn init(&mut self);
11
12    fn poll(&mut self, now: Instant);
13
14    fn get_event(&mut self) -> Option<DriverEvent>;
15
16    fn send_message(&mut self, header: Header, payload: &[u8]);
17
18    fn state(&mut self) -> DriverState;
19}
20
21/// Driver state
22#[derive(PartialEq, Clone, Copy)]
23pub enum DriverState {
24    /// VBUS is present, monitoring for activity on CC1/CC2
25    Usb20,
26    /// Activity on CC1/CC2 has been detected, waiting for first USB PD message
27    UsbPdWait,
28    /// Successful USB PD communication established
29    UsbPd,
30    /// Wait period after a failure
31    UsbRetryWait,
32}
33
34/// Event queue by FUSB302 instance for clients (such as `pd_sink`)
35pub enum DriverEvent {
36    StateChanged,
37    MessageReceived(Message),
38}
39
40pub struct Sink<DRIVER> {
41    driver: DRIVER,
42
43    protocol: Protocol,
44
45    /// Requested voltage (in mV)
46    requested_voltage: u16,
47
48    /// Requested maximum current (in mA)
49    requested_max_current: u16,
50
51    /// Active voltage (in mV)
52    active_voltage: u16,
53
54    /// Active maximum current (in mA)
55    active_max_current: u16,
56
57    /// Specification revision (of last message)
58    spec_rev: u8,
59
60    callback: CallbackFn,
61}
62
63impl<DRIVER: Driver> Sink<DRIVER> {
64    pub fn new(driver: DRIVER, callback: CallbackFn) -> Self {
65        Self {
66            driver,
67            protocol: Protocol::Usb20,
68            requested_voltage: 0,
69            requested_max_current: 0,
70            active_voltage: 5000,
71            active_max_current: 900,
72            spec_rev: 1,
73            callback,
74        }
75    }
76
77    pub fn init(&mut self) {
78        self.driver.init();
79        self.update_protocol();
80    }
81
82    pub fn poll(&mut self, now: Instant) {
83        // process events from PD controller
84        loop {
85            self.driver.poll(now);
86
87            let Some(evt) = self.driver.get_event() else {
88                break;
89            };
90
91            match evt {
92                DriverEvent::StateChanged => {
93                    if self.update_protocol() {
94                        self.notify(CallbackEvent::ProtocolChanged);
95                    }
96                }
97                DriverEvent::MessageReceived(message) => {
98                    self.handle_msg(message);
99                }
100            }
101        }
102    }
103
104    fn update_protocol(&mut self) -> bool {
105        let old_protocol = self.protocol;
106
107        if self.driver.state() == DriverState::UsbPd {
108            self.protocol = Protocol::UsbPd;
109        } else {
110            self.protocol = Protocol::Usb20;
111            self.active_voltage = 5000;
112            self.active_max_current = 900;
113        }
114
115        self.protocol != old_protocol
116    }
117
118    fn handle_msg(&mut self, message: Message) {
119        match message {
120            Message::Accept => self.notify(CallbackEvent::PowerAccepted),
121            Message::Reject => {
122                self.requested_voltage = 0;
123                self.requested_max_current = 0;
124                self.notify(CallbackEvent::PowerRejected);
125            }
126            Message::Ready => {
127                self.active_voltage = self.requested_voltage;
128                self.active_max_current = self.requested_max_current;
129                self.requested_voltage = 0;
130                self.requested_max_current = 0;
131                self.notify(CallbackEvent::PowerReady);
132            }
133            Message::SourceCapabilities(caps) => {
134                self.notify(CallbackEvent::SourceCapabilitiesChanged(caps))
135            }
136            Message::Unknown => unimplemented!(),
137        }
138    }
139
140    fn notify(&mut self, event: CallbackEvent) {
141        if let Some(response) = (self.callback)(event) {
142            match response {
143                Response::RequestPower { index, current } => self.request_power(current, index),
144            }
145        }
146    }
147
148    fn request_power(&mut self, max_current: u16, index: usize) {
149        // Create 'request' message
150        let mut payload = [0; 4];
151
152        self.set_request_payload_fixed(&mut payload, index as u8, max_current);
153
154        let header = Header(0)
155            .with_message_type_raw(DataMessageType::Request as u8)
156            .with_num_objects(1)
157            .with_spec_revision(SpecificationRevision::from(self.spec_rev))
158            .with_port_power_role(PowerRole::Sink);
159
160        // Send message
161        self.driver.send_message(header, &payload);
162    }
163
164    fn set_request_payload_fixed(&mut self, payload: &mut [u8], obj_pos: u8, mut current: u16) {
165        current = (current + 5) / 10;
166
167        if current > 0x3ff {
168            current = 0x3ff;
169        }
170
171        let obj_pos = obj_pos + 1;
172        assert!(obj_pos > 0b0000 && obj_pos <= 0b1110);
173
174        FixedVariableRequestDataObject(0)
175            .with_operating_current(current)
176            .with_maximum_operating_current(current)
177            .with_object_position(obj_pos)
178            .with_no_usb_suspend(true)
179            .with_usb_communications_capable(true)
180            .to_bytes(payload);
181    }
182}
183
184/// Power supply type
185#[derive(Clone, Copy, PartialEq)]
186pub enum SupplyType {
187    /// Fixed supply (Vmin = Vmax)
188    Fixed = 0,
189    /// Battery
190    Battery = 1,
191    /// Variable supply (non-battery)
192    Variable = 2,
193    /// Programmable power supply
194    Pps = 3,
195}
196
197/// Power deliver protocol
198#[derive(PartialEq, Clone, Copy)]
199enum Protocol {
200    /// No USB PD communication (5V only)
201    Usb20,
202    /// USB PD communication
203    UsbPd,
204}