147 lines
3.1 KiB
C++
147 lines
3.1 KiB
C++
#pragma once
|
|
|
|
/**
|
|
* a digital multi-gas sensor for indoor air quality monitoring
|
|
* https://www.sciosense.com/wp-content/uploads/documents/SC-001224-DS-7-ENS160-Datasheet.pdf
|
|
*/
|
|
template <typename I2C> class ENS160 {
|
|
|
|
private:
|
|
|
|
I2C& i2c;
|
|
static constexpr const uint8_t ADDR1 = 0x52;
|
|
static constexpr const uint8_t ADDR2 = 0x53;
|
|
uint8_t ADDR;
|
|
|
|
static constexpr const char* NAME = "ENS160";
|
|
|
|
static constexpr const uint8_t REG_PART_ID = 0x00;
|
|
static constexpr const uint8_t REG_OPMODE = 0x10;
|
|
static constexpr const uint8_t REG_TEMP_IN = 0x13;
|
|
static constexpr const uint8_t REG_RH_IN = 0x15;
|
|
static constexpr const uint8_t REG_DEVICE_STATUS = 0x20;
|
|
static constexpr const uint8_t REG_DATA_AQI = 0x21;
|
|
static constexpr const uint8_t REG_DATA_TVOC = 0x22;
|
|
static constexpr const uint8_t REG_DATA_ECO2 = 0x24;
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum class Mode : uint8_t {
|
|
DEEP_SLEEP = 0x00,
|
|
IDLE = 0x01,
|
|
STANDARD = 0x02,
|
|
RESET = 0xF0,
|
|
};
|
|
|
|
union Status {
|
|
|
|
uint8_t raw;
|
|
|
|
struct {
|
|
uint8_t newgpr : 1;
|
|
uint8_t newdat : 1;
|
|
uint8_t valid : 2;
|
|
uint8_t dummy : 2;
|
|
uint8_t stater : 1;
|
|
uint8_t statas : 1;
|
|
} __attribute__((__packed__));
|
|
|
|
bool isNormal() const {return valid == 0;}
|
|
bool isWarmUp() const {return valid == 1;}
|
|
bool isStartUp() const {return valid == 2;}
|
|
bool isInvalid() const {return valid == 3;}
|
|
|
|
} __attribute__((__packed__));
|
|
|
|
union Result {
|
|
|
|
uint8_t raw[6];
|
|
|
|
struct {
|
|
Status status;
|
|
uint8_t aqi;
|
|
uint16_t tvoc;
|
|
uint16_t eco2;
|
|
} __attribute__((__packed__));
|
|
|
|
} __attribute__((__packed__));
|
|
|
|
public:
|
|
|
|
ENS160(I2C& i2c, uint8_t addr = ADDR1) : i2c(i2c), ADDR(addr) {
|
|
|
|
}
|
|
|
|
/** always 0x01 0x60 */
|
|
uint16_t getID() {
|
|
uint16_t res = 0;
|
|
i2c.readReg(ADDR, 0x00, 2, (uint8_t*)&res);
|
|
return res;
|
|
}
|
|
|
|
/** switch the mode of operation */
|
|
void setMode(Mode m) {
|
|
i2c.writeReg8(ADDR, REG_OPMODE, (uint8_t)m);
|
|
DELAY_MS(250); // not mentioned in the data-sheet but important?
|
|
}
|
|
|
|
/** set the current ambient temperature - for compensation */
|
|
void setTemp(float celsius) {
|
|
float kelvin = celsius + 273.15;
|
|
uint16_t tmp = (uint16_t) (kelvin * 64);
|
|
i2c.writeReg(ADDR, REG_TEMP_IN, 2, (uint8_t*)&tmp);
|
|
}
|
|
|
|
/** set the current ambient humidity (in %) - for compensation */
|
|
void setHumi(uint8_t humi) {
|
|
uint16_t tmp = humi * 512;
|
|
i2c.writeReg(ADDR, REG_RH_IN, 2, (uint8_t*)&tmp);
|
|
}
|
|
|
|
/** status + aqi + tvoc + eco2 */
|
|
Result getAll() {
|
|
Result res;
|
|
memset(res.raw, 0, 6);
|
|
i2c.readReg(ADDR, REG_DEVICE_STATUS, 6, res.raw);
|
|
res.status = getStatus();
|
|
//res.aqi = getAQI();
|
|
//res.tvoc = getTVOC();
|
|
//res.eco2 = getECO2();
|
|
return res;
|
|
}
|
|
|
|
Status getStatus() {
|
|
Status res;
|
|
res.raw = i2c.readReg8(ADDR, REG_DEVICE_STATUS);
|
|
return res;
|
|
}
|
|
|
|
uint8_t getAQI() {
|
|
uint8_t tmp = 0;
|
|
i2c.readReg(ADDR, REG_DATA_AQI, 1, &tmp);
|
|
return tmp & 0b111;
|
|
}
|
|
|
|
uint16_t getTVOC() {
|
|
uint16_t tmp = 0;
|
|
i2c.readReg(ADDR, REG_DATA_TVOC, 2, (uint8_t*)&tmp);
|
|
return tmp;
|
|
}
|
|
|
|
uint16_t getECO2() {
|
|
uint16_t tmp = 0;
|
|
i2c.readReg(ADDR, REG_DATA_ECO2, 2, (uint8_t*)&tmp);
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
/** is the device present on the bus? */
|
|
bool isPresent() {
|
|
return i2c.query(ADDR);
|
|
}
|
|
|
|
};
|