sTodo-m5paper-client/libraries/M5Unit-ENV/test/embedded/test_bme688/bme688_test.cpp
2025-06-30 20:47:33 +02:00

638 lines
22 KiB
C++

/*
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*
UnitTest for UnitBME688
*/
#include <gtest/gtest.h>
#include <Wire.h>
#include <M5Unified.h>
#include <M5UnitUnified.hpp>
#include <googletest/test_helper.hpp>
#include <googletest/test_template.hpp>
#include <unit/unit_BME688.hpp>
#include <chrono>
#include <random>
#include <set>
using namespace m5::unit::googletest;
using namespace m5::unit;
using namespace m5::unit::bme688;
#if defined(UNIT_BME688_USING_BSEC2)
using namespace m5::unit::bme688::bsec2;
#endif
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
class TestBME688 : public ComponentTestBase<UnitBME688, bool> {
protected:
virtual UnitBME688* get_instance() override
{
auto ptr = new m5::unit::UnitBME688();
auto ccfg = ptr->component_config();
ccfg.stored_size = 8;
ptr->component_config(ccfg);
return ptr;
}
virtual bool is_using_hal() const override
{
return GetParam();
};
};
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestBME688,
// ::testing::Values(false, true));
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestBME688, ::testing::Values(true));
INSTANTIATE_TEST_SUITE_P(ParamValues, TestBME688, ::testing::Values(false));
namespace {
constexpr Oversampling os_table[] = {
Oversampling::None, Oversampling::x1, Oversampling::x1, Oversampling::x2,
Oversampling::x4, Oversampling::x8, Oversampling::x16,
};
constexpr Filter filter_table[] = {
Filter::None, Filter::Coeff_1, Filter::Coeff_3, Filter::Coeff_7,
Filter::Coeff_15, Filter::Coeff_31, Filter::Coeff_63, Filter::Coeff_127,
};
#if defined(UNIT_BME688_USING_BSEC2)
// All outputs
constexpr bsec_virtual_sensor_t vs_table[] = {
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_STABILIZATION_STATUS,
BSEC_OUTPUT_RUN_IN_STATUS,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_GAS_PERCENTAGE,
BSEC_OUTPUT_GAS_ESTIMATE_1,
BSEC_OUTPUT_GAS_ESTIMATE_2,
BSEC_OUTPUT_GAS_ESTIMATE_3,
BSEC_OUTPUT_GAS_ESTIMATE_4,
BSEC_OUTPUT_RAW_GAS_INDEX,
BSEC_OUTPUT_REGRESSION_ESTIMATE_1,
BSEC_OUTPUT_REGRESSION_ESTIMATE_2,
BSEC_OUTPUT_REGRESSION_ESTIMATE_3,
BSEC_OUTPUT_REGRESSION_ESTIMATE_4,
};
// Using BSEC2 library configuration files
constexpr uint8_t bsec_config[] = {
#include <config/bme688/bme688_sel_33v_300s_4d/bsec_selectivity.txt>
};
#endif
auto rng = std::default_random_engine{};
void check_measurement_values(UnitBME688* u)
{
auto latest = u->latest();
// for raw
EXPECT_TRUE(std::isfinite(latest.raw_temperature()));
EXPECT_TRUE(std::isfinite(latest.raw_pressure()));
EXPECT_TRUE(std::isfinite(latest.raw_humidity()));
EXPECT_TRUE(std::isfinite(latest.raw_gas()));
// M5_LOGI("%f/%f/%f/%f", latest.raw_temperature(), latest.raw_pressure(), latest.raw_humidity(), latest.raw_gas());
}
} // namespace
TEST_P(TestBME688, Misc)
{
#if defined(UNIT_BME688_USING_BSEC2)
for (auto&& v : vs_table) {
EXPECT_EQ(subscribe_to_bits(v), 1U << v);
}
auto bits = subscribe_to_bits(
BSEC_OUTPUT_IAQ, BSEC_OUTPUT_STATIC_IAQ, BSEC_OUTPUT_CO2_EQUIVALENT, BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_STABILIZATION_STATUS, BSEC_OUTPUT_RUN_IN_STATUS, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, BSEC_OUTPUT_GAS_PERCENTAGE, BSEC_OUTPUT_GAS_ESTIMATE_1,
BSEC_OUTPUT_GAS_ESTIMATE_2, BSEC_OUTPUT_GAS_ESTIMATE_3, BSEC_OUTPUT_GAS_ESTIMATE_4, BSEC_OUTPUT_RAW_GAS_INDEX,
BSEC_OUTPUT_REGRESSION_ESTIMATE_1, BSEC_OUTPUT_REGRESSION_ESTIMATE_2, BSEC_OUTPUT_REGRESSION_ESTIMATE_3,
BSEC_OUTPUT_REGRESSION_ESTIMATE_4);
constexpr uint32_t val{
1U << BSEC_OUTPUT_IAQ | 1U << BSEC_OUTPUT_STATIC_IAQ | 1U << BSEC_OUTPUT_CO2_EQUIVALENT |
1U << BSEC_OUTPUT_BREATH_VOC_EQUIVALENT | 1U << BSEC_OUTPUT_RAW_TEMPERATURE | 1U << BSEC_OUTPUT_RAW_PRESSURE |
1U << BSEC_OUTPUT_RAW_HUMIDITY | 1U << BSEC_OUTPUT_RAW_GAS | 1U << BSEC_OUTPUT_STABILIZATION_STATUS |
1U << BSEC_OUTPUT_RUN_IN_STATUS | 1U << BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE |
1U << BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY | 1U << BSEC_OUTPUT_GAS_PERCENTAGE |
1U << BSEC_OUTPUT_GAS_ESTIMATE_1 | 1U << BSEC_OUTPUT_GAS_ESTIMATE_2 | 1U << BSEC_OUTPUT_GAS_ESTIMATE_3 |
1U << BSEC_OUTPUT_GAS_ESTIMATE_4 | 1U << BSEC_OUTPUT_RAW_GAS_INDEX | 1U << BSEC_OUTPUT_REGRESSION_ESTIMATE_1 |
1U << BSEC_OUTPUT_REGRESSION_ESTIMATE_2 | 1U << BSEC_OUTPUT_REGRESSION_ESTIMATE_3 |
1U << BSEC_OUTPUT_REGRESSION_ESTIMATE_4};
EXPECT_EQ(bits, val);
#endif
}
TEST_P(TestBME688, Settings)
{
SCOPED_TRACE(ustr);
Oversampling os{};
Filter f{};
uint32_t serial{};
EXPECT_TRUE(unit->readUniqueID(serial));
EXPECT_NE(serial, 0U);
// TPH
for (auto&& e : os_table) {
EXPECT_TRUE(unit->writeOversamplingTemperature(e));
EXPECT_EQ(unit->tphSetting().os_temp, m5::stl::to_underlying(e));
EXPECT_TRUE(unit->readOversamplingTemperature(os));
EXPECT_EQ(os, e);
}
for (auto&& e : os_table) {
EXPECT_TRUE(unit->writeOversamplingPressure(e));
EXPECT_EQ(unit->tphSetting().os_pres, m5::stl::to_underlying(e));
EXPECT_TRUE(unit->readOversamplingPressure(os));
EXPECT_EQ(os, e);
}
for (auto&& e : os_table) {
EXPECT_TRUE(unit->writeOversamplingHumidity(e));
EXPECT_EQ(unit->tphSetting().os_hum, m5::stl::to_underlying(e));
EXPECT_TRUE(unit->readOversamplingHumidity(os));
EXPECT_EQ(os, e);
}
for (auto&& e : filter_table) {
EXPECT_TRUE(unit->writeIIRFilter(e));
EXPECT_EQ(unit->tphSetting().filter, m5::stl::to_underlying(e));
EXPECT_TRUE(unit->readIIRFilter(f));
EXPECT_EQ(f, e);
}
uint32_t cnt{10};
while (cnt--) {
bme68xConf tph = unit->tphSetting();
tph.os_temp = rng() % 0x06;
tph.os_pres = rng() % 0x06;
tph.os_hum = rng() % 0x06;
tph.filter = rng() % 0x07;
// M5_LOGW("%u/%u/%u/%u", tph.os_temp, tph.os_pres, tph.os_hum,
// tph.filter);
EXPECT_TRUE(unit->writeTPHSetting(tph));
EXPECT_EQ(unit->tphSetting().os_temp, tph.os_temp);
EXPECT_EQ(unit->tphSetting().os_pres, tph.os_pres);
EXPECT_EQ(unit->tphSetting().os_hum, tph.os_hum);
bme68xConf after{};
EXPECT_TRUE(unit->readTPHSetting(after));
EXPECT_TRUE(memcmp(&tph, &after, sizeof(tph)) == 0)
<< tph.os_temp << "/" << tph.os_pres << "/" << tph.os_hum << "/" << tph.filter;
EXPECT_TRUE(
unit->writeOversampling((Oversampling)tph.os_temp, (Oversampling)tph.os_pres, (Oversampling)tph.os_hum));
EXPECT_EQ(unit->tphSetting().os_temp, tph.os_temp);
EXPECT_EQ(unit->tphSetting().os_pres, tph.os_pres);
EXPECT_EQ(unit->tphSetting().os_hum, tph.os_hum);
EXPECT_TRUE(unit->readTPHSetting(after));
EXPECT_TRUE(memcmp(&tph, &after, sizeof(tph)) == 0)
<< tph.os_temp << "/" << tph.os_pres << "/" << tph.os_hum << "/" << tph.filter;
}
// Calibration
bme68xCalibration c0{}, c1{};
EXPECT_TRUE(unit->readCalibration(c0));
EXPECT_TRUE(unit->writeCalibration(c0));
EXPECT_TRUE(unit->readCalibration(c1));
EXPECT_TRUE(memcmp(&c0, &c1, sizeof(c1)) == 0);
// softReset rewinds settings
EXPECT_TRUE(unit->softReset());
//
EXPECT_TRUE(unit->readOversamplingTemperature(os));
EXPECT_EQ(os, Oversampling::None);
EXPECT_TRUE(unit->readOversamplingPressure(os));
EXPECT_EQ(os, Oversampling::None);
EXPECT_TRUE(unit->readOversamplingHumidity(os));
EXPECT_EQ(os, Oversampling::None);
EXPECT_TRUE(unit->readIIRFilter(f));
EXPECT_EQ(f, Filter::None);
}
#if defined(UNIT_BME688_USING_BSEC2)
TEST_P(TestBME688, BSEC2)
{
SCOPED_TRACE(ustr);
EXPECT_TRUE(unit->inPeriodic());
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
uint8_t cfg[BSEC_MAX_PROPERTY_BLOB_SIZE]{};
uint8_t state[BSEC_MAX_STATE_BLOB_SIZE]{};
uint8_t state2[BSEC_MAX_STATE_BLOB_SIZE]{};
uint32_t actual{};
EXPECT_TRUE(unit->bsec2GetState(state, actual)); // get current
// Version
auto& ver = unit->bsec2Version();
EXPECT_NE(ver.major, 0);
EXPECT_NE(ver.minor, 0);
// M5_LOGI("bsec2 ver:%u.%u.%u.%u", ver.major, ver.minor, ver.major_bugfix, ver.minor_bugfix);
// Subscribe
constexpr bsec_virtual_sensor_t sensorList[] = {
BSEC_OUTPUT_IAQ, BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS, BSEC_OUTPUT_STABILIZATION_STATUS, BSEC_OUTPUT_RUN_IN_STATUS};
std::vector<bsec_virtual_sensor_t> nosubscribed(vs_table, vs_table + m5::stl::size(vs_table));
auto it = std::remove_if(nosubscribed.begin(), nosubscribed.end(), [&sensorList](bsec_virtual_sensor_t vs) {
auto e = std::begin(sensorList) + m5::stl::size(sensorList);
return std::find(std::begin(sensorList), e, vs) != e;
});
nosubscribed.erase(it, nosubscribed.end());
EXPECT_TRUE(unit->bsec2UpdateSubscription(sensorList, m5::stl::size(sensorList), bsec2::SampleRate::LowPower));
for (auto&& e : sensorList) {
EXPECT_TRUE(unit->bsec2IsSubscribed(e)) << e;
}
for (auto&& e : nosubscribed) {
EXPECT_FALSE(unit->bsec2IsSubscribed(e)) << e;
}
for (auto&& e : sensorList) {
EXPECT_TRUE(unit->bsec2Unsubscribe(e)) << e;
EXPECT_FALSE(unit->bsec2IsSubscribed(e)) << e;
}
for (auto&& e : nosubscribed) {
EXPECT_FALSE(unit->bsec2IsSubscribed(e)) << e;
}
for (auto&& e : sensorList) {
EXPECT_TRUE(unit->bsec2Subscribe(e)) << e;
EXPECT_TRUE(unit->bsec2IsSubscribed(e)) << e;
}
for (auto&& e : nosubscribed) {
EXPECT_FALSE(unit->bsec2IsSubscribed(e)) << e;
}
EXPECT_TRUE(unit->bsec2UnsubscribeAll()); // Same as stop
for (auto&& e : vs_table) {
EXPECT_FALSE(unit->bsec2IsSubscribed(e)) << e;
}
// Measurement
EXPECT_TRUE(unit->startPeriodicMeasurement(sensorList, m5::stl::size(sensorList), bsec2::SampleRate::LowPower));
auto bits = virtual_sensor_array_to_bits(sensorList, m5::stl::size(sensorList));
EXPECT_EQ(unit->bsec2Subscription(), bits);
#if 1
test_periodic_measurement(unit.get(), 8, 8, (unit->interval() * 2) * 8, check_measurement_values, false);
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Sleep);
EXPECT_EQ(unit->available(), 8U);
EXPECT_FALSE(unit->empty());
EXPECT_TRUE(unit->full());
uint32_t cnt{4};
while (unit->available() && cnt--) {
EXPECT_TRUE(std::isfinite(unit->iaq()));
EXPECT_TRUE(std::isfinite(unit->temperature()));
EXPECT_TRUE(std::isfinite(unit->pressure()));
EXPECT_TRUE(std::isfinite(unit->humidity()));
EXPECT_TRUE(std::isfinite(unit->gas()));
EXPECT_FLOAT_EQ(unit->iaq(), unit->oldest().iaq());
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
EXPECT_FLOAT_EQ(unit->pressure(), unit->oldest().pressure());
EXPECT_FLOAT_EQ(unit->humidity(), unit->oldest().humidity());
EXPECT_FLOAT_EQ(unit->gas(), unit->oldest().gas());
EXPECT_FALSE(unit->empty());
unit->discard();
}
#else
uint32_t cnt{8};
while (cnt--) {
auto now{m5::utility::millis()};
auto timeout_at = now + 3 * 1000; // LowPower
do {
unit->update();
now = m5::utility::millis();
if (unit->updated()) {
break;
}
m5::utility::delay(1);
} while (now <= timeout_at);
// M5_LOGW("now:%ld timeout_at:%ld", now, timeout_at);
EXPECT_TRUE(unit->updated());
if (cnt < 2) {
EXPECT_LE(now, timeout_at);
}
auto d = unit->latest();
for (auto&& vs : sensorList) {
float f = d.get(vs);
// M5_LOGI("[%u]:%.2f", vs, f);
EXPECT_TRUE(std::isfinite(f)) << vs;
}
for (auto&& vs : nosubscribed) {
float f = d.get(vs);
EXPECT_FALSE(std::isfinite(f)) << vs;
}
}
EXPECT_TRUE(unit->inPeriodic());
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
EXPECT_EQ(unit->available(), 8U);
EXPECT_FALSE(unit->empty());
EXPECT_TRUE(unit->full());
cnt = 4;
while (unit->available() && cnt--) {
EXPECT_TRUE(std::isfinite(unit->iaq()));
EXPECT_TRUE(std::isfinite(unit->temperature()));
EXPECT_TRUE(std::isfinite(unit->pressure()));
EXPECT_TRUE(std::isfinite(unit->humidity()));
EXPECT_TRUE(std::isfinite(unit->gas()));
EXPECT_FLOAT_EQ(unit->iaq(), unit->oldest().iaq());
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
EXPECT_FLOAT_EQ(unit->pressure(), unit->oldest().pressure());
EXPECT_FLOAT_EQ(unit->humidity(), unit->oldest().humidity());
EXPECT_FLOAT_EQ(unit->gas(), unit->oldest().gas());
EXPECT_FALSE(unit->empty());
unit->discard();
}
#endif
EXPECT_EQ(unit->available(), 4U);
EXPECT_FALSE(unit->empty());
EXPECT_FALSE(unit->full());
unit->flush();
EXPECT_EQ(unit->available(), 0U);
EXPECT_TRUE(unit->empty());
EXPECT_FALSE(unit->full());
// Config
EXPECT_EQ(sizeof(bsec_config), BSEC_MAX_PROPERTY_BLOB_SIZE);
EXPECT_TRUE(unit->bsec2GetConfig(cfg, actual)); // get current
EXPECT_NE(memcmp(cfg, bsec_config, actual), 0);
EXPECT_TRUE(unit->bsec2SetConfig(bsec_config)); // overwrite
EXPECT_TRUE(unit->bsec2GetConfig(cfg, actual));
auto cmp = memcmp(cfg, bsec_config, actual) == 0;
EXPECT_TRUE(cmp);
if (!cmp) {
M5_DUMPI(cfg, actual);
M5_DUMPI(bsec_config, actual);
}
// State
EXPECT_TRUE(unit->bsec2GetState(state2, actual)); // get current
cmp = memcmp(state2, state, actual) == 0;
EXPECT_FALSE(cmp);
EXPECT_TRUE(unit->bsec2SetState(state)); // rewrite
EXPECT_TRUE(unit->bsec2GetState(state2, actual)); // get
cmp = memcmp(state2, state, actual) == 0;
if (!cmp) {
M5_DUMPI(state, actual);
M5_DUMPI(state2, actual);
}
}
#endif
TEST_P(TestBME688, SingleShot)
{
SCOPED_TRACE(ustr);
bme68xConf tph{};
tph.os_temp = m5::stl::to_underlying(Oversampling::x2);
tph.os_pres = m5::stl::to_underlying(Oversampling::x1);
tph.os_hum = m5::stl::to_underlying(Oversampling::x16);
tph.filter = m5::stl::to_underlying(Filter::None);
tph.odr = m5::stl::to_underlying(ODR::None);
EXPECT_TRUE(unit->writeTPHSetting(tph));
m5::unit::bme688::bme68xHeatrConf hs{};
hs.enable = true;
hs.heatr_temp = 300;
hs.heatr_dur = 100;
EXPECT_TRUE(unit->writeHeaterSetting(Mode::Forced, hs));
bme68xData data{};
EXPECT_TRUE(unit->inPeriodic());
EXPECT_FALSE(unit->measureSingleShot(data));
EXPECT_TRUE(unit->stopPeriodicMeasurement());
Mode m{};
EXPECT_TRUE(unit->readMode(m));
EXPECT_EQ(m, Mode::Sleep);
EXPECT_FALSE(unit->inPeriodic());
EXPECT_TRUE(unit->measureSingleShot(data));
#if 0
M5_LOGI(
"Status:%u\n"
"Gidx:%u Midx:%u\n"
"ResHeate:%u IDAC:%u GasWait:%u\n"
"T:%f P:%f H:%f R:%f",
data.status, data.gas_index, data.meas_index, data.res_heat, data.idac, data.gas_wait, data.temperature,
data.pressure, data.humidity, data.gas_resistance);
#endif
}
TEST_P(TestBME688, PeriodicForced)
{
SCOPED_TRACE(ustr);
EXPECT_TRUE(unit->inPeriodic());
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
bme68xConf tph{};
tph.os_temp = m5::stl::to_underlying(Oversampling::x2);
tph.os_pres = m5::stl::to_underlying(Oversampling::x1);
tph.os_hum = m5::stl::to_underlying(Oversampling::x16);
tph.filter = m5::stl::to_underlying(Filter::None);
tph.odr = m5::stl::to_underlying(ODR::None);
EXPECT_TRUE(unit->writeTPHSetting(tph));
m5::unit::bme688::bme68xHeatrConf hs{};
hs.enable = true;
hs.heatr_temp = 300;
hs.heatr_dur = 100;
EXPECT_TRUE(unit->writeHeaterSetting(Mode::Forced, hs));
//
EXPECT_FALSE(unit->inPeriodic());
EXPECT_TRUE(unit->startPeriodicMeasurement(Mode::Forced));
EXPECT_TRUE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Forced);
// Always wait for an interval to obtain the correct value for the first measurement
// EXPECT_EQ(unit->updatedMillis(), 0); //
EXPECT_EQ(unit->available(), 0U);
EXPECT_TRUE(unit->empty());
EXPECT_FALSE(unit->full());
test_periodic_measurement(unit.get(), 8, 8, (unit->interval() * 2) * 8, check_measurement_values, false);
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Sleep);
EXPECT_EQ(unit->available(), 8U);
EXPECT_FALSE(unit->empty());
EXPECT_TRUE(unit->full());
uint32_t cnt{4};
while (unit->available() && cnt--) {
EXPECT_TRUE(std::isfinite(unit->oldest().raw_temperature()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_pressure()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_humidity()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_gas()));
EXPECT_FALSE(unit->empty());
unit->discard();
}
EXPECT_EQ(unit->available(), 4U);
EXPECT_FALSE(unit->empty());
EXPECT_FALSE(unit->full());
unit->flush();
EXPECT_EQ(unit->available(), 0U);
EXPECT_TRUE(unit->empty());
EXPECT_FALSE(unit->full());
}
TEST_P(TestBME688, PeriodicParallel)
{
SCOPED_TRACE(ustr);
EXPECT_TRUE(unit->inPeriodic());
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
uint16_t temp_prof[10] = {320, 100, 100, 100, 200, 200, 200, 320, 320, 320};
/* Multiplier to the shared heater duration */
uint16_t mul_prof[10] = {5, 2, 10, 30, 5, 5, 5, 5, 5, 5};
bme68xConf tph{};
tph.os_temp = m5::stl::to_underlying(Oversampling::x2);
tph.os_pres = m5::stl::to_underlying(Oversampling::x1);
tph.os_hum = m5::stl::to_underlying(Oversampling::x16);
tph.filter = m5::stl::to_underlying(Filter::None);
tph.odr = m5::stl::to_underlying(ODR::None);
EXPECT_TRUE(unit->writeTPHSetting(tph));
m5::unit::bme688::bme68xHeatrConf hs{};
hs.enable = true;
memcpy(hs.temp_prof, temp_prof, sizeof(temp_prof));
memcpy(hs.dur_prof, mul_prof, sizeof(mul_prof));
hs.shared_heatr_dur = (uint16_t)(140 - (unit->calculateMeasurementInterval(Mode::Parallel, tph) / 1000));
hs.profile_len = 10;
EXPECT_TRUE(unit->writeHeaterSetting(Mode::Parallel, hs));
//
EXPECT_FALSE(unit->inPeriodic());
EXPECT_TRUE(unit->startPeriodicMeasurement(Mode::Parallel));
EXPECT_TRUE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Parallel);
EXPECT_EQ(unit->available(), 0U);
EXPECT_TRUE(unit->empty());
EXPECT_FALSE(unit->full());
// TODO : What are the measurement intervals in the parallel mode datasheet?
test_periodic_measurement(unit.get(), 8, 1, (unit->interval() * 10) * 10, check_measurement_values, false);
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Sleep);
EXPECT_EQ(unit->available(), 8U);
EXPECT_FALSE(unit->empty());
EXPECT_TRUE(unit->full());
uint32_t cnt{4};
while (unit->available() && cnt--) {
EXPECT_TRUE(std::isfinite(unit->oldest().raw_temperature()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_pressure()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_humidity()));
EXPECT_TRUE(std::isfinite(unit->oldest().raw_gas()));
EXPECT_FALSE(unit->empty());
unit->discard();
}
EXPECT_EQ(unit->available(), 4U);
EXPECT_FALSE(unit->empty());
EXPECT_FALSE(unit->full());
unit->flush();
EXPECT_EQ(unit->available(), 0U);
EXPECT_TRUE(unit->empty());
EXPECT_FALSE(unit->full());
}
TEST_P(TestBME688, PeriodiSequential)
{
SCOPED_TRACE(ustr);
EXPECT_TRUE(unit->inPeriodic());
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
uint16_t temp_prof[10] = {200, 240, 280, 320, 360, 360, 320, 280, 240, 200};
/* Heating duration in milliseconds */
uint16_t dur_prof[10] = {100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
bme68xConf tph{};
tph.os_temp = m5::stl::to_underlying(Oversampling::x2);
tph.os_pres = m5::stl::to_underlying(Oversampling::x1);
tph.os_hum = m5::stl::to_underlying(Oversampling::x16);
tph.filter = m5::stl::to_underlying(Filter::None);
tph.odr = m5::stl::to_underlying(ODR::None);
EXPECT_TRUE(unit->writeTPHSetting(tph));
m5::unit::bme688::bme68xHeatrConf hs{};
hs.enable = true;
memcpy(hs.temp_prof, temp_prof, sizeof(temp_prof));
memcpy(hs.dur_prof, dur_prof, sizeof(dur_prof));
hs.profile_len = 10;
EXPECT_TRUE(unit->writeHeaterSetting(Mode::Sequential, hs));
//
EXPECT_FALSE(unit->inPeriodic());
EXPECT_TRUE(unit->startPeriodicMeasurement(Mode::Sequential));
EXPECT_TRUE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Sequential);
test_periodic_measurement(unit.get(), 8, 1, (unit->interval() * 2) * 8, check_measurement_values, false);
EXPECT_TRUE(unit->stopPeriodicMeasurement());
EXPECT_FALSE(unit->inPeriodic());
EXPECT_EQ(unit->mode(), Mode::Sleep);
}
TEST_P(TestBME688, SelfTest)
{
SCOPED_TRACE(ustr);
EXPECT_TRUE(unit->selfTest());
}