rsiot/drivers_i2c/bmp180/
mod.rs

1//! Датчик давления BMP180
2
3mod calculate_values;
4
5use std::{sync::Arc, time::Duration};
6
7use serde::{Deserialize, Serialize};
8use tokio::{sync::Mutex, time::sleep};
9use tracing::{info, trace, warn};
10
11use crate::{
12    executor::CmpInOut,
13    message::{Message, MsgDataBound, PhyQuantity},
14};
15
16use super::{I2cSlaveAddress, RsiotI2cDriverBase};
17
18use calculate_values::calculate_values;
19
20pub struct BMP180<TMsg>
21where
22    TMsg: MsgDataBound,
23{
24    pub address: I2cSlaveAddress,
25    pub fn_output: fn(BMP180Data) -> Vec<Message<TMsg>>,
26    pub oversampling: BMP180Oversampling,
27    pub cmp_in_out: CmpInOut<TMsg>,
28}
29
30impl<TMsg> BMP180<TMsg>
31where
32    TMsg: MsgDataBound,
33{
34    pub async fn fn_process(&self, driver: Arc<Mutex<impl RsiotI2cDriverBase>>) {
35        let calibration_data: CalibrationData = loop {
36            let calibration_data = request_calibration_data(driver.clone(), self.address).await;
37            match calibration_data {
38                Ok(calibration_data) => break calibration_data.into(),
39                Err(err) => {
40                    warn!("Error getting calibration data for sensor BMP180: {}", err);
41                    sleep(Duration::from_secs(2)).await;
42                    continue;
43                }
44            }
45        };
46
47        loop {
48            let temperature = request_temperature(driver.clone(), self.address).await;
49            let Ok(temperature) = temperature else {
50                warn!("Error reading temperature from BMP180: {temperature:?}");
51                sleep(Duration::from_secs(2)).await;
52                continue;
53            };
54
55            let pressure = request_pressure(driver.clone(), self.address, self.oversampling).await;
56            let Ok(pressure) = pressure else {
57                warn!("Error reading pressure from BMP180: {pressure:?}");
58                sleep(Duration::from_secs(2)).await;
59                continue;
60            };
61
62            let values = calculate_values(
63                &calibration_data,
64                &temperature,
65                &pressure,
66                self.oversampling,
67            );
68            let msgs = (self.fn_output)(values);
69            for msg in msgs {
70                self.cmp_in_out.send_output(msg).await.unwrap();
71            }
72            sleep(Duration::from_secs(2)).await;
73        }
74    }
75}
76
77/// Запрос данных калибровки. Необходимо выполнить один раз при запуске
78async fn request_calibration_data(
79    driver: Arc<Mutex<impl RsiotI2cDriverBase>>,
80    address: I2cSlaveAddress,
81) -> Result<ResponseCalibrationData, String> {
82    let mut response;
83    {
84        let mut driver = driver.lock().await;
85        response = driver
86            .write_read(address, &[0xAA], 22, Duration::from_secs(2))
87            .await?;
88    }
89    swap_msb_lsb(&mut response);
90    let response =
91        bincode::deserialize::<ResponseCalibrationData>(&response).map_err(|e| e.to_string())?;
92    info!("Calibration data BMP180: {response:?}");
93    Ok(response)
94}
95
96/// Запрос на измерение температуры
97async fn request_temperature(
98    driver: Arc<Mutex<impl RsiotI2cDriverBase>>,
99    address: I2cSlaveAddress,
100) -> Result<ResponseUncompensatedTemperature, String> {
101    let mut response;
102    {
103        let mut driver = driver.lock().await;
104        driver
105            .write(address, &[0xF4, 0x2E], Duration::from_secs(2))
106            .await?;
107    }
108    sleep(Duration::from_millis(5)).await;
109    {
110        let mut driver = driver.lock().await;
111        response = driver
112            .write_read(address, &[0xF6], 2, Duration::from_secs(2))
113            .await?;
114    }
115    swap_msb_lsb(&mut response);
116    let response = bincode::deserialize::<ResponseUncompensatedTemperature>(&response)
117        .map_err(|e| e.to_string())?;
118    trace!("BMP180 temperature: {response:?}");
119    Ok(response)
120}
121
122/// Запрос на измерение давления
123#[allow(non_snake_case)]
124async fn request_pressure(
125    driver: Arc<Mutex<impl RsiotI2cDriverBase>>,
126    address: I2cSlaveAddress,
127    oversampling: BMP180Oversampling,
128) -> Result<ResponseUncompensatedPressure, String> {
129    let response;
130    let oversampling_command = match oversampling {
131        BMP180Oversampling::UltraLowPower => 0x34,
132        BMP180Oversampling::Standard => 0x74,
133        BMP180Oversampling::HighResolution => 0xB4,
134        BMP180Oversampling::UltraHighResolution => 0xF4,
135    };
136    {
137        let mut driver = driver.lock().await;
138        driver
139            .write(
140                address,
141                &[0xF4, oversampling_command],
142                Duration::from_secs(2),
143            )
144            .await?;
145    }
146    sleep(Duration::from_millis(26)).await;
147    {
148        let mut driver = driver.lock().await;
149        response = driver
150            .write_read(address, &[0xF6], 3, Duration::from_secs(2))
151            .await?;
152    }
153    let UP = (((response[0] as u32) << 16) + ((response[1] as u32) << 8) + response[2] as u32)
154        >> (8 - oversampling as u8);
155    let response = ResponseUncompensatedPressure { UP };
156    trace!("BMP180 pressure: {response:?}");
157    Ok(response)
158}
159
160#[allow(non_snake_case)]
161#[derive(Debug, Deserialize, Serialize)]
162struct ResponseCalibrationData {
163    AC1: i16,
164    AC2: i16,
165    AC3: i16,
166    AC4: u16,
167    AC5: u16,
168    AC6: u16,
169    B1: i16,
170    B2: i16,
171    MB: i16,
172    MC: i16,
173    MD: i16,
174}
175
176#[allow(non_snake_case)]
177struct CalibrationData {
178    AC1: f64,
179    AC2: f64,
180    AC3: f64,
181    AC4: f64,
182    AC5: f64,
183    AC6: f64,
184    B1: f64,
185    B2: f64,
186    #[allow(dead_code)]
187    MB: f64,
188    MC: f64,
189    MD: f64,
190}
191
192impl From<ResponseCalibrationData> for CalibrationData {
193    fn from(value: ResponseCalibrationData) -> Self {
194        CalibrationData {
195            AC1: value.AC1 as f64,
196            AC2: value.AC2 as f64,
197            AC3: value.AC3 as f64,
198            AC4: value.AC4 as f64,
199            AC5: value.AC5 as f64,
200            AC6: value.AC6 as f64,
201            B1: value.B1 as f64,
202            B2: value.B2 as f64,
203            MB: value.MB as f64,
204            MC: value.MC as f64,
205            MD: value.MD as f64,
206        }
207    }
208}
209
210#[allow(non_snake_case)]
211#[derive(Debug, Deserialize, Serialize)]
212struct ResponseUncompensatedTemperature {
213    UT: u16,
214}
215
216#[allow(non_snake_case)]
217#[derive(Debug, Deserialize, Serialize)]
218struct ResponseUncompensatedPressure {
219    UP: u32,
220}
221
222fn swap_msb_lsb(ve: &mut [u8]) {
223    let mut index = 0;
224    while index < ve.len() {
225        ve.swap(index, index + 1);
226        index += 2;
227    }
228}
229
230#[derive(Debug)]
231pub struct BMP180Data {
232    pub temperature: PhyQuantity,
233    pub pressure: PhyQuantity,
234    pub altitude: PhyQuantity,
235}
236
237/// Кол-во измерений для формирования значен
238#[derive(Clone, Copy, Debug)]
239pub enum BMP180Oversampling {
240    /// number of samples = 1
241    UltraLowPower = 0,
242    /// number of samples = 2
243    Standard = 1,
244    /// number of samples = 4
245    HighResolution = 2,
246    /// number of samples = 8
247    UltraHighResolution = 3,
248}