1#![warn(unsafe_code)]
72#![warn(missing_docs)]
73#![cfg_attr(not(test), no_std)]
74
75#[cfg(test)]
76mod test;
77
78use crate::command::Command;
79pub use crate::sample::*;
80use core::convert::TryFrom;
81use core::marker::PhantomData;
82use embedded_hal::{delay::DelayNs, i2c::I2c};
83pub use product_info::ProductIdentifier;
84use states::{
85 ContinuousSamplingState, IdleState, SleepState, SleepToIdle, ToDifferentialPressureSampling,
86 ToIdle, ToMassflowSampling, ToSleep,
87};
88
89pub mod command;
90pub mod product_info;
91pub mod sample;
92pub mod states;
93
94#[derive(Debug)]
96pub enum SdpError<I>
97where
98 I: I2c,
99{
100 Device(sensirion_i2c::i2c::Error<I>),
102 InvalidBufferSize,
104 InvalidVariant,
106 WakeUpWhileNotSleeping,
108 CannotWakeUp,
110 SampleError,
112 BufferTooSmall,
114}
115
116impl<I> From<sensirion_i2c::i2c::Error<I>> for SdpError<I>
117where
118 I: I2c,
119{
120 fn from(error: sensirion_i2c::i2c::Error<I>) -> Self {
121 SdpError::Device(error)
122 }
123}
124
125#[derive(Debug)]
127pub struct Sdp8xx<I2C, D, State> {
128 i2c: I2C,
130 address: u8,
132 delay: D,
134 state: PhantomData<State>,
136}
137
138impl<I, D> Sdp8xx<I, D, IdleState>
139where
140 I: I2c,
141 D: DelayNs,
142{
143 pub fn new(i2c: I, address: u8, delay: D) -> Self {
145 Self {
146 i2c,
147 address,
148 delay,
149 state: PhantomData::<IdleState>,
150 }
151 }
152
153 pub fn release(self) -> I {
155 self.i2c
156 }
157
158 fn send_command(&mut self, command: Command) -> Result<(), SdpError<I>> {
160 sensirion_i2c::i2c::write_command_u16(&mut self.i2c, self.address, command.into())
161 .map_err(|e| SdpError::Device(sensirion_i2c::i2c::Error::I2cWrite(e)))
162 }
163
164 pub fn read_product_id(&mut self) -> Result<ProductIdentifier, SdpError<I>> {
166 let mut buf = [0; 18];
167 self.send_command(Command::ReadProductId0)?;
169 self.send_command(Command::ReadProductId1)?;
170
171 self.i2c
172 .read(self.address, &mut buf)
173 .map_err(|e| SdpError::Device(sensirion_i2c::i2c::Error::I2cRead(e)))?;
174
175 Ok(ProductIdentifier::from(buf))
176 }
177
178 pub fn trigger_differential_pressure_sample(
181 &mut self,
182 ) -> Result<Sample<DifferentialPressure>, SdpError<I>> {
183 self.send_command(Command::TriggerDifferentialPressureRead)?;
184 self.delay.delay_ms(60);
185 let mut buffer = [0u8; 9];
186 sensirion_i2c::i2c::read_words_with_crc(&mut self.i2c, self.address, &mut buffer)?;
187 Sample::<DifferentialPressure>::try_from(buffer).map_err(|_| SdpError::SampleError)
188 }
189
190 pub fn trigger_mass_flow_sample(&mut self) -> Result<Sample<MassFlow>, SdpError<I>> {
193 self.send_command(Command::TriggerMassFlowRead)?;
194 self.delay.delay_ms(60);
195 let mut buffer = [0u8; 9];
196 sensirion_i2c::i2c::read_words_with_crc(&mut self.i2c, self.address, &mut buffer)?;
197 Sample::<MassFlow>::try_from(buffer).map_err(|_| SdpError::SampleError)
198 }
199
200 pub fn trigger_differential_pressure_sample_sync(
203 &mut self,
204 ) -> Result<Sample<DifferentialPressure>, SdpError<I>> {
205 self.send_command(Command::TriggerDifferentialPressureReadSync)?;
206 let mut buffer = [0u8; 9];
207 sensirion_i2c::i2c::read_words_with_crc(&mut self.i2c, self.address, &mut buffer)?;
208 Sample::<DifferentialPressure>::try_from(buffer).map_err(|_| SdpError::SampleError)
209 }
210
211 pub fn trigger_mass_flow_sample_sync(&mut self) -> Result<Sample<MassFlow>, SdpError<I>> {
214 self.send_command(Command::TriggerMassFlowReadSync)?;
215 let mut buffer = [0u8; 9];
216 sensirion_i2c::i2c::read_words_with_crc(&mut self.i2c, self.address, &mut buffer)?;
217 Sample::<MassFlow>::try_from(buffer).map_err(|_| SdpError::SampleError)
218 }
219
220 pub fn start_sampling_differential_pressure(
222 mut self,
223 averaging: bool,
224 ) -> ToDifferentialPressureSampling<I, D> {
225 let command = if averaging {
226 Command::SampleDifferentialPressureAveraging
227 } else {
228 Command::SampleDifferentialPressureRaw
229 };
230 self.send_command(command)?;
231 Ok(Sdp8xx {
232 i2c: self.i2c,
233 address: self.address,
234 delay: self.delay,
235 state: PhantomData::<ContinuousSamplingState<DifferentialPressure>>,
236 })
237 }
238
239 pub fn start_sampling_mass_flow(mut self, averaging: bool) -> ToMassflowSampling<I, D> {
241 let command = if averaging {
242 Command::SampleMassFlowAveraging
243 } else {
244 Command::SampleMassFlowRaw
245 };
246 self.send_command(command)?;
247 Ok(Sdp8xx {
248 i2c: self.i2c,
249 address: self.address,
250 delay: self.delay,
251 state: PhantomData::<ContinuousSamplingState<MassFlow>>,
252 })
253 }
254
255 pub fn go_to_sleep(mut self) -> ToSleep<I, D> {
257 self.send_command(Command::EnterSleepMode)?;
258 Ok(Sdp8xx {
259 i2c: self.i2c,
260 address: self.address,
261 delay: self.delay,
262 state: PhantomData::<SleepState>,
263 })
264 }
265}
266
267impl<I, D> Sdp8xx<I, D, SleepState>
268where
269 I: I2c,
270 D: DelayNs,
271{
272 pub fn wake_up(mut self) -> SleepToIdle<I, D> {
275 let _ = self.i2c.write(self.address, &[]);
278 self.delay.delay_ms(3);
279 if self.i2c.write(self.address, &[]).is_ok() {
280 return Err(SdpError::WakeUpWhileNotSleeping);
281 }
282 self.delay.delay_ms(3);
283 match self.i2c.write(self.address, &[]) {
284 Ok(_) => {}
285 Err(_) => return Err(SdpError::CannotWakeUp),
286 }
287 Ok(Sdp8xx {
288 i2c: self.i2c,
289 address: self.address,
290 delay: self.delay,
291 state: PhantomData::<IdleState>,
292 })
293 }
294
295 pub fn wake_up_poll(mut self) -> SleepToIdle<I, D> {
298 if self.i2c.write(self.address, &[]).is_ok() {
300 return Err(SdpError::WakeUpWhileNotSleeping);
301 }
302 loop {
303 if self.i2c.write(self.address, &[]).is_ok() {
305 break;
306 }
307 }
308 Ok(Sdp8xx {
309 i2c: self.i2c,
310 address: self.address,
311 delay: self.delay,
312 state: PhantomData::<IdleState>,
313 })
314 }
315}
316
317impl<I, D, T> Sdp8xx<I, D, ContinuousSamplingState<T>>
318where
319 I: I2c,
320 D: DelayNs,
321{
322 pub fn read_continuous_sample(&mut self) -> Result<Sample<T>, SdpError<I>> {
324 let mut buffer = [0u8; 9];
325 sensirion_i2c::i2c::read_words_with_crc(&mut self.i2c, self.address, &mut buffer)?;
327 Sample::try_from(buffer).map_err(|_| SdpError::SampleError)
328 }
329
330 pub fn stop_sampling(mut self) -> ToIdle<I, D> {
332 let bytes: [u8; 2] = Command::StopContinuousMeasurement.into();
333 self.i2c
334 .write(self.address, &bytes)
335 .map_err(|e| SdpError::Device(sensirion_i2c::i2c::Error::I2cWrite(e)))?;
336 Ok(Sdp8xx {
337 i2c: self.i2c,
338 address: self.address,
339 delay: self.delay,
340 state: PhantomData::<IdleState>,
341 })
342 }
343}