GY-63_MS5611/libraries/MTP40F/MTP40F.cpp
2024-02-21 14:17:30 +01:00

274 lines
5.4 KiB
C++

//
// FILE: MTP40F.cpp
// AUTHOR: Rob Tillaart
// DATE: 2023-07-25
// VERSION: 0.2.0
// PURPOSE: Arduino library for MTP40F CO2 sensor
// URL: https://github.com/RobTillaart/MTP40F
#include "MTP40F.h"
// debug flag, development.
// #define MTP40F_DEBUG 1
MTP40F::MTP40F(Stream * stream)
{
_ser = stream;
_buffer[0] = '\0';
_type = 5;
}
bool MTP40F::begin()
{
_timeout = 100;
_lastRead = 0;
_airPressureReference = 0;
_gasLevel = 0;
_suppressError = false;
_lastError = MTP40F_OK;
return true;
}
int MTP40F::getAirPressureReference()
{
_lastError = MTP40F_OK;
uint8_t cmd[9] = { 0x42, 0x4D, 0xA0, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31 };
if (request(cmd, 9, 11))
{
_airPressureReference = _buffer[7] * 256 + _buffer[8];
return _airPressureReference;
}
_lastError = MTP40F_INVALID_AIR_PRESSURE;
if (_suppressError) return _airPressureReference;
return _lastError;
}
bool MTP40F::setAirPressureReference(int apr)
{
if ((apr < 700) || (apr > 1100)) // page 5 datasheet
{
return false;
}
uint8_t cmd[11] = { 0x42, 0x4D, 0xA0, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 };
cmd[7] = apr / 256;
cmd[8] = apr % 256;
if (request(cmd, 11, 11) )
{
return true;
}
return false;
}
uint32_t MTP40F::getGasConcentration()
{
_lastError = MTP40F_OK;
// max read freq 1x per 2 seconds
// datasheet measurement interval = 2s
if (millis() - _lastRead < 2000)
{
return _gasLevel; // last value
}
_lastRead = millis();
uint8_t cmd[9] = { 0x42, 0x4D, 0xA0, 0x00, 0x03, 0x00, 0x00, 0x01, 0x32 };
if (request(cmd, 9, 14) )
{
uint8_t status = _buffer[11];
if (status == 0x00)
{
_gasLevel = _buffer[7];
_gasLevel <<= 8;
_gasLevel |= _buffer[8];
_gasLevel <<= 8;
_gasLevel |= _buffer[9];
_gasLevel <<= 8;
_gasLevel += _buffer[10];
return _gasLevel;
}
_lastError = MTP40F_INVALID_GAS_LEVEL;
if (_suppressError) return _gasLevel; // last level
return _lastError;
}
_lastError = MTP40F_REQUEST_FAILED;
if (_suppressError) return _gasLevel; // last level
return _lastError;
}
bool MTP40F::setSinglePointCorrection(uint32_t spc)
{
if ((spc < 400) || (spc > 2000)) // datasheet unclear 0x2000???
{
return false;
}
uint8_t cmd[13] = { 0x42, 0x4D, 0xA0, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
cmd[7] = 0;
cmd[8] = 0;
cmd[9] = spc / 256;
cmd[10] = spc % 256;
if (request(cmd, 13, 10) )
{
if (_buffer[7] ) return true;
}
return false;
}
bool MTP40F::getSinglePointCorrectionReady()
{
uint8_t cmd[9] = { 0x42, 0x4D, 0xA0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 };
if (request(cmd, 9, 10) )
{
if (_buffer[8] == 0) return true;
}
return false;
}
bool MTP40F::openSelfCalibration()
{
uint8_t cmd[10] = { 0x42, 0x4D, 0xA0, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00 };
if (request(cmd, 10, 9) )
{
return true;
}
return false;
}
bool MTP40F::closeSelfCalibration()
{
uint8_t cmd[10] = { 0x42, 0x4D, 0xA0, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00 };
if (request(cmd, 10, 9) )
{
return true;
}
return false;
}
uint8_t MTP40F::getSelfCalibrationStatus()
{
uint8_t cmd[9] = { 0x42, 0x4D, 0xA0, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00 };
if (request(cmd, 9, 10) )
{
return _buffer[7]; // 0x00 or 0xFF
}
_lastError = MTP40F_REQUEST_FAILED;
return _lastError;
}
uint16_t MTP40F::getSelfCalibrationHours()
{
uint8_t cmd[9] = { 0x42, 0x4D, 0xA0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 };
if (request(cmd, 9, 11) )
{
uint16_t hours = _buffer[7] * 256 + _buffer[8];
return hours;
}
_lastError = MTP40F_REQUEST_FAILED;
return _lastError;
}
bool MTP40F::setSelfCalibrationHours(uint16_t hours)
{
if ((hours < 24) || (hours > 720))
{
return false;
}
uint8_t cmd[11] = { 0x42, 0x4D, 0xA0, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 };
cmd[7] = hours / 256;
cmd[8] = hours & 0xFF;
if (request(cmd, 11, 10) )
{
return (_buffer[7] == 0x00);
}
return false;
}
int MTP40F::lastError()
{
int e = _lastError;
_lastError = MTP40F_OK;
return e;
}
//////////////////////////////////////////////////////////////////////
//
// PROTECTED
//
bool MTP40F::request(uint8_t *data, uint8_t commandLength, uint8_t responseLength)
{
// calculate CRC of command
uint16_t crc = CRC(data, commandLength - 2);
data[commandLength - 2] = crc / 256;
data[commandLength - 1] = crc & 0xFF;
while (commandLength--)
{
#ifdef MTP40F_DEBUG
if (*data < 0x10) Serial.print(0);
Serial.print(*data++, HEX);
Serial.print(" ");
#else
_ser->write(*data++);
#endif
yield(); // because baud rate is low!
}
uint32_t start = millis();
uint8_t i = 0;
while (i < responseLength)
{
if (millis() - start > _timeout) return false;
if (_ser->available())
{
_buffer[i++] = _ser->read();
}
yield(); // because baud rate is low!
}
if (responseLength > 2)
{
uint16_t expected_crc = (_buffer[responseLength - 2] << 8) | _buffer[responseLength - 1];
uint16_t calc_crc = CRC(_buffer, responseLength - 2);
if (calc_crc != expected_crc)
{
_lastError = MTP40F_INVALID_CRC;
return false;
}
return calc_crc == expected_crc;
}
return true;
}
uint16_t MTP40F::CRC(uint8_t *data, uint16_t length)
{
uint16_t sum = 0;
for (uint16_t i= 0; i < length; i++)
{
sum += *data++;
}
return sum;
}
// -- END OF FILE --