1#![no_std]
2
3use core::marker::PhantomData;
4
5use embedded_hal::{
6 adc::{Channel, OneShot},
7 blocking::delay::DelayMs,
8};
9use num_traits::float::FloatCore;
11
12const NO_SAMPLES: usize = 30;
13const SAMPLE_INTERVAL_MS: u16 = 40;
14
15pub enum Error<AdcError> {
16 ReadError(AdcError),
17}
18
19fn median(mut data: [u16; NO_SAMPLES]) -> u16 {
20 data.sort_unstable();
21 return data[data.len() / 2];
22}
23
24pub struct TdsMeter<OneShotReader, Adc, Word, PinData, Delay>
25where
26 OneShotReader: OneShot<Adc, Word, PinData>,
27 PinData: Channel<Adc>,
28 Delay: DelayMs<u16>,
29{
30 adc: OneShotReader,
31 adc_range: u16,
32 adc_vref: f32,
33 pin_data: PinData,
34 _unused: PhantomData<Adc>,
35 _unused2: PhantomData<Word>,
36 _unused3: PhantomData<Delay>,
37}
38
39impl<OneShotReader, Adc, Word, PinData, Delay> TdsMeter<OneShotReader, Adc, Word, PinData, Delay>
40where
41 Word: Into<u16>,
42 OneShotReader: OneShot<Adc, Word, PinData>,
43 PinData: Channel<Adc>,
44 Delay: DelayMs<u16>,
45{
46 pub fn new(adc: OneShotReader, adc_range: u16, adc_vref: f32, pin_data: PinData) -> Self {
47 Self {
48 adc,
49 adc_range,
50 adc_vref,
51 pin_data,
52 _unused: PhantomData,
53 _unused2: PhantomData,
54 _unused3: PhantomData,
55 }
56 }
57
58 pub fn measure(
62 &mut self,
63 temperature: f32,
64 delay: &mut Delay,
65 ) -> Result<f32, Error<OneShotReader::Error>> {
66 let mut data: [u16; NO_SAMPLES] = [0; NO_SAMPLES];
67 for i in 0..NO_SAMPLES {
68 loop {
69 let read_result = self.adc.read(&mut self.pin_data);
70
71 match read_result {
72 Ok(word) => {
73 data[i] = word.into();
74 break;
75 }
76 Err(nb::Error::Other(failed)) => {
77 return Err(Error::ReadError(failed));
78 }
79 Err(nb::Error::WouldBlock) => continue,
80 };
81 }
82
83 delay.delay_ms(SAMPLE_INTERVAL_MS);
84 }
85
86 let average_data = median(data);
87 let voltage = (average_data as f32 / self.adc_range as f32) * self.adc_vref;
88
89 let compensation_coefficient = 1.0 + 0.02 * (temperature - 25.0);
91 let compensated_voltage = voltage / compensation_coefficient;
92
93 Ok((66.71 * compensated_voltage.powi(3))
94 + (-112.93 * compensated_voltage.powi(2))
95 + (428.695 * compensated_voltage))
96 }
97}