22// FILE: MTP40C.h
33// AUTHOR: Rob Tillaart
44// DATE: 2021-08-20
5- // VERSION: 0.1.1
6- // PURPOSE: Arduino library for MTP40C CO2 sensor
5+ // VERSION: 0.2.0
6+ // PURPOSE: Arduino library for MTP40C MTP40D CO2 sensor
77// URL: https://github.com/RobTillaart/MTP40C
88//
99// HISTORY:
1010// 0.1.0 2021-08-20 initial version
1111// 0.1.1 2021-08-23 added examples, minor fixes
12+ // 0.2.0 2021-08-27 added MTP40D derived class
13+ // + many fixes after testing
1214
1315
1416#include " MTP40C.h"
1517
1618// debug flag, development.
17- // #define MTP40C_DEBUG 1
19+ // #define MTP40_DEBUG 1
1820
1921
2022
21- MTP40C::MTP40C (Stream * str)
23+ MTP40::MTP40 (Stream * str)
2224{
2325 _ser = str;
2426 _buffer[0 ] = ' \0 ' ;
2527}
2628
2729
28- bool MTP40C ::begin (uint8_t address)
30+ bool MTP40 ::begin (uint8_t address)
2931{
3032 if (address > 247 ) return false ;
3133
32- _useAddress = false ;
33- _timeout = 100 ;
34- _lastRead = 0 ;
35- _airPressure = 0 ;
36- _gasLevel = 0 ;
37- _address = address;
34+ _useAddress = false ;
35+ _timeout = 100 ;
36+ _lastRead = 0 ;
37+ _airPressureReference = 0 ;
38+ _gasLevel = 0 ;
39+ _address = address;
40+ _suppressError = false ;
41+
3842 return isConnected ();
3943}
4044
4145
42- bool MTP40C ::isConnected ()
46+ bool MTP40 ::isConnected ()
4347{
4448 uint8_t addr = getAddress ();
4549 return (addr == _address);
4650}
4751
4852
49- uint8_t MTP40C ::getAddress ()
53+ uint8_t MTP40 ::getAddress ()
5054{
5155 uint8_t cmd[8 ] = { 0xFE , 0x03 , 0x14 , 0x00 , 0x01 , 0x00 , 0x55 , 0xA5 };
5256 if (request (cmd, 8 , 7 ) )
5357 {
58+ _address = _buffer[3 ];
5459 return _buffer[3 ];
5560 }
56- return MTP40C_INVALID_ADDRESS;
61+
62+ return MTP40_INVALID_ADDRESS;
5763}
5864
5965
60- bool MTP40C ::setAddress (uint8_t address)
66+ bool MTP40 ::setAddress (uint8_t address)
6167{
6268 if (address > 247 ) return false ;
6369
@@ -73,33 +79,38 @@ bool MTP40C::setAddress(uint8_t address)
7379}
7480
7581
76- float MTP40C::getAirPressure ()
82+ float MTP40::getAirPressureReference ()
7783{
7884 union
7985 {
8086 float value;
8187 uint8_t b[4 ];
8288 } convert;
8389
90+ _lastError = MTP40_OK;
91+
8492 // max read freq 1x per 4 seconds
85- if (millis () - _lastRead < 4000 ) return _airPressure ; // last value
93+ if (millis () - _lastRead < 4000 ) return _airPressureReference ; // last value
8694 _lastRead = millis ();
8795
8896 uint8_t cmd[5 ] = { 0xFE , 0x68 , 0x01 , 0xFE , 0x30 };
89- if (request (cmd, 5 , 10 ) )
97+ if (request (cmd, 5 , 10 ))
9098 {
91- for (uint8_t i = 0 ; i < 3 ; i++)
99+ for (uint8_t i = 0 ; i < 4 ; i++)
92100 {
93101 convert.b [i] = _buffer[4 + i];
94102 }
95- _airPressure = convert.value ;
96- return _airPressure ;
103+ _airPressureReference = convert.value ;
104+ return _airPressureReference ;
97105 }
98- return MTP40C_INVALID_AIR_PRESSURE;
106+
107+ _lastError = MTP40_INVALID_AIR_PRESSURE;
108+ if (_suppressError) return _airPressureReference;
109+ return _lastError;
99110}
100111
101112
102- bool MTP40C ::setAirPressureReference (float apr)
113+ bool MTP40 ::setAirPressureReference (float apr)
103114{
104115 if ((apr < 700 ) || (apr > 1100 )) return false ;
105116
@@ -111,7 +122,7 @@ bool MTP40C::setAirPressureReference(float apr)
111122
112123 uint8_t cmd[10 ] = { 0xFE , 0x67 , 0x01 , 0x01 , 0x00 , 0x40 , 0x7D , 0x44 , 0xC4 , 0xA3 };
113124 convert.value = apr;
114- for (uint8_t i = 0 ; i < 3 ; i++)
125+ for (uint8_t i = 0 ; i < 4 ; i++)
115126 {
116127 cmd[4 + i] = convert.b [i];
117128 }
@@ -123,8 +134,11 @@ bool MTP40C::setAirPressureReference(float apr)
123134}
124135
125136
126- uint16_t MTP40C ::getGasConcentration ()
137+ uint16_t MTP40 ::getGasConcentration ()
127138{
139+
140+ _lastError = MTP40_OK;
141+
128142 // max read freq 1x per 4 seconds
129143 if (millis () - _lastRead < 4000 ) return _gasLevel; // last value
130144 _lastRead = millis ();
@@ -140,11 +154,14 @@ uint16_t MTP40C::getGasConcentration()
140154 _gasLevel = _buffer[5 ] *256 + _buffer[4 ];
141155 return _gasLevel;
142156 }
143- return MTP40C_INVALID_GAS_LEVEL;
157+
158+ _lastError = MTP40_INVALID_GAS_LEVEL;
159+ if (_suppressError) return _gasLevel;
160+ return _lastError;
144161}
145162
146163
147- bool MTP40C ::setSinglePointCorrection (float spc)
164+ bool MTP40 ::setSinglePointCorrection (float spc)
148165{
149166 if ((spc < 400 ) || (spc > 5000 )) return false ;
150167
@@ -156,7 +173,7 @@ bool MTP40C::setSinglePointCorrection(float spc)
156173
157174 uint8_t cmd[9 ] = { 0xFE , 0x28 , 0x80 , 0x00 , 0x80 , 0x40 , 0x44 , 0x33 , 0x22 };
158175 convert.value = spc;
159- for (uint8_t i = 0 ; i < 3 ; i++)
176+ for (uint8_t i = 0 ; i < 4 ; i++)
160177 {
161178 cmd[3 + i] = convert.b [i];
162179 }
@@ -168,7 +185,7 @@ bool MTP40C::setSinglePointCorrection(float spc)
168185}
169186
170187
171- bool MTP40C ::getSinglePointCorrectionReady ()
188+ bool MTP40 ::getSinglePointCorrectionReady ()
172189{
173190 uint8_t cmd[5 ] = { 0xFE , 0x28 , 0x81 , 0xCE , 0x50 };
174191 if (request (cmd, 5 , 6 ) )
@@ -179,7 +196,7 @@ bool MTP40C::getSinglePointCorrectionReady()
179196}
180197
181198
182- bool MTP40C ::openSelfCalibration ()
199+ bool MTP40 ::openSelfCalibration ()
183200{
184201 uint8_t cmd[6 ] = { 0xFE , 0x28 , 0x66 , 0xFF , 0xDA , 0x24 };
185202 if (request (cmd, 6 , 6 ) )
@@ -190,7 +207,7 @@ bool MTP40C::openSelfCalibration()
190207}
191208
192209
193- bool MTP40C ::closeSelfCalibration ()
210+ bool MTP40 ::closeSelfCalibration ()
194211{
195212 uint8_t cmd[6 ] = { 0xFE , 0x28 , 0x66 , 0x00 , 0x9A , 0x64 };
196213 if (request (cmd, 6 , 6 ) )
@@ -201,7 +218,7 @@ bool MTP40C::closeSelfCalibration()
201218}
202219
203220
204- uint8_t MTP40C ::getSelfCalibrationStatus ()
221+ uint8_t MTP40 ::getSelfCalibrationStatus ()
205222{
206223 uint8_t cmd[5 ] = { 0xFE , 0x28 , 0x67 , 0x4F , 0xDA };
207224 if (request (cmd, 5 , 6 ) )
@@ -212,7 +229,7 @@ uint8_t MTP40C::getSelfCalibrationStatus()
212229}
213230
214231
215- bool MTP40C ::setSelfCalibrationHours (uint16_t hrs)
232+ bool MTP40 ::setSelfCalibrationHours (uint16_t hrs)
216233{
217234 if ((hrs < 24 ) || (hrs > 720 )) return false ;
218235 uint8_t cmd[7 ] = { 0xFE , 0x28 , 0x6A , 0x64 , 0x00 , 0x0E , 0xA8 };
@@ -226,7 +243,7 @@ bool MTP40C::setSelfCalibrationHours(uint16_t hrs)
226243}
227244
228245
229- uint16_t MTP40C ::getSelfCalibrationHours ()
246+ uint16_t MTP40 ::getSelfCalibrationHours ()
230247{
231248 uint8_t cmd[5 ] = { 0xFE , 0x28 , 0x69 , 0xCE , 0x1E };
232249 if (request (cmd, 5 , 9 ) )
@@ -237,28 +254,37 @@ uint16_t MTP40C::getSelfCalibrationHours()
237254}
238255
239256
257+ int MTP40::lastError ()
258+ {
259+ int e = _lastError;
260+ _lastError = MTP40_OK;
261+ return e;
262+ }
263+
264+
265+
240266// ////////////////////////////////////////////////////////////////////
241267//
242268// PRIVATE
243269//
244- bool MTP40C ::request (uint8_t *data, uint8_t commandLength, uint8_t answerLength)
270+ bool MTP40 ::request (uint8_t *data, uint8_t commandLength, uint8_t answerLength)
245271{
246272 // generic or specific address
247- if (_useAddress)
273+ if (_useAddress)
248274 {
249275 data[0 ] = _address;
250276 }
251277 else
252278 {
253- data[0 ] = 0xFE ; // broadcast
279+ data[0 ] = 0xFE ; // broadcast
254280 }
255281 // calculate CRC of command
256282 uint16_t crc = CRC (data, commandLength - 2 );
257283 data[commandLength - 1 ] = crc / 256 ;
258284 data[commandLength - 2 ] = crc & 0xFF ;
259285 while (commandLength--)
260286 {
261- #ifdef MTP40C_DEBUG
287+ #ifdef MTP40_DEBUG
262288 if (*data < 0x10 ) _ser->print (0 );
263289 _ser->print (*data++, HEX);
264290 _ser->print (" " );
@@ -286,7 +312,7 @@ bool MTP40C::request(uint8_t *data, uint8_t commandLength, uint8_t answerLength)
286312
287313
288314// from datasheet
289- uint16_t MTP40C ::CRC (uint8_t *data, uint16_t len)
315+ uint16_t MTP40 ::CRC (uint8_t *data, uint16_t len)
290316{
291317const uint8_t auchCRCHi[] = {
292318 0x00 , 0xC1 , 0x81 , 0x40 , 0x01 , 0xC0 , 0x80 , 0x41 , 0x01 , 0xC0 , 0x80 , 0x41 , 0x00 , 0xC1 , 0x81 ,
@@ -348,4 +374,22 @@ const uint8_t auchCRCLo[] = {
348374}
349375
350376
377+ // ///////////////////////////////////////////////////////////
378+ //
379+ // DERIVED CLASSES
380+ //
381+
382+ MTP40C::MTP40C (Stream * str) : MTP40(str)
383+ {
384+ _type = 2 ;
385+ };
386+
387+
388+ MTP40D::MTP40D (Stream * str) : MTP40(str)
389+ {
390+ _type = 3 ;
391+ };
392+
393+
394+
351395// -- END OF FILE --
0 commit comments