@@ -23,6 +23,7 @@ use async_std::sync::Arc;
23
23
use async_std:: task:: { sleep, spawn} ;
24
24
use serde:: { Deserialize , Serialize } ;
25
25
26
+ use crate :: adc:: CalibratedChannel ;
26
27
use crate :: broker:: { BrokerBuilder , Topic } ;
27
28
28
29
#[ cfg( feature = "demo_mode" ) ]
@@ -135,6 +136,45 @@ const PORTS: &[(&str, &str)] = &[
135
136
) ,
136
137
] ;
137
138
139
+ // The total current for all ports is limited to 700mA, the per-port current is
140
+ // limited to 500mA.
141
+ pub const MAX_TOTAL_CURRENT : f32 = 0.7 ;
142
+ pub const MAX_PORT_CURRENT : f32 = 0.5 ;
143
+
144
+ // The measurement is not _that_ exact so start warning at 90% utilization.
145
+ const CURRENT_MARGIN : f32 = 0.9 ;
146
+ const WARN_TOTAL_CURRENT : f32 = MAX_TOTAL_CURRENT * CURRENT_MARGIN ;
147
+ const WARN_PORT_CURRENT : f32 = MAX_PORT_CURRENT * CURRENT_MARGIN ;
148
+
149
+ #[ derive( Serialize , Deserialize , Clone , PartialEq ) ]
150
+ pub enum OverloadedPort {
151
+ Total ,
152
+ Port1 ,
153
+ Port2 ,
154
+ Port3 ,
155
+ }
156
+
157
+ impl OverloadedPort {
158
+ fn from_currents ( total : f32 , port1 : f32 , port2 : f32 , port3 : f32 ) -> Option < Self > {
159
+ // Based on the maximum / per-port limits it should not be possible for two
160
+ // individual ports to be overloaded at the same time while the total is not
161
+ // overloaded, so reporting either "total" or one of the ports should be
162
+ // sufficient.
163
+
164
+ if total > WARN_TOTAL_CURRENT {
165
+ Some ( Self :: Total )
166
+ } else if port1 > WARN_PORT_CURRENT {
167
+ Some ( Self :: Port1 )
168
+ } else if port2 > WARN_PORT_CURRENT {
169
+ Some ( Self :: Port2 )
170
+ } else if port3 > WARN_PORT_CURRENT {
171
+ Some ( Self :: Port3 )
172
+ } else {
173
+ None
174
+ }
175
+ }
176
+ }
177
+
138
178
#[ derive( Serialize , Deserialize , PartialEq , Clone ) ]
139
179
pub struct UsbDevice {
140
180
id_product : String ,
@@ -151,6 +191,7 @@ pub struct UsbPort {
151
191
}
152
192
153
193
pub struct UsbHub {
194
+ pub overload : Arc < Topic < Option < OverloadedPort > > > ,
154
195
pub port1 : UsbPort ,
155
196
pub port2 : UsbPort ,
156
197
pub port3 : UsbPort ,
@@ -236,11 +277,49 @@ fn handle_port(bb: &mut BrokerBuilder, name: &'static str, base: &'static str) -
236
277
port
237
278
}
238
279
280
+ fn handle_overloads (
281
+ bb : & mut BrokerBuilder ,
282
+ total : CalibratedChannel ,
283
+ port1 : CalibratedChannel ,
284
+ port2 : CalibratedChannel ,
285
+ port3 : CalibratedChannel ,
286
+ ) -> Arc < Topic < Option < OverloadedPort > > > {
287
+ let overload = bb. topic_ro ( "/v1/usb/host/overload" , None ) ;
288
+
289
+ let overload_task = overload. clone ( ) ;
290
+
291
+ spawn ( async move {
292
+ loop {
293
+ let overloaded_port = OverloadedPort :: from_currents (
294
+ total. get ( ) . map ( |m| m. value ) . unwrap_or ( 0.0 ) ,
295
+ port1. get ( ) . map ( |m| m. value ) . unwrap_or ( 0.0 ) ,
296
+ port2. get ( ) . map ( |m| m. value ) . unwrap_or ( 0.0 ) ,
297
+ port3. get ( ) . map ( |m| m. value ) . unwrap_or ( 0.0 ) ,
298
+ ) ;
299
+
300
+ overload_task. set_if_changed ( overloaded_port) ;
301
+
302
+ sleep ( POLL_INTERVAL ) . await ;
303
+ }
304
+ } ) ;
305
+
306
+ overload
307
+ }
308
+
239
309
impl UsbHub {
240
- pub fn new ( bb : & mut BrokerBuilder ) -> Self {
310
+ pub fn new (
311
+ bb : & mut BrokerBuilder ,
312
+ total : CalibratedChannel ,
313
+ port1 : CalibratedChannel ,
314
+ port2 : CalibratedChannel ,
315
+ port3 : CalibratedChannel ,
316
+ ) -> Self {
317
+ let overload = handle_overloads ( bb, total, port1, port2, port3) ;
318
+
241
319
let mut ports = PORTS . iter ( ) . map ( |( name, base) | handle_port ( bb, name, base) ) ;
242
320
243
321
Self {
322
+ overload,
244
323
port1 : ports. next ( ) . unwrap ( ) ,
245
324
port2 : ports. next ( ) . unwrap ( ) ,
246
325
port3 : ports. next ( ) . unwrap ( ) ,
0 commit comments