-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathIAQCore.cpp
189 lines (169 loc) · 5.46 KB
/
IAQCore.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/**
* @file IAQCore.cpp
* @author Hannes Fuchs
* @date 2017-07-20
* @copyright MIT
* @brief Main Class file for iAQ-Core C/P Sensor library
*
* This is a simple libray for the indoor air quality sensors iAQ-core C and
* iAQ-core P from AMS. More information about these sensors could be found
* under http://ams.com/eng/Products/Environmental-Sensors/Air-Quality-Sensors
*
* @see http://ams.com/eng/Products/Environmental-Sensors/Air-Quality-Sensors
* @see http://ams.com/eng/Products/Environmental-Sensors/Air-Quality-Sensors/iAQ-core-C
* @see http://ams.com/eng/Products/Environmental-Sensors/Air-Quality-Sensors/iAQ-core-P
*/
#include "IAQCore.h"
/**
* @breif The main Class for the iAQ-core sensor library
*/
IAQCore::IAQCore() {
}
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
/**
* @brief The main Class for the iAQ-core sensor library
* @param sda and scl I/O Port
*/
IAQCore::IAQCore(int sda, int scl) {
_sda = sda;
_scl = scl;
}
#endif
/**
* @brief Initalizates the I2C Bus and sets the sensor type
* @param type The sensor type C or P, see IAQCore.h
*/
void IAQCore::begin(uint8_t type) {
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
if (_sda && _scl) {
Wire.begin(_sda, _scl);
} else {
Wire.begin();
}
#else
Wire.begin();
#endif
_type = type;
// atm there are only two types
if (type == IAQCORE_TYPE_C) {
_lastreadtime = -IAQCORE_MEASUREMENT_INTERVAL_TYPE_C;
_measurementinterval = IAQCORE_MEASUREMENT_INTERVAL_TYPE_C;
} else {
_lastreadtime = -IAQCORE_MEASUREMENT_INTERVAL_TYPE_P;
_measurementinterval = IAQCORE_MEASUREMENT_INTERVAL_TYPE_P;
}
// set unofficial status
_data[IAQCORE_STATUS_OFFSET] = IAQCORE_STATUS_NOT_UPDATED_AT_ALL;
}
/**
* @brief Wrapper for private function readBytesFromSensor()
*
* Updates only the status and the CO2 prediction value.
*
* @return Sensor status, see IAQCore.h for values
*/
uint8_t IAQCore::update(void) {
return readBytesFromSensor(IAQCORE_READ_CO2_AND_STATUS);
}
/**
* @brief Wrapper for private function readBytesFromSensor()
*
* Updates all possible sensor values; including CO2 prediction, status,
* sensor resistance and TVOC prediction values.
*
* @return Returns the status of an update, see IAQCore.h for values
*/
uint8_t IAQCore::updateAll(void) {
return readBytesFromSensor(IAQCORE_READ_ALL);
}
/**
* @brief Calculates the CO2 prediction value and returns it.
*
* @return Calculated CO2 prediction value
*/
uint16_t IAQCore::getCO2PredictionPPM(void) {
uint16_t tmp = _data[IAQCORE_CO2_PREDICTION_MSB_OFFSET];
tmp <<= 8;
tmp += _data[IAQCORE_CO2_PREDICTION_LSB_OFFSET];
return tmp;
}
/**
* @brief Just returns the status of the sensor
*
* @return Sensor status, see IAQCore.h for values
*/
uint8_t IAQCore::getStatus(void) {
return _data[IAQCORE_STATUS_OFFSET];
}
/**
* @brief Calculates the sensors resistance value and returns it.
*
* @return Calculated sensor resistance value
*/
uint32_t IAQCore::getSensorResistanceOhm(void) {
uint32_t tmp = _data[IAQCORE_RESISTANCE_MSB_OFFSET];
tmp <<= 8;
tmp += _data[IAQCORE_RESISTANCE_MID_OFFSET];
tmp <<= 8;
tmp += _data[IAQCORE_RESISTANCE_LSB_OFFSET];
return tmp;
}
/**
* @brief Calculates the TVOC prediction value and returns it.
*
* @return Calculated TVOC prediction value
*/
uint16_t IAQCore::getTVOCPredictionPPB(void) {
uint16_t tmp = _data[IAQCORE_TVOC_PREDICTION_MSB_OFFSET];
tmp <<= 8;
tmp += _data[IAQCORE_TVOC_PREDICTION_LSB_OFFSET];
return tmp;
}
/**
* @brief Reads the sensor, save the values in array and returns status
*
* On fast readings (especially the P version) the last status will be returned
* and the _data array will NOT be updated. Some custom status where added to
* catch some more errors.
*
* @param bytes How many Bytes should be read from the sensor
* @return Sensor status, see IAQCore.h for values
*/
uint8_t IAQCore::readBytesFromSensor(uint8_t bytes) {
// return quickly if we read to fast
uint32_t currenttime = millis();
if ((currenttime - _lastreadtime) < _measurementinterval) {
IAQCORE_DEBUG_PRINTLN(F("Measurement interval to short, return last status"));
return getStatus();
}
// set measurement time
_lastreadtime = currenttime;
// reset data, sizeof(data) should be known at compile time
memset(_data, 0x00, sizeof(_data));
// to be safe, this status should be overwritten
_data[IAQCORE_STATUS_OFFSET] = IAQCORE_STATUS_UPDATING;
IAQCORE_DEBUG_PRINT(F("Buffer: "));
for (uint8_t i=0; i<bytes; i++) {
IAQCORE_DEBUG_PRINT(_data[i], HEX); IAQCORE_DEBUG_PRINT(F(" "));
}
IAQCORE_DEBUG_PRINTLN(F(""));
// do we need this? see IAQCore.h on line 46
Wire.beginTransmission(IAQCORE_DEF_I2C_ADDR);
Wire.write(IAQCORE_START_READING);
Wire.endTransmission();
IAQCORE_DEBUG_PRINTLN(F("Request data from sensor"));
Wire.requestFrom((uint8_t)IAQCORE_DEF_I2C_ADDR, (uint8_t)bytes, (uint8_t)true);
if (Wire.available() != bytes) {
IAQCORE_DEBUG_PRINTLN(F("Request failed"));
_data[IAQCORE_STATUS_OFFSET] = IAQCORE_STATUS_I2C_REQ_FAILED;
return getStatus();
}
// read into buffer
IAQCORE_DEBUG_PRINT(F("Received: "));
for (uint8_t i=0; i<bytes; i++) {
_data[i] = Wire.read();
IAQCORE_DEBUG_PRINT(_data[i], HEX); IAQCORE_DEBUG_PRINT(F(" "));
}
IAQCORE_DEBUG_PRINTLN(F(""));
return getStatus();
}