1use esp_hal::{Async, i2c::master::I2c};
28use thiserror_no_std::Error;
29
30use crate::io::shared_i2c::SharedI2cBus;
31
32#[repr(u8)]
33#[derive(Debug, Default, Clone, Copy)]
34pub enum PpsRunningMode {
35 Off = 0,
36 Voltage = 1,
37 Current = 2,
38 #[default]
39 Unknown = 3,
40}
41
42impl PpsRunningMode {
43 pub fn from_u8(v: u8) -> Option<Self> {
44 match v {
45 0 => Some(Self::Off),
46 1 => Some(Self::Voltage),
47 2 => Some(Self::Current),
48 3 => Some(Self::Unknown),
49 _ => None,
50 }
51 }
52}
53
54#[derive(Debug, Error)]
55pub enum PpsError {
56 #[error("unknown error")]
57 Unknown,
58
59 #[error("Failed to read from PPS module")]
60 ReadError,
61
62 #[error("Command not implemented")]
63 UnsupportedCommand,
64
65 #[error("I2C master error: {0:?}")]
66 I2cMasterError(#[from] esp_hal::i2c::master::Error),
67}
68
69type I2cType = I2c<'static, Async>;
70
71#[allow(dead_code)]
72enum ReadCommand {
73 ModuleId,
74 GetRunningMode,
75 GetDataFlag,
76 ReadbackVoltage,
77 ReadbackCurrent,
78 GetTemperature,
79 GetInputVoltage,
80 GetAddress,
81 PsuUidW0,
82 PsuUidW1,
83 PsuUidW2,
84}
85
86pub enum ReadResult {
87 ModuleId(u16),
88 RunningMode(PpsRunningMode),
89 ReadbackVoltage(f32),
90 ReadbackCurrent(f32),
91 Temperature(f32),
92 InputVoltage(f32),
93}
94
95impl ReadCommand {
96 fn get_read_command(&self) -> (u8, usize) {
97 match self {
98 ReadCommand::ModuleId => (0x0, 2),
99 ReadCommand::GetRunningMode => (0x05, 1),
100 ReadCommand::GetDataFlag => (0x07, 1),
101 ReadCommand::ReadbackVoltage => (0x08, 4),
102 ReadCommand::ReadbackCurrent => (0x0c, 4),
103 ReadCommand::GetTemperature => (0x10, 4),
104 ReadCommand::GetInputVoltage => (0x14, 4),
105 ReadCommand::GetAddress => (0x50, 1),
106 ReadCommand::PsuUidW0 => (0x52, 4),
107 ReadCommand::PsuUidW1 => (0x56, 4),
108 ReadCommand::PsuUidW2 => (0x5a, 4),
109 }
110 }
111
112 fn evaluate_result(&self, buffer: &[u8; 4]) -> Result<ReadResult, PpsError> {
113 match self {
114 ReadCommand::ModuleId => Ok(ReadResult::ModuleId(
115 (buffer[1] as u16) << 8 | buffer[0] as u16,
116 )),
117 ReadCommand::GetRunningMode => Ok(ReadResult::RunningMode(
118 PpsRunningMode::from_u8(buffer[0]).ok_or(PpsError::Unknown)?,
119 )),
120 ReadCommand::ReadbackVoltage => {
121 Ok(ReadResult::ReadbackVoltage(f32::from_le_bytes(*buffer)))
122 }
123 ReadCommand::ReadbackCurrent => {
124 Ok(ReadResult::ReadbackCurrent(f32::from_le_bytes(*buffer)))
125 }
126 ReadCommand::GetTemperature => Ok(ReadResult::Temperature(f32::from_le_bytes(*buffer))),
127 ReadCommand::GetInputVoltage => {
128 Ok(ReadResult::InputVoltage(f32::from_le_bytes(*buffer)))
129 }
130 _ => Err(PpsError::UnsupportedCommand),
131 }
132 }
133
134 pub async fn receive_async(
135 self,
136 i2c: &mut I2cType,
137 address: u8,
138 ) -> Result<ReadResult, PpsError> {
139 let (cmd, bytes_to_read) = self.get_read_command();
140 let mut buffer = [0_u8; 4];
141 i2c.write_read_async(address, &[cmd], &mut buffer[..bytes_to_read])
142 .await?;
143 self.evaluate_result(&buffer)
144 }
145}
146
147#[derive(Debug)]
148enum WriteCommand {
149 ModuleEnable(bool),
150 SetVoltage(f32),
151 SetCurrent(f32),
152}
153
154impl WriteCommand {
155 fn get_write_command(&self, buffer: &mut [u8; 5]) -> usize {
156 match self {
157 WriteCommand::ModuleEnable(enable) => {
158 buffer[0] = 0x04;
159 buffer[1] = *enable as u8;
160 2
161 }
162 WriteCommand::SetVoltage(voltage) => {
163 buffer[0] = 0x18;
164 buffer[1..].copy_from_slice(voltage.to_le_bytes().as_slice());
165 5
166 }
167 WriteCommand::SetCurrent(current) => {
168 buffer[0] = 0x1c;
169 buffer[1..].copy_from_slice(current.to_le_bytes().as_slice());
170 5
171 }
172 }
173 }
174
175 pub async fn send_async(self, i2c: &mut I2cType, address: u8) -> Result<(), PpsError> {
176 debug!("send: {:?} to address 0x{:x}", self, address);
177 let mut buffer = [0x0_u8; 5];
178 let bytes_to_write = self.get_write_command(&mut buffer);
179 i2c.write_async(address, &buffer[..bytes_to_write]).await?;
180 Ok(())
181 }
182}
183
184pub struct PpsDriver {
185 i2c: &'static SharedI2cBus,
186 address: u8,
187}
188
189impl PpsDriver {
190 pub fn new(i2c: &'static SharedI2cBus, address: u8) -> Self {
191 Self { i2c, address }
192 }
193
194 pub async fn set_current(&mut self, current: f32) -> Result<&mut Self, PpsError> {
195 let cmd = WriteCommand::SetCurrent(current);
196 debug!("set current {}, sending command: {:?}", current, cmd);
197 let mut bus = self.i2c.lock().await;
198 cmd.send_async(&mut *bus, self.address).await?;
199 Ok(self)
200 }
201
202 pub async fn set_voltage(&mut self, voltage: f32) -> Result<&mut Self, PpsError> {
203 let cmd = WriteCommand::SetVoltage(voltage);
204 let mut bus = self.i2c.lock().await;
205 cmd.send_async(&mut *bus, self.address).await?;
206 Ok(self)
207 }
208
209 pub async fn enable(&mut self, enabled: bool) -> Result<&mut Self, PpsError> {
210 let cmd = WriteCommand::ModuleEnable(enabled);
211 let mut bus = self.i2c.lock().await;
212 cmd.send_async(&mut *bus, self.address).await?;
213 Ok(self)
214 }
215
216 pub async fn get_running_mode(&mut self) -> Result<PpsRunningMode, PpsError> {
217 let mut bus = self.i2c.lock().await;
218 match ReadCommand::GetRunningMode
219 .receive_async(&mut *bus, self.address)
220 .await?
221 {
222 ReadResult::RunningMode(mode) => Ok(mode),
223 _ => Err(PpsError::ReadError),
224 }
225 }
226
227 pub async fn get_voltage(&mut self) -> Result<f32, PpsError> {
228 let mut bus = self.i2c.lock().await;
229 match ReadCommand::ReadbackVoltage
230 .receive_async(&mut *bus, self.address)
231 .await?
232 {
233 ReadResult::ReadbackVoltage(voltage) => Ok(voltage),
234 _ => Err(PpsError::ReadError),
235 }
236 }
237
238 pub async fn get_current(&mut self) -> Result<f32, PpsError> {
239 let mut bus = self.i2c.lock().await;
240 match ReadCommand::ReadbackCurrent
241 .receive_async(&mut *bus, self.address)
242 .await?
243 {
244 ReadResult::ReadbackCurrent(current) => Ok(current),
245 _ => Err(PpsError::ReadError),
246 }
247 }
248
249 pub async fn get_temperature(&mut self) -> Result<f32, PpsError> {
250 let mut bus = self.i2c.lock().await;
251 match ReadCommand::GetTemperature
252 .receive_async(&mut *bus, self.address)
253 .await?
254 {
255 ReadResult::Temperature(temp) => Ok(temp),
256 _ => Err(PpsError::ReadError),
257 }
258 }
259
260 pub async fn get_input_voltage(&mut self) -> Result<f32, PpsError> {
261 let mut bus = self.i2c.lock().await;
262 match ReadCommand::GetInputVoltage
263 .receive_async(&mut *bus, self.address)
264 .await?
265 {
266 ReadResult::InputVoltage(voltage) => Ok(voltage),
267 _ => Err(PpsError::ReadError),
268 }
269 }
270
271 #[allow(dead_code)]
272 pub async fn get_module_id(&mut self) -> Result<u16, PpsError> {
273 let mut bus = self.i2c.lock().await;
274 match ReadCommand::ModuleId
275 .receive_async(&mut *bus, self.address)
276 .await?
277 {
278 ReadResult::ModuleId(id) => Ok(id),
279 _ => Err(PpsError::ReadError),
280 }
281 }
282}