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#[derive(PartialEq, Clone, Copy)]
23pub enum DriverState {
24 Usb20,
26 UsbPdWait,
28 UsbPd,
30 UsbRetryWait,
32}
33
34pub enum DriverEvent {
36 StateChanged,
37 MessageReceived(Message),
38}
39
40pub struct Sink<DRIVER> {
41 driver: DRIVER,
42
43 protocol: Protocol,
44
45 requested_voltage: u16,
47
48 requested_max_current: u16,
50
51 active_voltage: u16,
53
54 active_max_current: u16,
56
57 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 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 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 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#[derive(Clone, Copy, PartialEq)]
186pub enum SupplyType {
187 Fixed = 0,
189 Battery = 1,
191 Variable = 2,
193 Pps = 3,
195}
196
197#[derive(PartialEq, Clone, Copy)]
199enum Protocol {
200 Usb20,
202 UsbPd,
204}