bme68x_rust/
bme68x.rs

1use core::ffi;
2
3use crate::interface::{check_rslt, Error, Interface};
4use crate::internal::*;
5
6/// Operation mode of the sensor.
7#[derive(PartialEq)]
8pub enum OperationMode {
9    /// No measurements are performed. Minimal power consumption.
10    Sleep = 0,
11    /// Single TPHG cycle is performed. Gas sensor heater only operates during gas measurement.
12    /// Returns to Sleep afterwards.
13    Forced = 1,
14    /// Multiple TPHG cycles are performed. Gas sensor heater operates in parallel to TPH
15    /// measurement. Does not return to Sleep Mode.
16    Parallel = 2,
17    Sequential = 3,
18}
19
20/// ODR/Standby time macros
21#[repr(u8)]
22pub enum Odr {
23    /// Standby time of 0.59ms
24    Standby0_59Ms = 0,
25    /// Standby time of 62.5ms
26    Standby62_5Ms = 1,
27    /// Standby time of 125ms
28    Standby125Ms = 2,
29    /// Standby time of 250ms
30    Standby250Ms = 3,
31    /// Standby time of 500ms
32    Standby500Ms = 4,
33    /// Standby time of 1s
34    Standby1000Ms = 5,
35    /// Standby time of 10ms
36    Standby10Ms = 6,
37    /// Standby time of 20ms
38    Standby20Ms = 7,
39    /// No standby time
40    StandbyNone = 8,
41}
42
43/// Possible IIR Filter settings
44#[repr(u8)]
45pub enum Filter {
46    /// Switch off the filter
47    Off = 0u8,
48    /// Filter coefficient of 2
49    Size1 = 1,
50    /// Filter coefficient of 4
51    Size3 = 2,
52    /// Filter coefficient of 8
53    Size7 = 3,
54    /// Filter coefficient of 16
55    Size15 = 4,
56    /// Filter coefficient of 32
57    Size31 = 5,
58    /// Filter coefficient of 64
59    Size63 = 6,
60    /// Filter coefficient of 128
61    Size127 = 7,
62}
63
64/// Hardware communication interface (SPI & I2C)
65#[derive(Copy, Clone, Debug, PartialEq)]
66pub enum CommInterface {
67    SPI = 0,
68    I2C = 1,
69}
70
71#[derive(Copy, Clone, Default)]
72#[repr(C)]
73pub struct SensorData {
74    pub status: u8,
75    pub gas_index: u8,
76    pub meas_index: u8,
77    pub res_heat: u8,
78    pub idac: u8,
79    pub gas_wait: u8,
80    pub temperature: ffi::c_float,
81    pub pressure: ffi::c_float,
82    pub humidity: ffi::c_float,
83    pub gas_resistance: ffi::c_float,
84}
85
86#[derive(Debug, Copy, Clone, Default)]
87#[repr(C)]
88pub struct CalibrationData {
89    pub par_h1: u16,
90    pub par_h2: u16,
91    pub par_h3: i8,
92    pub par_h4: i8,
93    pub par_h5: i8,
94    pub par_h6: u8,
95    pub par_h7: i8,
96    pub par_gh1: i8,
97    pub par_gh2: i16,
98    pub par_gh3: i8,
99    pub par_t1: u16,
100    pub par_t2: i16,
101    pub par_t3: i8,
102    pub par_p1: u16,
103    pub par_p2: i16,
104    pub par_p3: i8,
105    pub par_p4: i16,
106    pub par_p5: i16,
107    pub par_p6: i8,
108    pub par_p7: i8,
109    pub par_p8: i16,
110    pub par_p9: i16,
111    pub par_p10: u8,
112    pub t_fine: ffi::c_float,
113    pub res_heat_range: u8,
114    pub res_heat_val: i8,
115    pub range_sw_err: i8,
116}
117
118#[derive(Copy, Clone, Default)]
119/// Sensor settings structure
120pub struct DeviceConfig {
121    os_hum: u8,
122    /// Temperature oversampling.
123    os_temp: u8,
124    /// Pressure oversampling.
125    os_pres: u8,
126    /// Filter coefficient.
127    filter: u8,
128    /// Standby time between sequential mode measurement profiles.
129    odr: u8,
130}
131
132/// Oversampling setting
133pub enum Sample {
134    /// Switch off measurements
135    Off = 0,
136    /// Perform 1 measurement
137    Once = 1,
138    /// Perform 2 measurements
139    X2 = 2,
140    /// Perform 4 measurements
141    X4 = 3,
142    /// Perform 8 measurements
143    X8 = 4,
144    /// Perform 16 measurements
145    X16 = 5,
146}
147
148impl DeviceConfig {
149    pub fn filter(&self, filter: Filter) -> Self {
150        let mut conf = *self;
151        conf.filter = filter as u8;
152        conf
153    }
154    pub fn odr(&self, odr: Odr) -> Self {
155        let mut conf = *self;
156        conf.odr = odr as u8;
157        conf
158    }
159    pub fn oversample_humidity(&self, h: Sample) -> Self {
160        let mut conf = *self;
161        conf.os_hum = h as u8;
162        conf
163    }
164    pub fn oversample_pressure(&self, p: Sample) -> Self {
165        let mut conf = *self;
166        conf.os_pres = p as u8;
167        conf
168    }
169    pub fn oversample_temperature(&self, t: Sample) -> Self {
170        let mut conf = *self;
171        conf.os_temp = t as u8;
172        conf
173    }
174}
175
176#[derive(Copy, Clone)]
177#[repr(C)]
178pub struct GasHeaterConfig {
179    pub(crate) enable: u8,
180    pub(crate) heatr_temp: u16,
181    pub(crate) heatr_dur: u16,
182    pub(crate) heatr_temp_prof: *mut u16,
183    pub(crate) heatr_dur_prof: *mut u16,
184    pub(crate) profile_len: u8,
185    pub(crate) shared_heatr_dur: u16,
186}
187
188impl GasHeaterConfig {
189    pub fn enable(&self) -> Self {
190        let mut conf = *self;
191        conf.enable = true as u8;
192        conf
193    }
194    pub fn heater_temp(&self, temp: u16) -> Self {
195        let mut conf = *self;
196        conf.heatr_temp = temp;
197        conf
198    }
199    pub fn heater_duration(&self, duration: u16) -> Self {
200        let mut conf = *self;
201        conf.heatr_dur = duration;
202        conf
203    }
204    pub fn disable(&self) -> Self {
205        let mut conf = *self;
206        conf.enable = false as u8;
207        conf
208    }
209}
210
211impl Default for GasHeaterConfig {
212    fn default() -> Self {
213        Self {
214            enable: 0,
215            heatr_temp: 0,
216            heatr_dur: 0,
217            heatr_temp_prof: 0 as *mut u16,
218            heatr_dur_prof: 0 as *mut u16,
219            profile_len: 0,
220            shared_heatr_dur: 0,
221        }
222    }
223}
224
225/// BME68x Device Controller
226///
227/// ```
228///  let mut bme = Device::initialize(SpiDriver {
229///      spicl: args.spicl,
230///      tty: args.tty,
231///  })?;
232///
233///  bme.set_config(DeviceConfigig::default()
234///                  .filter(0)
235///                  .odr(8)
236///                  .oversample_humidity(5)
237///                  .oversample_pressure(1)
238///                  .oversample_temperature(2))?;
239/// ```
240///
241pub struct Device<I: Interface> {
242    pub interface: I,
243    pub config: DeviceConfig,
244    pub gas_heater_config: GasHeaterConfig,
245    pub(crate) variant_id: u32,
246    pub(crate) mem_page: u8,
247    pub(crate) amb_temp: i8,
248    pub(crate) calib: CalibrationData,
249    pub(crate) interface_result: i8,
250    pub(crate) info_msg: u8,
251}
252
253impl<I: Interface> Device<I> {
254    /// Initialization.
255    ///
256    /// Reads the chip-id of the sensor which is the first step to verify the sensor
257    /// and also calibrates the sensor.
258    pub fn initialize(interface: I) -> Result<Self, Error> {
259        // NOTE moved amb_temp from bme68x_interface_init since everything else that function did
260        // is now contained within the interface trait.
261        let amb_temp = 25;
262        let mut device = Self {
263            variant_id: 0,
264            interface,
265            mem_page: 0,
266            amb_temp,
267            gas_heater_config: GasHeaterConfig::default(),
268            config: DeviceConfig::default(),
269            calib: CalibrationData::default(),
270            interface_result: 0,
271            info_msg: 0,
272        };
273
274        device.soft_reset()?;
275        let mut chip_id = 0;
276        device.get_regs(
277            0xd0 as ffi::c_int as u8,
278            &mut chip_id,
279            1 as ffi::c_int as u32,
280        )?;
281        let mut rslt: i8 = 0;
282        if chip_id == 0x61 {
283            rslt = read_variant_id(&mut device);
284            if rslt as ffi::c_int == 0 as ffi::c_int {
285                rslt = get_calib_data(&mut device);
286            }
287        } else {
288            rslt = -(3 as ffi::c_int) as i8;
289        }
290        check_rslt(rslt)?;
291        Ok(device)
292    }
293
294    /// Writes the given data to the register address of the sensor.
295    pub(crate) fn set_regs(
296        &mut self,
297        reg_addr: *const u8,
298        reg_data: *const u8,
299        len: u32,
300    ) -> Result<(), Error> {
301        unsafe {
302            let mut rslt: i8 = 0;
303            let mut tmp_buff: [u8; 20] = [0; 20];
304            let mut index: u16 = 0;
305            rslt = null_ptr_check(self);
306            if rslt as ffi::c_int == 0 as ffi::c_int && !reg_addr.is_null() && !reg_data.is_null() {
307                if len > 0 as ffi::c_int as ffi::c_uint
308                    && len <= (20 as ffi::c_int / 2 as ffi::c_int) as ffi::c_uint
309                {
310                    index = 0 as ffi::c_int as u16;
311                    while (index as ffi::c_uint) < len {
312                        if (*self).interface.interface_type() == CommInterface::SPI {
313                            rslt = set_mem_page(*reg_addr.offset(index as isize), self);
314                            tmp_buff[(2 as ffi::c_int * index as ffi::c_int) as usize] =
315                                (*reg_addr.offset(index as isize) as ffi::c_int
316                                    & 0x7f as ffi::c_int) as u8;
317                        } else {
318                            tmp_buff[(2 as ffi::c_int * index as ffi::c_int) as usize] =
319                                *reg_addr.offset(index as isize);
320                        }
321                        tmp_buff
322                            [(2 as ffi::c_int * index as ffi::c_int + 1 as ffi::c_int) as usize] =
323                            *reg_data.offset(index as isize);
324                        index = index.wrapping_add(1);
325                    }
326                    if rslt as ffi::c_int == 0 as ffi::c_int {
327                        (*self).interface_result = (*self).interface.write_raw(
328                            tmp_buff[0],
329                            &mut *tmp_buff.as_mut_ptr().offset(1 as ffi::c_int as isize),
330                            (2 as ffi::c_int as ffi::c_uint)
331                                .wrapping_mul(len)
332                                .wrapping_sub(1 as ffi::c_int as ffi::c_uint),
333                        );
334                        if (*self).interface_result as ffi::c_int != 0 as ffi::c_int {
335                            rslt = -(2 as ffi::c_int) as i8;
336                        }
337                    }
338                } else {
339                    rslt = -(4 as ffi::c_int) as i8;
340                }
341            } else {
342                rslt = -(1 as ffi::c_int) as i8;
343            }
344            check_rslt(rslt)
345        }
346    }
347
348    /// Reads the data from the given register address of sensor.
349    pub(crate) fn get_regs(
350        &mut self,
351        mut reg_addr: u8,
352        reg_data: *mut u8,
353        len: u32,
354    ) -> Result<(), Error> {
355        unsafe {
356            let mut rslt: i8 = 0;
357            rslt = null_ptr_check(self);
358            if rslt as ffi::c_int == 0 as ffi::c_int && !reg_data.is_null() {
359                if (*self).interface.interface_type() == CommInterface::SPI {
360                    rslt = set_mem_page(reg_addr, self);
361                    if rslt as ffi::c_int == 0 as ffi::c_int {
362                        reg_addr = (reg_addr as ffi::c_int | 0x80 as ffi::c_int) as u8;
363                    }
364                }
365                (*self).interface_result = (*self).interface.read_raw(reg_addr, reg_data, len);
366                if (*self).interface_result as ffi::c_int != 0 as ffi::c_int {
367                    rslt = -(2 as ffi::c_int) as i8;
368                }
369            } else {
370                rslt = -(1 as ffi::c_int) as i8;
371            }
372            check_rslt(rslt)
373        }
374    }
375
376    /// Triggers a soft-resets of the sensor.
377    pub fn soft_reset(&mut self) -> Result<(), Error> {
378        unsafe {
379            let mut rslt: i8 = 0;
380            let mut reg_addr: u8 = 0xe0 as ffi::c_int as u8;
381            let mut soft_rst_cmd: u8 = 0xb6 as ffi::c_int as u8;
382            rslt = null_ptr_check(self);
383            if rslt as ffi::c_int == 0 as ffi::c_int {
384                if (*self).interface.interface_type() == CommInterface::SPI {
385                    rslt = get_mem_page(self);
386                }
387                if rslt as ffi::c_int == 0 as ffi::c_int {
388                    self.set_regs(&mut reg_addr, &mut soft_rst_cmd, 1 as ffi::c_int as u32)?;
389                    (*self).interface.delay(10000 as ffi::c_uint);
390                    if (*self).interface.interface_type() == CommInterface::SPI {
391                        rslt = get_mem_page(self);
392                    }
393                }
394            }
395            check_rslt(rslt)
396        }
397    }
398
399    /// Used to set the oversampling, filter and odr configuration.
400    pub fn set_config(&mut self, conf: DeviceConfig) -> Result<(), Error> {
401        self.config = conf;
402        unsafe {
403            let mut rslt: i8 = 0;
404            let mut odr20: u8 = 0;
405            let mut odr3: u8 = 1;
406            let mut reg_array: [u8; 5] = [0x71, 0x72, 0x73, 0x74, 0x75];
407            let mut data_array: [u8; 5] = [0, 0, 0, 0, 0];
408            let current_op_mode = self.get_op_mode()?;
409            self.set_op_mode(OperationMode::Sleep)?;
410            self.get_regs(reg_array[0], data_array.as_mut_ptr(), 5)?;
411            (*self).info_msg = 0 as u8;
412            if rslt == 0 {
413                rslt = boundary_check(&mut self.config.filter, 7 as u8, self);
414            }
415            if rslt == 0 {
416                rslt = boundary_check(&mut self.config.os_temp, 5 as u8, self);
417            }
418            if rslt == 0 {
419                rslt = boundary_check(&mut self.config.os_pres, 5 as u8, self);
420            }
421            if rslt == 0 {
422                rslt = boundary_check(&mut self.config.os_hum, 5 as u8, self);
423            }
424            if rslt == 0 {
425                rslt = boundary_check(&mut self.config.odr, 8 as u8, self);
426            }
427            if rslt == 0 {
428                data_array[4] = (data_array[4] as ffi::c_int & !(0x1c as ffi::c_int)
429                    | (self.config.filter as ffi::c_int) << 2 as ffi::c_int & 0x1c as ffi::c_int)
430                    as u8;
431                data_array[3] = (data_array[3] as ffi::c_int & !(0xe0 as ffi::c_int)
432                    | (self.config.os_temp as ffi::c_int) << 5 as ffi::c_int & 0xe0 as ffi::c_int)
433                    as u8;
434                data_array[3] = (data_array[3] as ffi::c_int & !(0x1c as ffi::c_int)
435                    | (self.config.os_pres as ffi::c_int) << 2 as ffi::c_int & 0x1c as ffi::c_int)
436                    as u8;
437                data_array[1] = (data_array[1] as ffi::c_int & !(0x7 as ffi::c_int)
438                    | self.config.os_hum as ffi::c_int & 0x7 as ffi::c_int)
439                    as u8;
440                if self.config.odr as ffi::c_int != 8 as ffi::c_int {
441                    odr20 = self.config.odr;
442                    odr3 = 0 as ffi::c_int as u8;
443                }
444                data_array[4] = (data_array[4] as ffi::c_int & !(0xe0 as ffi::c_int)
445                    | (odr20 as ffi::c_int) << 5 as ffi::c_int & 0xe0 as ffi::c_int)
446                    as u8;
447                data_array[0] = (data_array[0] as ffi::c_int & !(0x80 as ffi::c_int)
448                    | (odr3 as ffi::c_int) << 7 as ffi::c_int & 0x80 as ffi::c_int)
449                    as u8;
450            }
451            if rslt == 0 {
452                self.set_regs(reg_array.as_mut_ptr(), data_array.as_mut_ptr(), 5)?;
453            }
454            if current_op_mode != OperationMode::Sleep && rslt == 0 {
455                self.set_op_mode(current_op_mode)?;
456            }
457            return check_rslt(rslt);
458        }
459    }
460
461    /// Used to get the oversampling, filter and odr configurations.
462    pub fn get_conf(&mut self, mut conf: &mut DeviceConfig) -> Result<(), Error> {
463        let reg_addr: u8 = 0x71 as ffi::c_int as u8;
464        let mut data_array: [u8; 5] = [0; 5];
465        self.get_regs(reg_addr, data_array.as_mut_ptr(), 5 as ffi::c_int as u32)?;
466        (*conf).os_hum = (data_array[1] as ffi::c_int & 0x7 as ffi::c_int) as u8;
467        (*conf).filter =
468            ((data_array[4] as ffi::c_int & 0x1c as ffi::c_int) >> 2 as ffi::c_int) as u8;
469        (*conf).os_temp =
470            ((data_array[3] as ffi::c_int & 0xe0 as ffi::c_int) >> 5 as ffi::c_int) as u8;
471        (*conf).os_pres =
472            ((data_array[3] as ffi::c_int & 0x1c as ffi::c_int) >> 2 as ffi::c_int) as u8;
473        if (data_array[0] as ffi::c_int & 0x80 as ffi::c_int) >> 7 as ffi::c_int != 0 {
474            (*conf).odr = 8 as ffi::c_int as u8;
475        } else {
476            (*conf).odr =
477                ((data_array[4] as ffi::c_int & 0xe0 as ffi::c_int) >> 5 as ffi::c_int) as u8;
478        }
479        Ok(())
480    }
481
482    /// Used to set the operation mode of the sensor.
483    pub fn set_op_mode(&mut self, op_mode: OperationMode) -> Result<(), Error> {
484        let op_mode = op_mode as u8;
485        let mut tmp_pow_mode: u8 = 0;
486        let mut reg_addr: u8 = 0x74 as ffi::c_int as u8;
487        loop {
488            self.get_regs(
489                0x74 as ffi::c_int as u8,
490                &mut tmp_pow_mode,
491                1 as ffi::c_int as u32,
492            )?;
493            let pow_mode = (tmp_pow_mode as ffi::c_int & 0x3 as ffi::c_int) as u8;
494            if pow_mode as ffi::c_int != 0 as ffi::c_int {
495                tmp_pow_mode = (tmp_pow_mode as ffi::c_int & !(0x3 as ffi::c_int)) as u8;
496                self.set_regs(&mut reg_addr, &mut tmp_pow_mode, 1 as ffi::c_int as u32)?;
497                (*self).interface.delay(10000 as ffi::c_uint);
498            }
499            if !(pow_mode as ffi::c_int != 0 as ffi::c_int) {
500                break;
501            }
502        }
503        if op_mode as ffi::c_int != 0 as ffi::c_int {
504            tmp_pow_mode = (tmp_pow_mode as ffi::c_int & !(0x3 as ffi::c_int)
505                | op_mode as ffi::c_int & 0x3 as ffi::c_int) as u8;
506            self.set_regs(&mut reg_addr, &mut tmp_pow_mode, 1 as ffi::c_int as u32)?;
507        }
508        Ok(())
509    }
510
511    /// Used to get the operation mode of the sensor.
512    pub fn get_op_mode(&mut self) -> Result<OperationMode, Error> {
513        let mut mode: u8 = 0;
514        self.get_regs(0x74 as ffi::c_int as u8, &mut mode, 1 as ffi::c_int as u32)?;
515        let op_mode = (mode as ffi::c_int & 0x3 as ffi::c_int) as u8;
516        Ok(match op_mode {
517            0 => OperationMode::Sleep,
518            1 => OperationMode::Forced,
519            2 => OperationMode::Parallel,
520            _ => unreachable!(),
521        })
522    }
523
524    /// Used to get the remaining duration that can be used for heating.
525    pub fn get_measure_duration(&mut self, op_mode: OperationMode) -> u32 {
526        unsafe {
527            let mut rslt: i8 = 0;
528            let mut meas_dur: u32 = 0 as ffi::c_int as u32;
529            let mut meas_cycles: u32 = 0;
530            let os_to_meas_cycles: [u8; 6] = [
531                0 as ffi::c_int as u8,
532                1 as ffi::c_int as u8,
533                2 as ffi::c_int as u8,
534                4 as ffi::c_int as u8,
535                8 as ffi::c_int as u8,
536                16 as ffi::c_int as u8,
537            ];
538            rslt = boundary_check(&mut self.config.os_temp, 5 as ffi::c_int as u8, self);
539            if rslt as ffi::c_int == 0 as ffi::c_int {
540                rslt = boundary_check(&mut self.config.os_pres, 5 as ffi::c_int as u8, self);
541            }
542            if rslt as ffi::c_int == 0 as ffi::c_int {
543                rslt = boundary_check(&mut self.config.os_hum, 5 as ffi::c_int as u8, self);
544            }
545            if rslt as ffi::c_int == 0 as ffi::c_int {
546                meas_cycles = os_to_meas_cycles[self.config.os_temp as usize] as u32;
547                meas_cycles = (meas_cycles as ffi::c_uint)
548                    .wrapping_add(os_to_meas_cycles[self.config.os_pres as usize] as ffi::c_uint)
549                    as u32 as u32;
550                meas_cycles = (meas_cycles as ffi::c_uint)
551                    .wrapping_add(os_to_meas_cycles[self.config.os_hum as usize] as ffi::c_uint)
552                    as u32 as u32;
553                meas_dur = meas_cycles.wrapping_mul(1963 as ffi::c_uint);
554                meas_dur = (meas_dur as ffi::c_uint)
555                    .wrapping_add((477 as ffi::c_int as ffi::c_uint).wrapping_mul(4 as ffi::c_uint))
556                    as u32 as u32;
557                meas_dur = (meas_dur as ffi::c_uint)
558                    .wrapping_add((477 as ffi::c_int as ffi::c_uint).wrapping_mul(5 as ffi::c_uint))
559                    as u32 as u32;
560                if op_mode != OperationMode::Parallel {
561                    meas_dur = (meas_dur as ffi::c_uint).wrapping_add(1000 as ffi::c_uint) as u32;
562                }
563            }
564            return meas_dur;
565        }
566    }
567
568    /// Reads the pressure, temperature humidity and gas data from the sensor,
569    /// compensates the data and store it in the SensorData structure instance passed by the user.
570    ///
571    /// TODO refactor and make safer.
572    pub fn get_data(
573        &mut self,
574        op_mode: u8,
575        data: *mut SensorData,
576        n_data: &mut u8,
577    ) -> Result<(), Error> {
578        unsafe {
579            let mut rslt: i8 = 0;
580            let mut i: u8 = 0 as ffi::c_int as u8;
581            let mut j: u8 = 0 as ffi::c_int as u8;
582            let mut new_fields: u8 = 0 as ffi::c_int as u8;
583            let mut field_ptr: [*mut SensorData; 3] = [
584                0 as *mut SensorData,
585                0 as *mut SensorData,
586                0 as *mut SensorData,
587            ];
588            let mut field_data: [SensorData; 3] = [
589                {
590                    let init = SensorData {
591                        status: 0 as ffi::c_int as u8,
592                        gas_index: 0,
593                        meas_index: 0,
594                        res_heat: 0,
595                        idac: 0,
596                        gas_wait: 0,
597                        temperature: 0.,
598                        pressure: 0.,
599                        humidity: 0.,
600                        gas_resistance: 0.,
601                    };
602                    init
603                },
604                SensorData {
605                    status: 0,
606                    gas_index: 0,
607                    meas_index: 0,
608                    res_heat: 0,
609                    idac: 0,
610                    gas_wait: 0,
611                    temperature: 0.,
612                    pressure: 0.,
613                    humidity: 0.,
614                    gas_resistance: 0.,
615                },
616                SensorData {
617                    status: 0,
618                    gas_index: 0,
619                    meas_index: 0,
620                    res_heat: 0,
621                    idac: 0,
622                    gas_wait: 0,
623                    temperature: 0.,
624                    pressure: 0.,
625                    humidity: 0.,
626                    gas_resistance: 0.,
627                },
628            ];
629            field_ptr[0] =
630                &mut *field_data.as_mut_ptr().offset(0 as ffi::c_int as isize) as *mut SensorData;
631            field_ptr[1] =
632                &mut *field_data.as_mut_ptr().offset(1 as ffi::c_int as isize) as *mut SensorData;
633            field_ptr[2] =
634                &mut *field_data.as_mut_ptr().offset(2 as ffi::c_int as isize) as *mut SensorData;
635            rslt = null_ptr_check(self);
636            if rslt as ffi::c_int == 0 as ffi::c_int && !data.is_null() {
637                if op_mode as ffi::c_int == 1 as ffi::c_int {
638                    rslt = read_field_data(0 as ffi::c_int as u8, data, self);
639                    if rslt as ffi::c_int == 0 as ffi::c_int {
640                        if (*data).status as ffi::c_int & 0x80 as ffi::c_int != 0 {
641                            new_fields = 1 as ffi::c_int as u8;
642                        } else {
643                            new_fields = 0 as ffi::c_int as u8;
644                            rslt = 2 as ffi::c_int as i8;
645                        }
646                    }
647                } else if op_mode as ffi::c_int == 2 as ffi::c_int
648                    || op_mode as ffi::c_int == 3 as ffi::c_int
649                {
650                    rslt =
651                        read_all_field_data(field_ptr.as_mut_ptr() as *const *mut SensorData, self);
652                    new_fields = 0 as ffi::c_int as u8;
653                    i = 0 as ffi::c_int as u8;
654                    while (i as ffi::c_int) < 3 as ffi::c_int
655                        && rslt as ffi::c_int == 0 as ffi::c_int
656                    {
657                        if (*field_ptr[i as usize]).status as ffi::c_int & 0x80 as ffi::c_int != 0 {
658                            new_fields = new_fields.wrapping_add(1);
659                        }
660                        i = i.wrapping_add(1);
661                    }
662                    i = 0 as ffi::c_int as u8;
663                    while (i as ffi::c_int) < 2 as ffi::c_int
664                        && rslt as ffi::c_int == 0 as ffi::c_int
665                    {
666                        j = (i as ffi::c_int + 1 as ffi::c_int) as u8;
667                        while (j as ffi::c_int) < 3 as ffi::c_int {
668                            sort_sensor_data(i, j, field_ptr.as_mut_ptr());
669                            j = j.wrapping_add(1);
670                        }
671                        i = i.wrapping_add(1);
672                    }
673                    i = 0 as ffi::c_int as u8;
674                    while (i as ffi::c_int) < 3 as ffi::c_int
675                        && rslt as ffi::c_int == 0 as ffi::c_int
676                    {
677                        *data.offset(i as isize) = *field_ptr[i as usize];
678                        i = i.wrapping_add(1);
679                    }
680                    if new_fields as ffi::c_int == 0 as ffi::c_int {
681                        rslt = 2 as ffi::c_int as i8;
682                    }
683                } else {
684                    rslt = 1 as ffi::c_int as i8;
685                }
686                *n_data = new_fields;
687            } else {
688                rslt = -(1 as ffi::c_int) as i8;
689            }
690            check_rslt(rslt)
691        }
692    }
693
694    /// Used to set the gas configuration of the sensor.
695    pub fn set_gas_heater_conf(
696        &mut self,
697        op_mode: OperationMode,
698        conf: GasHeaterConfig,
699    ) -> Result<(), Error> {
700        unsafe {
701            let mut rslt: i8 = 0;
702            let mut nb_conv: u8 = 0 as ffi::c_int as u8;
703            let mut hctrl: u8 = 0;
704            let mut run_gas: u8 = 0 as ffi::c_int as u8;
705            let mut ctrl_gas_data: [u8; 2] = [0; 2];
706            let mut ctrl_gas_addr: [u8; 2] = [0x70 as ffi::c_int as u8, 0x71 as ffi::c_int as u8];
707            self.set_op_mode(OperationMode::Sleep)?;
708            // NOTE BWB, not the same as self.set_config
709            rslt = set_conf(&conf, op_mode as u8, &mut nb_conv, self);
710            if rslt as ffi::c_int == 0 as ffi::c_int {
711                self.get_regs(
712                    0x70 as ffi::c_int as u8,
713                    ctrl_gas_data.as_mut_ptr(),
714                    2 as ffi::c_int as u32,
715                )?;
716                if rslt as ffi::c_int == 0 as ffi::c_int {
717                    if conf.enable as ffi::c_int == 0x1 as ffi::c_int {
718                        hctrl = 0 as ffi::c_int as u8;
719                        if (*self).variant_id == 0x1 as ffi::c_int as ffi::c_uint {
720                            run_gas = 0x2 as ffi::c_int as u8;
721                        } else {
722                            run_gas = 0x1 as ffi::c_int as u8;
723                        }
724                    } else {
725                        hctrl = 0x1 as ffi::c_int as u8;
726                        run_gas = 0 as ffi::c_int as u8;
727                    }
728                    ctrl_gas_data[0] = (ctrl_gas_data[0] as ffi::c_int & !(0x8 as ffi::c_int)
729                        | (hctrl as ffi::c_int) << 3 as ffi::c_int & 0x8 as ffi::c_int)
730                        as u8;
731                    ctrl_gas_data[1] = (ctrl_gas_data[1] as ffi::c_int & !(0xf as ffi::c_int)
732                        | nb_conv as ffi::c_int & 0xf as ffi::c_int)
733                        as u8;
734                    ctrl_gas_data[1] = (ctrl_gas_data[1] as ffi::c_int & !(0x30 as ffi::c_int)
735                        | (run_gas as ffi::c_int) << 4 as ffi::c_int & 0x30 as ffi::c_int)
736                        as u8;
737                    self.set_regs(
738                        ctrl_gas_addr.as_mut_ptr(),
739                        ctrl_gas_data.as_mut_ptr(),
740                        2 as ffi::c_int as u32,
741                    )?;
742                }
743            }
744            check_rslt(rslt)
745        }
746    }
747
748    /// Used to get the gas configuration of the sensor.
749    pub fn get_gas_heater_conf(&mut self, config: GasHeaterConfig) -> Result<(), Error> {
750        self.gas_heater_config = config;
751        unsafe {
752            let mut data_array: [u8; 10] = [0 as ffi::c_int as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0];
753            let mut i: u8 = 0;
754            self.get_regs(
755                0x5a as ffi::c_int as u8,
756                data_array.as_mut_ptr(),
757                10 as ffi::c_int as u32,
758            )?;
759            if !(self.gas_heater_config.heatr_dur_prof).is_null()
760                && !(self.gas_heater_config.heatr_temp_prof).is_null()
761            {
762                i = 0 as ffi::c_int as u8;
763                while (i as ffi::c_int) < 10 as ffi::c_int {
764                    *(self.gas_heater_config.heatr_temp_prof).offset(i as isize) =
765                        data_array[i as usize] as u16;
766                    i = i.wrapping_add(1);
767                }
768                self.get_regs(
769                    0x64 as ffi::c_int as u8,
770                    data_array.as_mut_ptr(),
771                    10 as ffi::c_int as u32,
772                )?;
773                i = 0 as ffi::c_int as u8;
774                while (i as ffi::c_int) < 10 as ffi::c_int {
775                    *(self.gas_heater_config.heatr_dur_prof).offset(i as isize) =
776                        data_array[i as usize] as u16;
777                    i = i.wrapping_add(1);
778                }
779                Ok(())
780            } else {
781                Err(Error::NullPointer)
782            }
783        }
784    }
785}