1use embassy_time::{Duration, Instant, Ticker, with_timeout};
3
4use crate::driver::pps::PpsDriver;
5pub use crate::driver::pps::{PpsError, PpsRunningMode};
6use crate::io::shared_i2c::SharedI2cBus;
7
8pub struct PpsReadings {
9 pub voltage: f32,
10 pub current: f32,
11 pub temperature: f32,
12 pub input_voltage: f32,
13 pub running_mode: PpsRunningMode,
14}
15
16pub struct PpsSetpoint {
17 pub current_limit: Option<f32>,
18 pub voltage_limit: Option<f32>,
19 pub enabled: Option<bool>,
20}
21
22pub struct PpsResources {
23 pub i2c: &'static SharedI2cBus,
24}
25
26const PPS_LOOP_TIME_MS: u64 = 500;
27
28async fn read_pps(pps: &mut PpsDriver) -> Result<PpsReadings, PpsError> {
29 let voltage = pps.get_voltage().await?;
30 let current = pps.get_current().await?;
31 let temperature = pps.get_temperature().await?;
32 let input_voltage = pps.get_input_voltage().await?;
33 let running_mode = pps.get_running_mode().await?;
34 Ok(PpsReadings {
35 voltage,
36 current,
37 temperature,
38 input_voltage,
39 running_mode,
40 })
41}
42
43async fn write_pps(pps: &mut PpsDriver, setpoint: &PpsSetpoint) -> Result<(), PpsError> {
44 debug!(
45 "write_pps: cl: {:?} vl: {:?} enabled: {:?}",
46 setpoint.current_limit, setpoint.voltage_limit, setpoint.enabled
47 );
48 if let Some(cl) = setpoint.current_limit {
49 pps.set_current(cl).await?;
50 }
51 if let Some(vl) = setpoint.voltage_limit {
52 pps.set_voltage(vl).await?;
53 }
54 match setpoint.enabled {
55 Some(en) => {
56 pps.enable(en).await?;
57 }
58 None => (),
59 }
60 Ok(())
61}
62
63async fn poll_pps(
64 pps: &mut PpsDriver,
65 on_read: fn(&PpsReadings),
66 get_setpoint: fn() -> PpsSetpoint,
67) -> Result<(), PpsError> {
68 let setpoint = get_setpoint();
69 write_pps(pps, &setpoint).await?;
70 let readings = read_pps(pps).await?;
71 on_read(&readings);
72 Ok(())
73}
74
75pub async fn pps_loop(
93 resources: PpsResources,
94 on_read: fn(&PpsReadings),
95 get_setpoint: fn() -> PpsSetpoint,
96) {
97 let mut pps = PpsDriver::new(resources.i2c, 0x35);
98 pps.enable(false).await.ok();
99
100 let mut ticker = Ticker::every(Duration::from_millis(PPS_LOOP_TIME_MS));
101 let mut error_count = 0;
102 loop {
103 let loop_start = Instant::now();
104 let timeout_result = with_timeout(
105 Duration::from_millis(PPS_LOOP_TIME_MS * 3),
106 poll_pps(&mut pps, on_read, get_setpoint),
107 )
108 .await;
109 match timeout_result {
110 Ok(poll_result) => match poll_result {
111 Ok(_) => {
112 error_count = 0;
113 }
114 Err(err) => {
115 warn!("PPS error: {}", err);
116 error_count += 1;
117 if error_count > 10 {
118 error!("stopping PPS task after 10 consecutive errors");
119 break;
120 }
121 }
122 },
123 Err(err) => {
124 error!("timeout in io i2c loop: {:?}", err);
125 ticker.reset_at(Instant::now() - Duration::from_millis(PPS_LOOP_TIME_MS));
126 }
127 }
128 let loop_time = loop_start.elapsed();
129 debug!("io loop time: {:?} ms", loop_time.as_millis());
130 ticker.next().await;
131 }
132}