first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
347
libraries/M5Unit-ENV/test/embedded/scd4x_test.inl
Normal file
347
libraries/M5Unit-ENV/test/embedded/scd4x_test.inl
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
Common parts of SCD40/41 test
|
||||
*/
|
||||
|
||||
namespace {
|
||||
// float t uu int16 (temperature) same as library
|
||||
constexpr uint16_t float_to_uint16(const float f)
|
||||
{
|
||||
return f * 65536 / 175;
|
||||
}
|
||||
|
||||
constexpr Mode mode_table[] = {Mode::Normal, Mode::LowPower};
|
||||
constexpr uint32_t interval_table[] = {
|
||||
5 * 1000,
|
||||
30 * 1000,
|
||||
};
|
||||
|
||||
template <class U>
|
||||
elapsed_time_t test_periodic(U* unit, const uint32_t times, const uint32_t measure_duration = 0)
|
||||
{
|
||||
auto tm = unit->interval();
|
||||
auto timeout_at = m5::utility::millis() + 10 * 1000;
|
||||
|
||||
do {
|
||||
unit->update();
|
||||
if (unit->updated()) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
} while (!unit->updated() && m5::utility::millis() <= timeout_at);
|
||||
// timeout
|
||||
if (!unit->updated()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
uint32_t measured{};
|
||||
auto start_at = m5::utility::millis();
|
||||
timeout_at = start_at + (times * (tm + measure_duration) * 2);
|
||||
|
||||
do {
|
||||
unit->update();
|
||||
measured += unit->updated() ? 1 : 0;
|
||||
if (measured >= times) {
|
||||
break;
|
||||
}
|
||||
m5::utility::delay(1);
|
||||
|
||||
} while (measured < times && m5::utility::millis() <= timeout_at);
|
||||
return (measured == times) ? m5::utility::millis() - start_at : 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestSCD4x, BasicCommand)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& m : mode_table) {
|
||||
auto s = m5::utility::formatString("Mode:%u", m);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
// Return False if already stopped
|
||||
EXPECT_FALSE(unit->stopPeriodicMeasurement());
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(m));
|
||||
// Return False if already started
|
||||
EXPECT_FALSE(unit->startPeriodicMeasurement(m));
|
||||
EXPECT_FALSE(unit->startLowPowerPeriodicMeasurement());
|
||||
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
// These APIs result in an error during periodic detection
|
||||
{
|
||||
EXPECT_FALSE(unit->writeTemperatureOffset(0));
|
||||
float offset{};
|
||||
EXPECT_FALSE(unit->readTemperatureOffset(offset));
|
||||
|
||||
EXPECT_FALSE(unit->writeSensorAltitude(0));
|
||||
uint16_t altitude{};
|
||||
EXPECT_FALSE(unit->readSensorAltitude(altitude));
|
||||
|
||||
int16_t correction{};
|
||||
EXPECT_FALSE(unit->performForcedRecalibration(0, correction));
|
||||
|
||||
EXPECT_FALSE(unit->writeAutomaticSelfCalibrationEnabled(true));
|
||||
bool enabled{};
|
||||
EXPECT_FALSE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
|
||||
EXPECT_FALSE(unit->writeAutomaticSelfCalibrationTarget(0));
|
||||
uint16_t ppm{};
|
||||
EXPECT_FALSE(unit->readAutomaticSelfCalibrationTarget(ppm));
|
||||
|
||||
EXPECT_FALSE(unit->writePersistSettings());
|
||||
|
||||
uint64_t sno{};
|
||||
EXPECT_FALSE(unit->readSerialNumber(sno));
|
||||
|
||||
bool malfunction{};
|
||||
EXPECT_FALSE(unit->performSelfTest(malfunction));
|
||||
|
||||
EXPECT_FALSE(unit->performFactoryReset());
|
||||
|
||||
EXPECT_FALSE(unit->reInit());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unit->writeAmbientPressure(1013));
|
||||
uint16_t pressure{};
|
||||
EXPECT_TRUE(unit->readAmbientPressure(pressure));
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, OnChipOutputSignalCompensation)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
{
|
||||
constexpr float OFFSET{5.4f};
|
||||
EXPECT_TRUE(unit->writeTemperatureOffset(OFFSET));
|
||||
float offset{};
|
||||
EXPECT_TRUE(unit->readTemperatureOffset(offset));
|
||||
EXPECT_EQ(float_to_uint16(offset), float_to_uint16(OFFSET)) << "offset:" << offset << " OFFSET:" << OFFSET;
|
||||
}
|
||||
|
||||
{
|
||||
constexpr uint16_t ALTITUDE{3776};
|
||||
EXPECT_TRUE(unit->writeSensorAltitude(ALTITUDE));
|
||||
uint16_t altitude{};
|
||||
EXPECT_TRUE(unit->readSensorAltitude(altitude));
|
||||
EXPECT_EQ(altitude, ALTITUDE);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr uint16_t PRESSURE{1111};
|
||||
EXPECT_TRUE(unit->writeAmbientPressure(PRESSURE));
|
||||
uint16_t pressure{};
|
||||
EXPECT_TRUE(unit->readAmbientPressure(pressure));
|
||||
EXPECT_EQ(pressure, PRESSURE);
|
||||
|
||||
EXPECT_TRUE(unit->writeAmbientPressure(700));
|
||||
EXPECT_TRUE(unit->readAmbientPressure(pressure));
|
||||
EXPECT_EQ(pressure, 700);
|
||||
|
||||
EXPECT_TRUE(unit->writeAmbientPressure(1200));
|
||||
EXPECT_TRUE(unit->readAmbientPressure(pressure));
|
||||
EXPECT_EQ(pressure, 1200);
|
||||
|
||||
EXPECT_FALSE(unit->writeAmbientPressure(699));
|
||||
EXPECT_FALSE(unit->writeAmbientPressure(1201));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, FieldCalibration)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
{
|
||||
int16_t correction{};
|
||||
EXPECT_TRUE(unit->performForcedRecalibration(1234, correction));
|
||||
}
|
||||
|
||||
{
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationEnabled(false));
|
||||
bool enabled{};
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
EXPECT_FALSE(enabled);
|
||||
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationEnabled(true));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
EXPECT_TRUE(enabled);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr uint16_t PPM{12345};
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationTarget(PPM));
|
||||
uint16_t ppm{};
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationTarget(ppm));
|
||||
EXPECT_EQ(ppm, PPM);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, AdvancedFeatures)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
{
|
||||
// Read direct [MSB] SNB_3, SNB_2, CRC, SNB_1, SNB_0, CRC [LSB]
|
||||
std::array<uint8_t, 9> rbuf{};
|
||||
EXPECT_TRUE(unit->readRegister(m5::unit::scd4x::command::GET_SERIAL_NUMBER, rbuf.data(), rbuf.size(), 1));
|
||||
|
||||
// M5_LOGI("%02x%02x%02x%02x%02x%02x", rbuf[0], rbuf[1], rbuf[3],
|
||||
// rbuf[4],
|
||||
// rbuf[6], rbuf[7]);
|
||||
|
||||
m5::types::big_uint16_t w0(rbuf[0], rbuf[1]);
|
||||
m5::types::big_uint16_t w1(rbuf[3], rbuf[4]);
|
||||
m5::types::big_uint16_t w2(rbuf[6], rbuf[7]);
|
||||
uint64_t d_sno = (((uint64_t)w0.get()) << 32) | (((uint64_t)w1.get()) << 16) | ((uint64_t)w2.get());
|
||||
|
||||
// M5_LOGI("d_sno[%llX]", d_sno);
|
||||
|
||||
//
|
||||
uint64_t sno{};
|
||||
char ssno[13]{};
|
||||
EXPECT_TRUE(unit->readSerialNumber(sno));
|
||||
EXPECT_TRUE(unit->readSerialNumber(ssno));
|
||||
|
||||
// M5_LOGI("s:[%s] uint64:[%x]", ssno, sno);
|
||||
|
||||
EXPECT_EQ(sno, d_sno);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::uppercase << std::setw(12) << std::hex << std::setfill('0') << sno;
|
||||
std::string s(stream.str());
|
||||
EXPECT_STREQ(s.c_str(), ssno);
|
||||
}
|
||||
|
||||
// Set
|
||||
constexpr float OFFSET{1.234f};
|
||||
EXPECT_TRUE(unit->writeTemperatureOffset(OFFSET));
|
||||
constexpr uint16_t ALTITUDE{3776};
|
||||
EXPECT_TRUE(unit->writeSensorAltitude(ALTITUDE));
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationEnabled(false));
|
||||
constexpr uint16_t PPM{12345};
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationTarget(PPM));
|
||||
|
||||
EXPECT_TRUE(unit->writePersistSettings()); // Save EEPROM
|
||||
|
||||
// Overwrite settings
|
||||
EXPECT_TRUE(unit->writeTemperatureOffset(OFFSET * 2));
|
||||
EXPECT_TRUE(unit->writeSensorAltitude(ALTITUDE * 2));
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationEnabled(true));
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationTarget(PPM * 2));
|
||||
|
||||
float off{};
|
||||
uint16_t alt{}, ppm{};
|
||||
bool enabled{};
|
||||
|
||||
EXPECT_TRUE(unit->readTemperatureOffset(off));
|
||||
EXPECT_TRUE(unit->readSensorAltitude(alt));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationTarget(ppm));
|
||||
|
||||
EXPECT_EQ(float_to_uint16(off), float_to_uint16(OFFSET * 2));
|
||||
EXPECT_EQ(alt, ALTITUDE * 2);
|
||||
EXPECT_EQ(ppm, PPM * 2);
|
||||
EXPECT_TRUE(enabled);
|
||||
|
||||
EXPECT_TRUE(unit->reInit()); // Load EEPROM
|
||||
|
||||
// Check saved settings
|
||||
EXPECT_TRUE(unit->readTemperatureOffset(off));
|
||||
EXPECT_TRUE(unit->readSensorAltitude(alt));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationTarget(ppm));
|
||||
|
||||
EXPECT_EQ(float_to_uint16(off), float_to_uint16(OFFSET));
|
||||
EXPECT_EQ(alt, ALTITUDE);
|
||||
EXPECT_EQ(ppm, PPM);
|
||||
EXPECT_FALSE(enabled);
|
||||
|
||||
bool malfunction{};
|
||||
EXPECT_TRUE(unit->performSelfTest(malfunction));
|
||||
|
||||
EXPECT_TRUE(unit->performFactoryReset()); // Reset EEPROM
|
||||
|
||||
EXPECT_TRUE(unit->readTemperatureOffset(off));
|
||||
EXPECT_TRUE(unit->readSensorAltitude(alt));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationEnabled(enabled));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationTarget(ppm));
|
||||
|
||||
EXPECT_NE(float_to_uint16(off), float_to_uint16(OFFSET));
|
||||
EXPECT_NE(alt, ALTITUDE);
|
||||
EXPECT_NE(ppm, PPM);
|
||||
EXPECT_TRUE(enabled);
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->performFactoryReset()); // Reset EEPROM
|
||||
|
||||
uint32_t idx{};
|
||||
for (auto&& m : mode_table) {
|
||||
auto s = m5::utility::formatString("Mode:%u", m);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(m));
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_EQ(unit->updatedMillis(), 0);
|
||||
|
||||
auto it = interval_table[idx];
|
||||
auto elapsed = test_periodic(unit.get(), STORED_SIZE, it);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_NE(elapsed, 0);
|
||||
EXPECT_GE(elapsed, STORED_SIZE * it);
|
||||
|
||||
//
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_TRUE(unit->full());
|
||||
|
||||
uint32_t cnt{STORED_SIZE / 2};
|
||||
while (cnt-- && unit->available()) {
|
||||
EXPECT_NE(unit->co2(), 0);
|
||||
EXPECT_TRUE(std::isfinite(unit->celsius()));
|
||||
EXPECT_TRUE(std::isfinite(unit->fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(unit->humidity()));
|
||||
|
||||
EXPECT_EQ(unit->co2(), unit->oldest().co2());
|
||||
EXPECT_FLOAT_EQ(unit->celsius(), unit->oldest().celsius());
|
||||
EXPECT_FLOAT_EQ(unit->fahrenheit(), unit->oldest().fahrenheit());
|
||||
EXPECT_FLOAT_EQ(unit->humidity(), unit->oldest().humidity());
|
||||
|
||||
EXPECT_FALSE(unit->empty());
|
||||
unit->discard();
|
||||
}
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE / 2);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_FALSE(unit->full());
|
||||
|
||||
unit->flush();
|
||||
EXPECT_EQ(unit->available(), 0);
|
||||
EXPECT_TRUE(unit->empty());
|
||||
EXPECT_FALSE(unit->full());
|
||||
|
||||
EXPECT_EQ(unit->co2(), 0);
|
||||
EXPECT_FALSE(std::isfinite(unit->celsius()));
|
||||
EXPECT_FALSE(std::isfinite(unit->fahrenheit()));
|
||||
EXPECT_FALSE(std::isfinite(unit->humidity()));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue