ens160_aq/
data.rs

1// no_std support
2#[allow(unused_imports)]
3#[warn(dead_code)]
4use libm::{exp, round, trunc};
5
6#[allow(unused_imports)] // for no_std use
7//use num_traits::float::FloatCore;
8
9//use crate::error::Error;
10use bitfield::bitfield;
11
12/// Default I²C address, ADDR pin low
13pub const DEFAULT_ADDRESS: u8 = 0x52;
14/// the sensor's secondary address ['SECONDARY_ADDRESS']), ADDR pin high
15pub const SECONDARY_ADDRESS: u8 = 0x53;
16
17/// A measurement result from the sensor.
18#[derive(Debug, PartialEq, Clone, Copy)]
19pub struct Measurements {
20    /// CO₂ equivalent (parts per million, ppm)
21    pub co2eq_ppm: ECO2,
22    /// Total Volatile Organic Compounds (parts per billion, ppb)
23    pub tvoc_ppb: u16,
24    /// air quality index as enum
25    pub air_quality_index: AirQualityIndex,
26    /// ethanol concentration in ppb
27    pub etoh: u16,
28    /// raw resitance value of hot plate in ohms
29    pub raw_resistance: f32,
30}
31
32/// air quality index 
33#[derive(Debug, Clone, Copy, Eq, PartialEq)]
34#[repr(u8)] // as defined in data sheet
35pub enum AirQualityIndex {
36    Unavailable = 0,
37    Excellent = 1,
38    Good = 2,
39    Moderate = 3,
40    Poor = 4,
41    Unhealthy = 5,
42    InvalidRange = 6,
43}
44
45impl From<u8> for AirQualityIndex {
46    fn from(i: u8) -> Self {
47        match i {
48            0 => Self::Unavailable,
49            1 => Self::Excellent,
50            2 => Self::Good,
51            3 => Self::Moderate,
52            4 => Self::Poor,
53            5 => Self::Unhealthy,
54            _ => Self::InvalidRange,
55        }
56    }
57}
58
59/// raw ECO2 
60#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
61pub struct ECO2 {
62    pub value: u16,
63}
64
65impl ECO2 {
66    pub fn get_value(&self) -> u16 {
67        self.value
68    }
69}
70
71impl From<u16> for ECO2 {
72    fn from(v: u16) -> Self {
73        ECO2 { value: v }
74    }
75}
76
77/// Operation Mode of the sensor.
78#[derive(Debug, PartialEq)]
79#[repr(u8)]
80pub enum OperationMode {
81    /// DEEP SLEEP mode (low-power standby)
82    Sleep = 0x00,
83    /// IDLE mode (low power)
84    Idle = 0x01,
85    /// SSTANDARD Gas Sensing Mode.  Normal run mode
86    Standard = 0x02,
87    /// Soft reset device:  this will reset the ENS160 back to factory parameters including
88    /// the InitialStartupPhase for one hour which will persist until 24 hours of continuous
89    /// operating.  Not required for "normal" use.
90    Reset = 0xf0,
91}
92
93impl From<u8> for OperationMode {
94    fn from(value: u8) -> Self {
95        match value {
96            0x00 => OperationMode::Sleep,
97            0x01 => OperationMode::Idle,
98            0x02 => OperationMode::Standard,
99            0xf0 => OperationMode::Reset, // just for completeness, cannot presist in this state
100            _ => unreachable!(),
101        }
102    }
103}
104
105/// Commands for ENS160 command register writes
106#[repr(u8)]
107pub enum ENS160Command {
108    /// No operation
109    Nop = 0x00,
110    /// Get FW (App) version
111    GetAppVersion = 0x0e,
112    /// Clears GPR Read Registers
113    ClearGPR = 0xcc,
114}
115
116// required by bitfield below
117#[derive(Debug, Clone, Copy)]
118pub enum ValidityFlag {
119    NormalOperation,
120    WarmupPhase,
121    InitialStartupPhase,
122    InvalidOutput,
123}
124
125// required by bitfield
126impl From<u8> for ValidityFlag {
127    fn from(v: u8) -> Self {
128        match v {
129            0x00 => Self::NormalOperation,
130            0x01 => Self::WarmupPhase,
131            0x02 => Self::InitialStartupPhase,
132            0x03 => Self::InvalidOutput,
133            _ => unreachable!(), // only four modes so should never get here
134        }
135    }
136}
137
138bitfield! {
139    /// ENS160 status bits
140    pub struct Status(u8);
141    impl Debug;
142
143    pub bool, new_group_data_ready, _: 0;
144    pub bool, new_data_ready, _: 1;
145    pub into ValidityFlag, validity_flag, _: 3,2;  // 2 bits
146    // 5, 4 not used
147    pub bool, error, _: 6;  // probably wrong opmode selected
148    pub bool, running_mode, _: 7;
149}
150
151#[derive(Debug)]
152/// Interrupt pin configuration value, use builder methods
153pub struct InterruptPinConfig(pub u8);
154
155impl InterruptPinConfig {
156    /// builder sets config value to 0x00
157    pub fn builder() -> InterruptPinConfig {
158        InterruptPinConfig(0x00)
159    }
160    /// gets interrupt pin config value from struct
161    pub fn get_value(&self) -> u8 {
162        self.0
163    }
164    /// interrupt pin is high when active
165    pub fn active_high(mut self) -> Self {
166        self.0 |= 0b01000000;
167        self
168    }
169    /// interrupt pin is low when active
170    pub fn active_low(mut self) -> Self {
171        self.0 &= 0b10111111;
172        self
173    }
174    /// interrupt pin drive is push-pull
175    pub fn push_pull(mut self) -> Self {
176        self.0 |= 0b00100000;
177        self
178    }
179    /// interrupt pin drive is open drain (not driven)
180    pub fn open_drain(mut self) -> Self {
181        self.0 &= 0b11011111;
182        self
183    }
184    /// interrupt on new group data ready
185    pub fn on_new_group_data(mut self) -> Self {
186        self.0 |= 0b00000100;
187        self
188    }
189    /// no interrupt when new group data ready
190    pub fn not_new_group_data(mut self) -> Self {
191        self.0 &= 0b11111011;
192        self
193    }
194    /// interrupt on new data ready
195    pub fn on_new_data(mut self) -> Self {
196        self.0 |= 0b00000010;
197        self
198    }
199    /// no interrupt when new data ready
200    pub fn not_new_data(mut self) -> Self {
201        self.0 &= 0b11111101;
202        self
203    }
204    /// enable interrupt pin
205    pub fn enable_interrupt(mut self) -> Self {
206        self.0 |= 0b00000001;
207        self
208    }
209    /// disable interrupt pin
210    pub fn disable_interrupt(mut self) -> Self {
211        self.0 &= 0b11111110;
212        self
213    }
214    /// build: just rerurns the value as u8
215    pub fn build(&self) -> u8 {  // nothing to build, but build method is part of builder pattern
216        self.0
217    }
218
219}