first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
60
libraries/M5Unit-ENV/test/common_main.cpp
Normal file
60
libraries/M5Unit-ENV/test/common_main.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
main for UnitTest on native
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// C++ version
|
||||
#if __cplusplus >= 202002L
|
||||
#pragma message "C++20 or later"
|
||||
#elif __cplusplus >= 201703L
|
||||
#pragma message "C++17 or later"
|
||||
#elif __cplusplus >= 201402L
|
||||
#pragma message "C++14 or later"
|
||||
#elif __cplusplus >= 201103L
|
||||
#pragma message "C++11 or later"
|
||||
#else
|
||||
#error "Need C++11 or later"
|
||||
#endif
|
||||
// Compiler
|
||||
#if defined(__clang__)
|
||||
#pragma message "Clang"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma message "MSVC"
|
||||
#elif defined(__BORLANDC__)
|
||||
#pragma message "BORLANDC"
|
||||
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma message "MINGW"
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
#pragma message "ICC"
|
||||
#elif defined(__GNUG__)
|
||||
#pragma message "GCC"
|
||||
#else
|
||||
#pragma message "Unknown compiler"
|
||||
#endif
|
||||
|
||||
/*
|
||||
For native test, this main() is used.
|
||||
If the Arduino framework is used, the framework library main is used.
|
||||
*/
|
||||
#if !defined(ARDUINO)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
#ifdef GTEST_FILTER
|
||||
::testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
RUN_ALL_TESTS();
|
||||
#pragma GCC diagnostic pop
|
||||
// Always return zero-code and allow PlatformIO to parse results
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
61
libraries/M5Unit-ENV/test/embedded/embedded_main.cpp
Normal file
61
libraries/M5Unit-ENV/test/embedded/embedded_main.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
main for UnitTest on embedded
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Unified.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
#pragma message "Embedded setup/loop"
|
||||
|
||||
#if __has_include(<esp_idf_version.h>)
|
||||
#include <esp_idf_version.h>
|
||||
#else // esp_idf_version.h has been introduced in Arduino 1.0.5 (ESP-IDF3.3)
|
||||
#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||
#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(3, 2, 0)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
auto& lcd = M5.Display;
|
||||
} // namespace
|
||||
|
||||
void test()
|
||||
{
|
||||
lcd.fillRect(0, 0, lcd.width() >> 1, lcd.height(), RUN_ALL_TESTS() ? TFT_RED : TFT_GREEN);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
delay(1500);
|
||||
|
||||
M5.begin();
|
||||
|
||||
M5_LOGI("CPP %ld", __cplusplus);
|
||||
M5_LOGI("ESP-IDF Version %d.%d.%d", (ESP_IDF_VERSION >> 16) & 0xFF, (ESP_IDF_VERSION >> 8) & 0xFF,
|
||||
ESP_IDF_VERSION & 0xFF);
|
||||
M5_LOGI("BOARD:%X", M5.getBoard());
|
||||
M5_LOGI("Heap: %u", esp_get_free_heap_size());
|
||||
|
||||
lcd.clear(TFT_DARKGRAY);
|
||||
::testing::InitGoogleTest();
|
||||
|
||||
#ifdef GTEST_FILTER
|
||||
::testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
test();
|
||||
#if 0
|
||||
delay(1000);
|
||||
esp_restart();
|
||||
#endif
|
||||
while (true) {
|
||||
delay(10000);
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
638
libraries/M5Unit-ENV/test/embedded/test_bme688/bme688_test.cpp
Normal file
638
libraries/M5Unit-ENV/test/embedded/test_bme688/bme688_test.cpp
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
526
libraries/M5Unit-ENV/test/embedded/test_bmp280/bmp280_test.cpp
Normal file
526
libraries/M5Unit-ENV/test/embedded/test_bmp280/bmp280_test.cpp
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitBMP280
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_BMP280.hpp>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::bmp280;
|
||||
using namespace m5::unit::bmp280::command;
|
||||
using m5::unit::types::elapsed_time_t;
|
||||
|
||||
constexpr uint32_t STORED_SIZE{8};
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
class TestBMP280 : public ComponentTestBase<UnitBMP280, bool> {
|
||||
protected:
|
||||
virtual UnitBMP280* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitBMP280();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
|
||||
void print_ctrl_measurement(const char* msg = "")
|
||||
{
|
||||
uint8_t v{};
|
||||
unit->readRegister8(CONTROL_MEASUREMENT, v, 0);
|
||||
M5_LOGI("%s CM:%02X", msg, v);
|
||||
}
|
||||
void print_status(const char* msg = "")
|
||||
{
|
||||
uint8_t v{};
|
||||
unit->readRegister8(GET_STATUS, v, 0);
|
||||
M5_LOGI("%s S:%02X", msg, v);
|
||||
}
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestBMP280,
|
||||
// ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestBMP280, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestBMP280, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr Oversampling os_table[] = {
|
||||
Oversampling::Skipped, Oversampling::X1, Oversampling::X2, Oversampling::X4, Oversampling::X8, Oversampling::X16,
|
||||
};
|
||||
|
||||
constexpr OversamplingSetting oss_table[] = {
|
||||
OversamplingSetting::UltraLowPower, OversamplingSetting::LowPower,
|
||||
OversamplingSetting::StandardResolution, OversamplingSetting::HighResolution,
|
||||
OversamplingSetting::UltraHighResolution,
|
||||
};
|
||||
|
||||
constexpr Oversampling osrss_table[][2] = {
|
||||
// Pressure, Temperature
|
||||
{Oversampling::X1, Oversampling::X1}, {Oversampling::X2, Oversampling::X1}, {Oversampling::X4, Oversampling::X1},
|
||||
{Oversampling::X8, Oversampling::X1}, {Oversampling::X16, Oversampling::X2},
|
||||
};
|
||||
|
||||
constexpr Filter filter_table[] = {
|
||||
Filter::Off, Filter::Coeff2, Filter::Coeff4, Filter::Coeff8, Filter::Coeff16,
|
||||
|
||||
};
|
||||
|
||||
constexpr Standby standby_table[] = {
|
||||
Standby::Time0_5ms, Standby::Time62_5ms, Standby::Time125ms, Standby::Time250ms,
|
||||
Standby::Time500ms, Standby::Time1sec, Standby::Time2sec, Standby::Time4sec,
|
||||
};
|
||||
|
||||
constexpr uint32_t standby_time_table[] = {1, 63, 125, 250, 500, 1000, 2000, 4000};
|
||||
|
||||
constexpr PowerMode pw_table[] = {
|
||||
PowerMode::Sleep,
|
||||
PowerMode::Forced,
|
||||
PowerMode::Normal,
|
||||
};
|
||||
|
||||
constexpr UseCase uc_table[] = {
|
||||
UseCase::LowPower, UseCase::Dynamic, UseCase::Weather, UseCase::Elevator, UseCase::Drop, UseCase::Indoor,
|
||||
};
|
||||
|
||||
struct UseCaseSetting {
|
||||
OversamplingSetting osrss;
|
||||
Filter filter;
|
||||
Standby st;
|
||||
};
|
||||
constexpr UseCaseSetting uc_val_table[] = {
|
||||
{OversamplingSetting::UltraHighResolution, Filter::Coeff4, Standby::Time62_5ms},
|
||||
{OversamplingSetting::StandardResolution, Filter::Coeff16, Standby::Time0_5ms},
|
||||
{OversamplingSetting::UltraLowPower, Filter::Off, Standby::Time4sec},
|
||||
{OversamplingSetting::StandardResolution, Filter::Coeff4, Standby::Time125ms},
|
||||
{OversamplingSetting::LowPower, Filter::Off, Standby::Time0_5ms},
|
||||
{OversamplingSetting::UltraHighResolution, Filter::Coeff16, Standby::Time0_5ms},
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
// m5::utility::delay(1);
|
||||
|
||||
} while (measured < times && m5::utility::millis() <= timeout_at);
|
||||
return (measured == times) ? m5::utility::millis() - start_at : 0;
|
||||
|
||||
// return (measured == times) ? unit->updatedMillis() - start_at : 0;
|
||||
}
|
||||
|
||||
uint32_t calculate_measure_time(const Oversampling osrsP, const Oversampling osrsT, const Filter f)
|
||||
{
|
||||
uint32_t px = ((1U << m5::stl::to_underlying(osrsP) >> 1));
|
||||
uint32_t tx = ((1U << m5::stl::to_underlying(osrsT) >> 1));
|
||||
// uint32_t fx = (1U << m5::stl::to_underlying(f));
|
||||
// if (fx == 1) {
|
||||
// fx = 0;
|
||||
// }
|
||||
|
||||
// M5_LOGI("%u,%u,%u => %u,%u,%u", osrsP, osrsT, f,
|
||||
// px,tx,fx);
|
||||
|
||||
float pt = 2.3f * px;
|
||||
float tt = 2.3f * tx;
|
||||
// float ft = 0.5f * fx;
|
||||
return pt + tt + 0.5f;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestBMP280, Settings)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
// Oversampling
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
auto s = m5::utility::formatString("OSRS:%u/%u", po, to);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_FALSE(unit->writeOversampling(po, to));
|
||||
EXPECT_FALSE(unit->writeOversamplingPressure(po));
|
||||
EXPECT_FALSE(unit->writeOversamplingTemperature(to));
|
||||
}
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
Oversampling p;
|
||||
Oversampling t;
|
||||
|
||||
auto s = m5::utility::formatString("OSRS:%u/%u", po, to);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversampling(po, to));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, po);
|
||||
EXPECT_EQ(t, to);
|
||||
|
||||
// Write reverse settings and check
|
||||
EXPECT_TRUE(unit->writeOversamplingPressure(to));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, to);
|
||||
EXPECT_EQ(t, to);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversamplingTemperature(po));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, to);
|
||||
EXPECT_EQ(t, po);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OversamplingSettings
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto& oss : oss_table) {
|
||||
auto s = m5::utility::formatString("OSS:%u", oss);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeOversampling(oss));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
uint32_t idx{};
|
||||
for (auto& oss : oss_table) {
|
||||
auto s = m5::utility::formatString("OSS:%u", oss);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversampling(oss));
|
||||
|
||||
Oversampling p;
|
||||
Oversampling t;
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, osrss_table[idx][0]);
|
||||
EXPECT_EQ(t, osrss_table[idx][1]);
|
||||
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : filter_table) {
|
||||
auto s = m5::utility::formatString("F:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_FALSE(unit->writeFilter(e));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : filter_table) {
|
||||
auto s = m5::utility::formatString("F:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeFilter(e));
|
||||
|
||||
Filter f;
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_EQ(f, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Standby
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto&& e : standby_table) {
|
||||
auto s = m5::utility::formatString("ST:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeStandbyTime(e));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& e : standby_table) {
|
||||
auto s = m5::utility::formatString("ST:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeStandbyTime(e));
|
||||
|
||||
Standby st;
|
||||
EXPECT_TRUE(unit->readStandbyTime(st));
|
||||
EXPECT_EQ(st, e);
|
||||
}
|
||||
}
|
||||
|
||||
// PowerMode
|
||||
if (1) {
|
||||
for (auto&& pw : pw_table) {
|
||||
auto s = m5::utility::formatString("PM:%u", pw);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writePowerMode(pw));
|
||||
|
||||
PowerMode p{};
|
||||
EXPECT_TRUE(unit->readPowerMode(p));
|
||||
EXPECT_EQ(p, pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestBMP280, UseCase)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
// This process fails during periodic measurements.
|
||||
for (auto&& uc : uc_table) {
|
||||
auto s = m5::utility::formatString("UC:%u", uc);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeUseCaseSetting(uc));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& uc : uc_table) {
|
||||
auto s = m5::utility::formatString("UC:%u", uc);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeUseCaseSetting(uc));
|
||||
|
||||
Oversampling p{};
|
||||
Oversampling t{};
|
||||
Filter f{};
|
||||
Standby st{};
|
||||
const auto& val = uc_val_table[m5::stl::to_underlying(uc)];
|
||||
const auto& osrrs = osrss_table[m5::stl::to_underlying(val.osrss)];
|
||||
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_TRUE(unit->readStandbyTime(st));
|
||||
|
||||
EXPECT_EQ(p, osrrs[0]);
|
||||
EXPECT_EQ(t, osrrs[1]);
|
||||
EXPECT_EQ(f, val.filter);
|
||||
EXPECT_EQ(st, val.st);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestBMP280, Reset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
Oversampling p{}, t{};
|
||||
Filter f{};
|
||||
Standby s{};
|
||||
PowerMode pm{};
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_TRUE(unit->readStandbyTime(s));
|
||||
EXPECT_TRUE(unit->readPowerMode(pm));
|
||||
|
||||
EXPECT_NE(p, Oversampling::Skipped);
|
||||
EXPECT_NE(t, Oversampling::Skipped);
|
||||
EXPECT_NE(f, Filter::Off);
|
||||
EXPECT_NE(s, Standby::Time0_5ms);
|
||||
EXPECT_EQ(pm, PowerMode::Normal);
|
||||
|
||||
EXPECT_TRUE(unit->softReset());
|
||||
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_TRUE(unit->readStandbyTime(s));
|
||||
EXPECT_TRUE(unit->readPowerMode(pm));
|
||||
|
||||
EXPECT_EQ(p, Oversampling::Skipped);
|
||||
EXPECT_EQ(t, Oversampling::Skipped);
|
||||
EXPECT_EQ(f, Filter::Off);
|
||||
EXPECT_EQ(s, Standby::Time0_5ms);
|
||||
EXPECT_EQ(pm, PowerMode::Sleep);
|
||||
}
|
||||
|
||||
TEST_P(TestBMP280, SingleShot)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
bmp280::Data discard{};
|
||||
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_FALSE(unit->measureSingleshot(discard));
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
// Standby time for periodic measurement, does not affect single shots
|
||||
EXPECT_TRUE(unit->writeStandbyTime(Standby::Time4sec));
|
||||
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
for (auto&& coeff : filter_table) {
|
||||
auto s = m5::utility::formatString("Singleshot OS:%u/%u F:%u", po, to, coeff);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
// Specify settings and measure
|
||||
bmp280::Data d{};
|
||||
bool can_not_measure = to == Oversampling::Skipped;
|
||||
bool only_temperature = to != Oversampling::Skipped && po == Oversampling::Skipped;
|
||||
|
||||
// M5_LOGI("%s:<%u><%u>", s.c_str(), can_not_measure, only_temperature);
|
||||
|
||||
if (can_not_measure) {
|
||||
EXPECT_FALSE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
} else if (only_temperature) {
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
// M5_LOGI("%f/%f", d.celsius(), d.pressure());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(d.celsius()));
|
||||
EXPECT_TRUE(std::isfinite(d.fahrenheit()));
|
||||
EXPECT_FALSE(std::isfinite(d.pressure()));
|
||||
} else {
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
// M5_LOGI("%f/%f", d.celsius(), d.pressure());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(d.celsius()));
|
||||
EXPECT_TRUE(std::isfinite(d.fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(d.pressure()));
|
||||
}
|
||||
|
||||
if (!can_not_measure) {
|
||||
Oversampling t;
|
||||
Oversampling p;
|
||||
Filter f;
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_EQ(p, po);
|
||||
EXPECT_EQ(t, to);
|
||||
EXPECT_EQ(f, coeff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestBMP280, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& uc : uc_table) {
|
||||
auto s = m5::utility::formatString("UC:%u", uc);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
const auto& val = uc_val_table[m5::stl::to_underlying(uc)];
|
||||
const auto& osrrs = osrss_table[m5::stl::to_underlying(val.osrss)];
|
||||
elapsed_time_t tm{};
|
||||
|
||||
if (val.st == Standby::Time0_5ms) {
|
||||
tm = calculate_measure_time(osrrs[0], osrrs[1], val.filter);
|
||||
} else {
|
||||
tm = standby_time_table[m5::stl::to_underlying(val.st)];
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unit->writeUseCaseSetting(uc));
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
auto elapsed = test_periodic(unit.get(), STORED_SIZE, tm);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
// M5_LOGW("E:%ld tm:%ld/%ld", elapsed, tm, tm * STORED_SIZE);
|
||||
|
||||
EXPECT_NE(elapsed, 0);
|
||||
EXPECT_LE(elapsed, STORED_SIZE * tm);
|
||||
|
||||
//
|
||||
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_TRUE(std::isfinite(unit->temperature()));
|
||||
EXPECT_TRUE(std::isfinite(unit->fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(unit->pressure()));
|
||||
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
|
||||
EXPECT_FLOAT_EQ(unit->pressure(), unit->oldest().pressure());
|
||||
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_FALSE(std::isfinite(unit->temperature()));
|
||||
EXPECT_FALSE(std::isfinite(unit->pressure()));
|
||||
}
|
||||
}
|
||||
499
libraries/M5Unit-ENV/test/embedded/test_qmp6988/qmp6988_test.cpp
Normal file
499
libraries/M5Unit-ENV/test/embedded/test_qmp6988/qmp6988_test.cpp
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitQMP6988
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_QMP6988.hpp>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::qmp6988;
|
||||
using namespace m5::unit::qmp6988::command;
|
||||
using m5::unit::types::elapsed_time_t;
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
constexpr uint32_t STORED_SIZE{8};
|
||||
|
||||
class TestQMP6988 : public ComponentTestBase<UnitQMP6988, bool> {
|
||||
protected:
|
||||
virtual UnitQMP6988* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitQMP6988();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestQMP6988,
|
||||
// ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestQMP6988, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestQMP6988, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
constexpr Oversampling os_table[] = {
|
||||
Oversampling::Skipped, Oversampling::X1, Oversampling::X2, Oversampling::X4,
|
||||
Oversampling::X8, Oversampling::X16, Oversampling::X32, Oversampling::X64,
|
||||
};
|
||||
|
||||
constexpr OversamplingSetting oss_table[] = {
|
||||
OversamplingSetting::HighSpeed, OversamplingSetting::LowPower, OversamplingSetting::Standard,
|
||||
OversamplingSetting::HighAccuracy, OversamplingSetting::UltraHightAccuracy,
|
||||
};
|
||||
|
||||
constexpr Oversampling osrss_table[][2] = {
|
||||
// Pressure, Temperature
|
||||
{Oversampling::X2, Oversampling::X1}, {Oversampling::X4, Oversampling::X1}, {Oversampling::X8, Oversampling::X1},
|
||||
{Oversampling::X16, Oversampling::X2}, {Oversampling::X32, Oversampling::X4},
|
||||
};
|
||||
|
||||
constexpr Filter filter_table[] = {
|
||||
Filter::Off, Filter::Coeff2, Filter::Coeff4, Filter::Coeff8, Filter::Coeff16, Filter::Coeff32,
|
||||
|
||||
};
|
||||
|
||||
constexpr Standby standby_table[] = {
|
||||
Standby::Time1ms, Standby::Time5ms, Standby::Time50ms, Standby::Time250ms,
|
||||
Standby::Time500ms, Standby::Time1sec, Standby::Time2sec, Standby::Time4sec,
|
||||
};
|
||||
|
||||
constexpr PowerMode pw_table[] = {
|
||||
PowerMode::Sleep,
|
||||
PowerMode::Forced,
|
||||
PowerMode::Normal,
|
||||
};
|
||||
|
||||
constexpr UseCase uc_table[] = {
|
||||
UseCase::Weather, UseCase::Drop, UseCase::Elevator, UseCase::Stair, UseCase::Indoor,
|
||||
};
|
||||
|
||||
struct UseCaseSetting {
|
||||
OversamplingSetting osrss;
|
||||
Filter filter;
|
||||
};
|
||||
|
||||
constexpr UseCaseSetting uc_val_table[] = {
|
||||
{OversamplingSetting::HighSpeed, Filter::Off},
|
||||
{OversamplingSetting::LowPower, Filter::Off},
|
||||
{OversamplingSetting::Standard, Filter::Coeff4},
|
||||
{OversamplingSetting::HighAccuracy, Filter::Coeff8},
|
||||
{OversamplingSetting::UltraHightAccuracy, Filter::Coeff32},
|
||||
};
|
||||
|
||||
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() + 8 * 1000;
|
||||
// First measured
|
||||
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;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
// m5::utility::delay(1);
|
||||
|
||||
} while (measured < times && m5::utility::millis() <= timeout_at);
|
||||
|
||||
if (measured == times) {
|
||||
return m5::utility::millis() - start_at;
|
||||
}
|
||||
M5_LOGE("measured:%u", measured);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestQMP6988, Settings)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
// Oversampling
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
auto s = m5::utility::formatString("OSRS:%u/%u", po, to);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_FALSE(unit->writeOversampling(po, to));
|
||||
EXPECT_FALSE(unit->writeOversamplingPressure(po));
|
||||
EXPECT_FALSE(unit->writeOversamplingTemperature(to));
|
||||
}
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
Oversampling p;
|
||||
Oversampling t;
|
||||
|
||||
auto s = m5::utility::formatString("OSRS:%u/%u", po, to);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversampling(po, to));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, po);
|
||||
EXPECT_EQ(t, to);
|
||||
|
||||
// Write reverse settings and check
|
||||
EXPECT_TRUE(unit->writeOversamplingPressure(to));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, to);
|
||||
EXPECT_EQ(t, to);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversamplingTemperature(po));
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, to);
|
||||
EXPECT_EQ(t, po);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OversamplingSettings
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto& oss : oss_table) {
|
||||
auto s = m5::utility::formatString("OSS:%u", oss);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeOversampling(oss));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
uint32_t idx{};
|
||||
for (auto& oss : oss_table) {
|
||||
auto s = m5::utility::formatString("OSS:%u", oss);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writeOversampling(oss));
|
||||
|
||||
Oversampling p;
|
||||
Oversampling t;
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_EQ(p, osrss_table[idx][0]);
|
||||
EXPECT_EQ(t, osrss_table[idx][1]);
|
||||
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : filter_table) {
|
||||
auto s = m5::utility::formatString("F:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_FALSE(unit->writeFilter(e));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : filter_table) {
|
||||
auto s = m5::utility::formatString("F:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeFilter(e));
|
||||
|
||||
Filter f;
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_EQ(f, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Standby
|
||||
if (1) {
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto&& e : standby_table) {
|
||||
auto s = m5::utility::formatString("ST:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeStandbyTime(e));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& e : standby_table) {
|
||||
auto s = m5::utility::formatString("ST:%u", e);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeStandbyTime(e));
|
||||
|
||||
Standby st;
|
||||
EXPECT_TRUE(unit->readStandbyTime(st));
|
||||
EXPECT_EQ(st, e);
|
||||
}
|
||||
}
|
||||
|
||||
// PowerMode
|
||||
if (1) {
|
||||
for (auto&& pw : pw_table) {
|
||||
auto s = m5::utility::formatString("PM:%u", pw);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->writePowerMode(pw));
|
||||
|
||||
PowerMode p{};
|
||||
EXPECT_TRUE(unit->readPowerMode(p));
|
||||
EXPECT_EQ(p, pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestQMP6988, UseCase)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
// This process fails during periodic measurements.
|
||||
for (auto&& uc : uc_table) {
|
||||
auto s = m5::utility::formatString("UC:%u", uc);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->writeUseCaseSetting(uc));
|
||||
}
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
for (auto&& uc : uc_table) {
|
||||
auto s = m5::utility::formatString("UC:%u", uc);
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_TRUE(unit->writeUseCaseSetting(uc));
|
||||
|
||||
Oversampling p{};
|
||||
Oversampling t{};
|
||||
Filter f{};
|
||||
const auto& val = uc_val_table[m5::stl::to_underlying(uc)];
|
||||
const auto& osrrs = osrss_table[m5::stl::to_underlying(val.osrss)];
|
||||
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
|
||||
EXPECT_EQ(p, osrrs[0]);
|
||||
EXPECT_EQ(t, osrrs[1]);
|
||||
EXPECT_EQ(f, val.filter);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestQMP6988, Reset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
Oversampling p{}, t{};
|
||||
Filter f{};
|
||||
Standby s{};
|
||||
PowerMode pm{};
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_TRUE(unit->readStandbyTime(s));
|
||||
EXPECT_TRUE(unit->readPowerMode(pm));
|
||||
|
||||
EXPECT_NE(p, Oversampling::Skipped);
|
||||
EXPECT_NE(t, Oversampling::Skipped);
|
||||
EXPECT_NE(f, Filter::Off);
|
||||
EXPECT_NE(s, Standby::Time1ms);
|
||||
EXPECT_EQ(pm, PowerMode::Normal);
|
||||
|
||||
EXPECT_TRUE(unit->softReset());
|
||||
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_TRUE(unit->readStandbyTime(s));
|
||||
EXPECT_TRUE(unit->readPowerMode(pm));
|
||||
|
||||
EXPECT_EQ(p, Oversampling::Skipped);
|
||||
EXPECT_EQ(t, Oversampling::Skipped);
|
||||
EXPECT_EQ(f, Filter::Off);
|
||||
EXPECT_EQ(s, Standby::Time1ms);
|
||||
EXPECT_EQ(pm, PowerMode::Sleep);
|
||||
}
|
||||
|
||||
TEST_P(TestQMP6988, SingleShot)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
// This process fails during periodic measurements.
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
qmp6988::Data discard{};
|
||||
EXPECT_FALSE(unit->measureSingleshot(discard));
|
||||
|
||||
// Success if not in periodic measurement
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
// Standby time for periodic measurement, does not affect single shots
|
||||
EXPECT_TRUE(unit->writeStandbyTime(Standby::Time4sec));
|
||||
|
||||
for (auto&& po : os_table) {
|
||||
for (auto&& to : os_table) {
|
||||
for (auto&& coeff : filter_table) {
|
||||
auto s = m5::utility::formatString("Singleshot OS:%u/%u F:%u", po, to, coeff);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
// Specify settings and measure
|
||||
qmp6988::Data d{};
|
||||
bool can_not_measure = to == Oversampling::Skipped;
|
||||
bool only_temperature = to != Oversampling::Skipped && po == Oversampling::Skipped;
|
||||
|
||||
// M5_LOGI("%s:<%u><%u>", s.c_str(), can_not_measure, only_temperature);
|
||||
|
||||
if (can_not_measure) {
|
||||
EXPECT_FALSE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
} else if (only_temperature) {
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
// M5_LOGI("%f/%f/%f", d.celsius(), d.fahrenheit(), d.pressure());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(d.celsius()));
|
||||
EXPECT_TRUE(std::isfinite(d.fahrenheit()));
|
||||
EXPECT_FALSE(std::isfinite(d.pressure()));
|
||||
} else {
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, po, to, coeff));
|
||||
|
||||
// M5_LOGI("%f/%f", d.celsius(), d.pressure());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(d.celsius()));
|
||||
EXPECT_TRUE(std::isfinite(d.fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(d.pressure()));
|
||||
}
|
||||
|
||||
if (!can_not_measure) {
|
||||
Oversampling t;
|
||||
Oversampling p;
|
||||
Filter f;
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_EQ(p, po);
|
||||
EXPECT_EQ(t, to);
|
||||
EXPECT_EQ(f, coeff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestQMP6988, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& uc : uc_table) {
|
||||
for (auto&& st : standby_table) {
|
||||
auto s = m5::utility::formatString("UC:%u ST:%u", uc, st);
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
// M5_LOGW("%s", s.c_str());
|
||||
|
||||
const auto& val = uc_val_table[m5::stl::to_underlying(uc)];
|
||||
const auto& osrrs = osrss_table[m5::stl::to_underlying(val.osrss)];
|
||||
|
||||
EXPECT_TRUE(unit->writeUseCaseSetting(uc));
|
||||
EXPECT_TRUE(unit->writeStandbyTime(st));
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
auto tm = unit->interval();
|
||||
auto elapsed = test_periodic(unit.get(), STORED_SIZE, (int)st == 0 ? ((uint32_t)uc + 1) * 2 : 0);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
// M5_LOGW("E:(%u) %ld", tm == 1 ? (uint32_t)uc * 2 : 0, elapsed);
|
||||
|
||||
EXPECT_NE(elapsed, 0);
|
||||
EXPECT_NE(elapsed, -1);
|
||||
EXPECT_GE(elapsed, STORED_SIZE * tm - 1);
|
||||
|
||||
Oversampling t;
|
||||
Oversampling p;
|
||||
Filter f;
|
||||
EXPECT_TRUE(unit->readOversampling(p, t));
|
||||
EXPECT_TRUE(unit->readFilter(f));
|
||||
EXPECT_EQ(p, osrrs[0]);
|
||||
EXPECT_EQ(t, osrrs[1]);
|
||||
EXPECT_EQ(f, val.filter);
|
||||
|
||||
//
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_TRUE(unit->full());
|
||||
|
||||
uint32_t cnt{STORED_SIZE / 2};
|
||||
while (cnt-- && unit->available()) {
|
||||
// M5_LOGI("%f/%f/%f", unit->celsius(), unit->fahrenheit(), unit->pressure());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(unit->temperature()));
|
||||
EXPECT_TRUE(std::isfinite(unit->fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(unit->pressure()));
|
||||
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
|
||||
EXPECT_FLOAT_EQ(unit->pressure(), unit->oldest().pressure());
|
||||
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_FALSE(std::isfinite(unit->temperature()));
|
||||
EXPECT_FALSE(std::isfinite(unit->pressure()));
|
||||
}
|
||||
}
|
||||
}
|
||||
54
libraries/M5Unit-ENV/test/embedded/test_scd40/scd40_test.cpp
Normal file
54
libraries/M5Unit-ENV/test/embedded/test_scd40/scd40_test.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitSCD40
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_SCD40.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::scd4x;
|
||||
using m5::unit::types::elapsed_time_t;
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
constexpr uint32_t STORED_SIZE{4};
|
||||
|
||||
class TestSCD4x : public ComponentTestBase<UnitSCD40, bool> {
|
||||
protected:
|
||||
virtual UnitSCD40* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitSCD40();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
auto cfg = ptr->config();
|
||||
cfg.start_periodic = false;
|
||||
ptr->config(cfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
} // namespace
|
||||
|
||||
#include "../scd4x_test.inl"
|
||||
142
libraries/M5Unit-ENV/test/embedded/test_scd41/scd41_test.cpp
Normal file
142
libraries/M5Unit-ENV/test/embedded/test_scd41/scd41_test.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitSCD41
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <unit/unit_SCD41.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::scd4x;
|
||||
using m5::unit::types::elapsed_time_t;
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
constexpr uint32_t STORED_SIZE{4};
|
||||
|
||||
class TestSCD4x : public ComponentTestBase<UnitSCD41, bool> {
|
||||
protected:
|
||||
virtual UnitSCD41* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitSCD41();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
auto cfg = ptr->config();
|
||||
cfg.start_periodic = false;
|
||||
ptr->config(cfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestSCD4x, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
} // namespace
|
||||
|
||||
#include "../scd4x_test.inl"
|
||||
|
||||
TEST_P(TestSCD4x, Singleshot)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
{
|
||||
Data d{};
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
EXPECT_TRUE(unit->measureSingleshot(d));
|
||||
EXPECT_NE(d.co2(), 0);
|
||||
EXPECT_TRUE(std::isfinite(d.temperature()));
|
||||
EXPECT_TRUE(std::isfinite(d.humidity()));
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_FALSE(unit->measureSingleshot(d));
|
||||
EXPECT_EQ(d.co2(), 0);
|
||||
EXPECT_FLOAT_EQ(d.temperature(), -45.f);
|
||||
EXPECT_FLOAT_EQ(d.humidity(), 0.0f);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
}
|
||||
{
|
||||
Data d{};
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
EXPECT_TRUE(unit->measureSingleshotRHT(d));
|
||||
EXPECT_EQ(d.co2(), 0);
|
||||
EXPECT_TRUE(std::isfinite(d.temperature()));
|
||||
EXPECT_TRUE(std::isfinite(d.humidity()));
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_FALSE(unit->measureSingleshotRHT(d));
|
||||
EXPECT_EQ(d.co2(), 0);
|
||||
EXPECT_FLOAT_EQ(d.temperature(), -45.f);
|
||||
EXPECT_FLOAT_EQ(d.humidity(), 0.0f);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, PowerMode)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
uint32_t count{8};
|
||||
while (count--) {
|
||||
EXPECT_TRUE(unit->powerDown()) << count;
|
||||
EXPECT_TRUE(unit->wakeup()) << count;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
EXPECT_FALSE(unit->powerDown());
|
||||
EXPECT_FALSE(unit->wakeup());
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->reInit());
|
||||
}
|
||||
|
||||
TEST_P(TestSCD4x, ASC)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
constexpr uint16_t hours_table[] = {0, 32768, 65535};
|
||||
for (auto&& h : hours_table) {
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationInitialPeriod(h));
|
||||
EXPECT_TRUE(unit->writeAutomaticSelfCalibrationStandardPeriod(h));
|
||||
|
||||
uint16_t ih{}, sh{};
|
||||
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationInitialPeriod(ih));
|
||||
EXPECT_TRUE(unit->readAutomaticSelfCalibrationStandardPeriod(sh));
|
||||
|
||||
EXPECT_EQ(ih, (h >> 2) << 2);
|
||||
EXPECT_EQ(sh, (h >> 2) << 2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement());
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
for (auto&& h : hours_table) {
|
||||
EXPECT_FALSE(unit->writeAutomaticSelfCalibrationInitialPeriod(h));
|
||||
EXPECT_FALSE(unit->writeAutomaticSelfCalibrationStandardPeriod(h));
|
||||
}
|
||||
}
|
||||
208
libraries/M5Unit-ENV/test/embedded/test_sgp30/sgp30_test.cpp
Normal file
208
libraries/M5Unit-ENV/test/embedded/test_sgp30/sgp30_test.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitSGP30
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_SGP30.hpp>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::sgp30;
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
class TestSGP30 : public ComponentTestBase<UnitSGP30, bool> {
|
||||
protected:
|
||||
virtual UnitSGP30* get_instance() override
|
||||
{
|
||||
auto* ptr = new m5::unit::UnitSGP30();
|
||||
if (ptr) {
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = 4;
|
||||
ptr->component_config(ccfg);
|
||||
|
||||
auto cfg = ptr->config();
|
||||
cfg.start_periodic = false;
|
||||
ptr->config(cfg);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSGP30, ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSGP30, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestSGP30, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
void check_measurement_values(UnitSGP30* u)
|
||||
{
|
||||
EXPECT_NE(u->co2eq(), 0xFFFFU);
|
||||
EXPECT_NE(u->tvoc(), 0XFFFFU);
|
||||
|
||||
// readRaw test
|
||||
uint16_t h{}, e{};
|
||||
EXPECT_TRUE(u->readRaw(h, e));
|
||||
EXPECT_NE(h, 0U);
|
||||
EXPECT_NE(e, 0U);
|
||||
}
|
||||
|
||||
void wait15sec()
|
||||
{
|
||||
auto to = m5::utility::millis() + 15 * 1000;
|
||||
do {
|
||||
m5::utility::delay(1);
|
||||
} while (m5::utility::millis() < to);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestSGP30, FeatureSet)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_NE(unit->productVersion(), 0U);
|
||||
M5_LOGI("productVersion:%x", unit->productVersion());
|
||||
|
||||
Feature f{};
|
||||
EXPECT_TRUE(unit->readFeatureSet(f));
|
||||
EXPECT_EQ(f.productType(), 0U);
|
||||
EXPECT_NE(f.productVersion(), 0U);
|
||||
|
||||
EXPECT_EQ(unit->productVersion(), f.productVersion());
|
||||
}
|
||||
|
||||
TEST_P(TestSGP30, selfTest)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
uint16_t result{};
|
||||
EXPECT_TRUE(unit->measureTest(result));
|
||||
EXPECT_EQ(result, 0xD400);
|
||||
}
|
||||
|
||||
TEST_P(TestSGP30, serialNumber)
|
||||
{
|
||||
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(command::GET_SERIAL_ID, 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);
|
||||
}
|
||||
|
||||
TEST_P(TestSGP30, generalReset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(0x1234, 0x5678, 0x9ABC));
|
||||
M5_LOGW("SGP30 measurement starts 15 seconds after begin");
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
wait15sec();
|
||||
|
||||
uint16_t co2eq{}, tvoc{}, inceptive_tvoc{};
|
||||
EXPECT_TRUE(unit->readIaqBaseline(co2eq, tvoc));
|
||||
// EXPECT_TRUE(unit->readTvocInceptiveBaseline(inceptive_tvoc));
|
||||
|
||||
// M5_LOGW("%x/%x/%x", co2eq, tvoc, inceptive_tvoc);
|
||||
|
||||
EXPECT_EQ(co2eq, 0x1234);
|
||||
EXPECT_EQ(tvoc, 0x5678);
|
||||
// EXPECT_EQ(inceptive_tvoc, 0x1122);
|
||||
|
||||
EXPECT_TRUE(unit->generalReset());
|
||||
|
||||
EXPECT_TRUE(unit->readIaqBaseline(co2eq, tvoc));
|
||||
// EXPECT_TRUE(unit->readTvocInceptiveBaseline(inceptive_tvoc));
|
||||
// M5_LOGW("%x/%x/%x", co2eq, tvoc, inceptive_tvoc);
|
||||
|
||||
EXPECT_EQ(co2eq, 0x0000);
|
||||
EXPECT_EQ(tvoc, 0x0000);
|
||||
// EXPECT_EQ(inceptive_tvoc, 0x0000);
|
||||
}
|
||||
|
||||
TEST_P(TestSGP30, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
{
|
||||
uint32_t cnt{10};
|
||||
uint16_t h2{}, et{};
|
||||
while (cnt--) {
|
||||
EXPECT_TRUE(unit->readRaw(h2, et));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(0, 0, 0));
|
||||
M5_LOGW("SGP30 measurement starts 15 seconds after begin");
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
wait15sec();
|
||||
|
||||
test_periodic_measurement(unit.get(), 4, check_measurement_values);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_EQ(unit->available(), 4);
|
||||
EXPECT_TRUE(unit->full());
|
||||
EXPECT_FALSE(unit->empty());
|
||||
|
||||
uint32_t cnt{2};
|
||||
while (unit->available() && cnt--) {
|
||||
EXPECT_FALSE(unit->empty());
|
||||
// M5_LOGW("C:%u T:%u", unit->co2eq(), unit->tvoc());
|
||||
EXPECT_EQ(unit->co2eq(), unit->oldest().co2eq());
|
||||
EXPECT_EQ(unit->tvoc(), unit->oldest().tvoc());
|
||||
unit->discard();
|
||||
}
|
||||
|
||||
EXPECT_EQ(unit->available(), 2);
|
||||
EXPECT_FALSE(unit->full());
|
||||
EXPECT_FALSE(unit->empty());
|
||||
|
||||
unit->flush();
|
||||
EXPECT_EQ(unit->co2eq(), 0XFFFF);
|
||||
EXPECT_EQ(unit->tvoc(), 0XFFFF);
|
||||
EXPECT_EQ(unit->available(), 0);
|
||||
EXPECT_TRUE(unit->empty());
|
||||
EXPECT_FALSE(unit->full());
|
||||
}
|
||||
355
libraries/M5Unit-ENV/test/embedded/test_sht30/sht30_test.cpp
Normal file
355
libraries/M5Unit-ENV/test/embedded/test_sht30/sht30_test.cpp
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitSHT30
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_SHT30.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <bitset>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::sht30;
|
||||
using namespace m5::unit::sht30::command;
|
||||
|
||||
constexpr size_t STORED_SIZE{4};
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
class TestSHT30 : public ComponentTestBase<UnitSHT30, bool> {
|
||||
protected:
|
||||
virtual UnitSHT30* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitSHT30();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT30,
|
||||
// ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT30, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT30, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
// flot t uu int16 (temperature)
|
||||
constexpr uint16_t float_to_uint16(const float f)
|
||||
{
|
||||
return f * 65536 / 175;
|
||||
}
|
||||
|
||||
std::tuple<const char*, Repeatability, bool> ss_table[] = {
|
||||
{"HighTrue", Repeatability::High, true}, {"MediumTrue", Repeatability::Medium, true},
|
||||
{"LowTrue", Repeatability::Low, true}, {"HighFalse", Repeatability::High, false},
|
||||
{"MediumFalse", Repeatability::Medium, false}, {"LowFalse", Repeatability::Low, false},
|
||||
};
|
||||
|
||||
void check_measurement_values(UnitSHT30* u)
|
||||
{
|
||||
EXPECT_TRUE(std::isfinite(u->latest().celsius()));
|
||||
EXPECT_TRUE(std::isfinite(u->latest().fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(u->latest().humidity()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestSHT30, SingleShot)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
|
||||
for (auto&& e : ss_table) {
|
||||
const char* s{};
|
||||
Repeatability rep;
|
||||
bool stretch{};
|
||||
std::tie(s, rep, stretch) = e;
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
int cnt{10}; // repeat 10 times
|
||||
while (cnt--) {
|
||||
sht30::Data d{};
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, rep, stretch)) << (int)rep << " : " << stretch;
|
||||
EXPECT_TRUE(std::isfinite(d.temperature()));
|
||||
EXPECT_TRUE(std::isfinite(d.humidity()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSHT30, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
constexpr std::tuple<const char*, MPS, Repeatability> table[] = {
|
||||
//
|
||||
{"HalfHigh", MPS::Half, Repeatability::High},
|
||||
{"HalfMedium", MPS::Half, Repeatability::Medium},
|
||||
{"HalfLow", MPS::Half, Repeatability::Low},
|
||||
//
|
||||
{"1High", MPS::One, Repeatability::High},
|
||||
{"1Medium", MPS::One, Repeatability::Medium},
|
||||
{"1Low", MPS::One, Repeatability::Low},
|
||||
//
|
||||
{"2High", MPS::Two, Repeatability::High},
|
||||
{"2Medium", MPS::Two, Repeatability::Medium},
|
||||
{"2Low", MPS::Two, Repeatability::Low},
|
||||
//
|
||||
{"4fHigh", MPS::Four, Repeatability::High},
|
||||
{"4Medium", MPS::Four, Repeatability::Medium},
|
||||
{"4Low", MPS::Four, Repeatability::Low},
|
||||
//
|
||||
{"10fHigh", MPS::Ten, Repeatability::High},
|
||||
{"10Medium", MPS::Ten, Repeatability::Medium},
|
||||
{"10Low", MPS::Ten, Repeatability::Low},
|
||||
};
|
||||
|
||||
for (auto&& e : table) {
|
||||
const char* s{};
|
||||
MPS mps;
|
||||
Repeatability rep;
|
||||
std::tie(s, mps, rep) = e;
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(mps, rep));
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
// Cannot call all singleshot in periodic
|
||||
for (auto&& e : ss_table) {
|
||||
const char* s{};
|
||||
Repeatability rep;
|
||||
bool stretch{};
|
||||
std::tie(s, rep, stretch) = e;
|
||||
sht30::Data d{};
|
||||
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->measureSingleshot(d, rep, stretch));
|
||||
}
|
||||
test_periodic_measurement(unit.get(), 4, 1, check_measurement_values);
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_TRUE(unit->full());
|
||||
|
||||
uint32_t cnt{2};
|
||||
while (cnt-- && unit->available()) {
|
||||
// M5_LOGI("%s T:%f H:%f", s, unit->temperature(), unit->humidity());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(unit->temperature()));
|
||||
EXPECT_TRUE(std::isfinite(unit->humidity()));
|
||||
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
|
||||
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_FALSE(std::isfinite(unit->temperature()));
|
||||
EXPECT_FALSE(std::isfinite(unit->humidity()));
|
||||
}
|
||||
|
||||
// ART Command (4 mps)
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
EXPECT_FALSE(unit->writeModeAccelerateResponseTime());
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(MPS::Half,
|
||||
Repeatability::High)); // 0.5mps
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_EQ(unit->updatedMillis(), 0);
|
||||
EXPECT_TRUE(unit->writeModeAccelerateResponseTime()); // boost to 4mps
|
||||
|
||||
// Cannot call all singleshot in periodic
|
||||
for (auto&& e : ss_table) {
|
||||
const char* s{};
|
||||
Repeatability rep;
|
||||
bool stretch{};
|
||||
std::tie(s, rep, stretch) = e;
|
||||
sht30::Data d{};
|
||||
|
||||
SCOPED_TRACE(s);
|
||||
EXPECT_FALSE(unit->measureSingleshot(d, rep, stretch));
|
||||
}
|
||||
|
||||
test_periodic_measurement(unit.get(), 4, 1, check_measurement_values);
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_TRUE(unit->full());
|
||||
// M5_LOGI("ART T:%f H:%f", unit->temperature(), unit->humidity());
|
||||
|
||||
EXPECT_TRUE(std::isfinite(unit->temperature()));
|
||||
EXPECT_TRUE(std::isfinite(unit->humidity()));
|
||||
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
|
||||
EXPECT_FLOAT_EQ(unit->humidity(), unit->oldest().humidity());
|
||||
|
||||
unit->flush();
|
||||
EXPECT_TRUE(std::isnan(unit->temperature()));
|
||||
EXPECT_TRUE(std::isnan(unit->humidity()));
|
||||
EXPECT_EQ(unit->available(), 0);
|
||||
EXPECT_TRUE(unit->empty());
|
||||
EXPECT_FALSE(unit->full());
|
||||
|
||||
// startPeriodicMeasurement after ART (ART is disabled)
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(MPS::Two,
|
||||
Repeatability::High)); // 2 mps
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
EXPECT_EQ(unit->updatedMillis(), 0);
|
||||
|
||||
std::array<uint8_t, 6> rbuf{};
|
||||
types::elapsed_time_t timeout_at{}, now{}, at[2]{};
|
||||
uint32_t idx{};
|
||||
timeout_at = m5::utility::millis() + 1100;
|
||||
do {
|
||||
m5::utility::delay(1);
|
||||
at[idx] = now = m5::utility::millis();
|
||||
unit->update();
|
||||
if (unit->updated()) {
|
||||
++idx;
|
||||
}
|
||||
} while (idx < 2 && now <= timeout_at);
|
||||
EXPECT_EQ(idx, 2);
|
||||
auto diff = at[1] - at[0];
|
||||
EXPECT_GT(diff, 250); // 2mps(500) > 4mps(250)
|
||||
}
|
||||
|
||||
namespace {
|
||||
void printStatus(const Status& s)
|
||||
{
|
||||
#if 0
|
||||
std::bitset<16> bits(s.value);
|
||||
M5_LOGI("[%s]: %u/%u/%u/%u/%u/%u/%u", bits.to_string().c_str(),
|
||||
s.alertPending(), s.heater(), s.trackingAlertRH(),
|
||||
s.trackingAlert(), s.reset(), s.command(), s.checksum());
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestSHT30, HeaterAndStatus)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
Status s{};
|
||||
|
||||
EXPECT_TRUE(unit->startHeater());
|
||||
|
||||
EXPECT_TRUE(unit->readStatus(s));
|
||||
printStatus(s);
|
||||
EXPECT_TRUE(s.heater());
|
||||
|
||||
// clearStatus will not clear heater status
|
||||
EXPECT_TRUE(unit->clearStatus());
|
||||
EXPECT_TRUE(unit->readStatus(s));
|
||||
printStatus(s);
|
||||
EXPECT_TRUE(s.heater());
|
||||
|
||||
EXPECT_TRUE(unit->stopHeater());
|
||||
EXPECT_TRUE(unit->readStatus(s));
|
||||
printStatus(s);
|
||||
|
||||
EXPECT_FALSE(s.heater());
|
||||
}
|
||||
|
||||
TEST_P(TestSHT30, SoftReset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
// Soft reset is only possible in standby mode.
|
||||
EXPECT_FALSE(unit->softReset());
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
|
||||
Status s{};
|
||||
// After a reset, the heaters are set to a deactivated state as a default
|
||||
// condition (*1)
|
||||
EXPECT_TRUE(unit->startHeater());
|
||||
|
||||
EXPECT_TRUE(unit->softReset());
|
||||
|
||||
EXPECT_TRUE(unit->readStatus(s));
|
||||
EXPECT_FALSE(s.alertPending());
|
||||
EXPECT_FALSE(s.heater()); // *1
|
||||
EXPECT_FALSE(s.trackingAlertRH());
|
||||
EXPECT_FALSE(s.trackingAlert());
|
||||
EXPECT_FALSE(s.reset());
|
||||
EXPECT_FALSE(s.command());
|
||||
EXPECT_FALSE(s.checksum());
|
||||
}
|
||||
|
||||
TEST_P(TestSHT30, GeneralReset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->startHeater());
|
||||
|
||||
EXPECT_TRUE(unit->generalReset());
|
||||
|
||||
Status s{};
|
||||
EXPECT_TRUE(unit->readStatus(s));
|
||||
// The ALERT pin will also become active (high) after powerup and after
|
||||
// resets
|
||||
EXPECT_TRUE(s.alertPending());
|
||||
EXPECT_FALSE(s.heater());
|
||||
EXPECT_FALSE(s.trackingAlertRH());
|
||||
EXPECT_FALSE(s.trackingAlert());
|
||||
EXPECT_TRUE(s.reset());
|
||||
EXPECT_FALSE(s.command());
|
||||
EXPECT_FALSE(s.checksum());
|
||||
}
|
||||
|
||||
TEST_P(TestSHT30, SerialNumber)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
|
||||
{
|
||||
// Read direct [MSB] SNB_3, SNB_2, CRC, SNB_1, SNB_0, CRC [LSB]
|
||||
std::array<uint8_t, 6> rbuf{};
|
||||
EXPECT_TRUE(unit->readRegister(GET_SERIAL_NUMBER_ENABLE_STRETCH, rbuf.data(), rbuf.size(), 1));
|
||||
uint32_t d_sno = (((uint32_t)rbuf[0]) << 24) | (((uint32_t)rbuf[1]) << 16) | (((uint32_t)rbuf[3]) << 8) |
|
||||
((uint32_t)rbuf[4]);
|
||||
|
||||
//
|
||||
uint32_t sno{};
|
||||
char ssno[9]{};
|
||||
EXPECT_TRUE(unit->readSerialNumber(sno));
|
||||
EXPECT_TRUE(unit->readSerialNumber(ssno));
|
||||
|
||||
EXPECT_EQ(sno, d_sno);
|
||||
|
||||
// M5_LOGI("s:[%s] uint32:[%x]", ssno, sno);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::uppercase << std::setw(8) << std::setfill('0') << std::hex << sno;
|
||||
std::string s(stream.str());
|
||||
EXPECT_STREQ(s.c_str(), ssno);
|
||||
}
|
||||
}
|
||||
245
libraries/M5Unit-ENV/test/embedded/test_sht40/sht40_test.cpp
Normal file
245
libraries/M5Unit-ENV/test/embedded/test_sht40/sht40_test.cpp
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for UnitSHT30
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <Wire.h>
|
||||
#include <M5Unified.h>
|
||||
#include <M5UnitUnified.hpp>
|
||||
#include <googletest/test_template.hpp>
|
||||
#include <googletest/test_helper.hpp>
|
||||
#include <unit/unit_SHT40.hpp>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
using namespace m5::unit::googletest;
|
||||
using namespace m5::unit;
|
||||
using namespace m5::unit::sht40;
|
||||
using namespace m5::unit::sht40::command;
|
||||
using m5::unit::types::elapsed_time_t;
|
||||
|
||||
constexpr size_t STORED_SIZE{4};
|
||||
|
||||
const ::testing::Environment* global_fixture = ::testing::AddGlobalTestEnvironment(new GlobalFixture<400000U>());
|
||||
|
||||
class TestSHT40 : public ComponentTestBase<UnitSHT40, bool> {
|
||||
protected:
|
||||
virtual UnitSHT40* get_instance() override
|
||||
{
|
||||
auto ptr = new m5::unit::UnitSHT40();
|
||||
auto ccfg = ptr->component_config();
|
||||
ccfg.stored_size = STORED_SIZE;
|
||||
ptr->component_config(ccfg);
|
||||
return ptr;
|
||||
}
|
||||
virtual bool is_using_hal() const override
|
||||
{
|
||||
return GetParam();
|
||||
};
|
||||
};
|
||||
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT40,
|
||||
// ::testing::Values(false, true));
|
||||
// INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT40, ::testing::Values(true));
|
||||
INSTANTIATE_TEST_SUITE_P(ParamValues, TestSHT40, ::testing::Values(false));
|
||||
|
||||
namespace {
|
||||
|
||||
template <class U>
|
||||
elapsed_time_t test_periodic(U* unit, const uint32_t times)
|
||||
{
|
||||
auto timeout_at = m5::utility::millis() + (times * unit->interval() * 2);
|
||||
|
||||
// First read
|
||||
while (!unit->updated() && m5::utility::millis() < timeout_at) {
|
||||
std::this_thread::yield();
|
||||
unit->update();
|
||||
}
|
||||
// timeout
|
||||
if (!unit->updated()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
uint32_t measured{};
|
||||
auto start_at = m5::utility::millis();
|
||||
unit->update();
|
||||
|
||||
do {
|
||||
m5::utility::delay(1);
|
||||
unit->update();
|
||||
measured += unit->updated() ? 1 : 0;
|
||||
} while (measured < times && m5::utility::millis() < timeout_at);
|
||||
|
||||
return (measured == times) ? m5::utility::millis() - start_at : 0;
|
||||
}
|
||||
|
||||
std::tuple<const char*, Precision, Heater, elapsed_time_t> sm_table[] = {
|
||||
//
|
||||
{"HighLong", Precision::High, Heater::Long, 9},
|
||||
{"HighShort", Precision::High, Heater::Short, 9},
|
||||
{"HighNone", Precision::High, Heater::None, 9},
|
||||
//
|
||||
{"MediumLong", Precision::Medium, Heater::Long, 5},
|
||||
{"MediumSHort", Precision::Medium, Heater::Short, 5},
|
||||
{"MediumNone", Precision::Medium, Heater::None, 5},
|
||||
//
|
||||
{"LowLong", Precision::Low, Heater::Long, 2},
|
||||
{"LowShort", Precision::Low, Heater::Short, 2},
|
||||
{"LowNone", Precision::Low, Heater::None, 2},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_P(TestSHT40, SoftReset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
// Soft reset is only possible in standby mode.
|
||||
EXPECT_FALSE(unit->softReset());
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
EXPECT_TRUE(unit->softReset());
|
||||
}
|
||||
|
||||
TEST_P(TestSHT40, GeneralReset)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
EXPECT_TRUE(unit->generalReset());
|
||||
}
|
||||
|
||||
TEST_P(TestSHT40, SerialNumber)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
{
|
||||
// Read direct [MSB] SNB_3, SNB_2, CRC, SNB_1, SNB_0, CRC [LSB]
|
||||
std::array<uint8_t, 6> rbuf{};
|
||||
EXPECT_TRUE(unit->readRegister(GET_SERIAL_NUMBER, rbuf.data(), rbuf.size(), 1));
|
||||
uint32_t d_sno = (((uint32_t)rbuf[0]) << 24) | (((uint32_t)rbuf[1]) << 16) | (((uint32_t)rbuf[3]) << 8) |
|
||||
((uint32_t)rbuf[4]);
|
||||
|
||||
//
|
||||
uint32_t sno{};
|
||||
char ssno[9]{};
|
||||
EXPECT_TRUE(unit->readSerialNumber(sno));
|
||||
EXPECT_TRUE(unit->readSerialNumber(ssno));
|
||||
|
||||
EXPECT_EQ(sno, d_sno);
|
||||
|
||||
// M5_LOGI("s:[%s] uint32:[%x]", ssno, sno);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::uppercase << std::setw(8) << std::setfill('0') << std::hex << sno;
|
||||
std::string s(stream.str());
|
||||
EXPECT_STREQ(s.c_str(), ssno);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSHT40, SingleShot)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : sm_table) {
|
||||
const char* s{};
|
||||
Precision p{};
|
||||
Heater h{};
|
||||
elapsed_time_t tm{};
|
||||
std::tie(s, p, h, tm) = e;
|
||||
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
uint32_t cnt{5}; // repeat 5 times
|
||||
while (cnt--) {
|
||||
sht40::Data d{};
|
||||
EXPECT_TRUE(unit->measureSingleshot(d, p, h));
|
||||
EXPECT_TRUE(std::isfinite(d.temperature()));
|
||||
EXPECT_TRUE(std::isfinite(d.humidity()));
|
||||
EXPECT_EQ(d.heater, h != Heater::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(TestSHT40, Periodic)
|
||||
{
|
||||
SCOPED_TRACE(ustr);
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
for (auto&& e : sm_table) {
|
||||
const char* s{};
|
||||
Precision p{};
|
||||
Heater h{};
|
||||
elapsed_time_t tm{};
|
||||
std::tie(s, p, h, tm) = e;
|
||||
|
||||
SCOPED_TRACE(s);
|
||||
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(p, h));
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
// Cannot call all singleshot in periodic
|
||||
for (auto&& single : sm_table) {
|
||||
const char* s{};
|
||||
Precision p{};
|
||||
Heater h{};
|
||||
elapsed_time_t tm{};
|
||||
std::tie(s, p, h, tm) = single;
|
||||
sht40::Data d{};
|
||||
EXPECT_FALSE(unit->measureSingleshot(d, p, h));
|
||||
}
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
//
|
||||
EXPECT_TRUE(unit->startPeriodicMeasurement(p, h));
|
||||
EXPECT_TRUE(unit->inPeriodic());
|
||||
|
||||
auto elapsed = test_periodic(unit.get(), STORED_SIZE);
|
||||
EXPECT_NE(elapsed, 0);
|
||||
EXPECT_GE(elapsed, STORED_SIZE * tm);
|
||||
EXPECT_LE(elapsed, STORED_SIZE * tm + 1);
|
||||
|
||||
// M5_LOGW("[%s] %lu %zu", s, elapsed, unit->available());
|
||||
|
||||
EXPECT_TRUE(unit->stopPeriodicMeasurement());
|
||||
EXPECT_FALSE(unit->inPeriodic());
|
||||
|
||||
EXPECT_EQ(unit->available(), STORED_SIZE);
|
||||
EXPECT_FALSE(unit->empty());
|
||||
EXPECT_TRUE(unit->full());
|
||||
|
||||
uint32_t cnt{2};
|
||||
while (cnt-- && unit->available()) {
|
||||
EXPECT_TRUE(std::isfinite(unit->temperature()));
|
||||
EXPECT_TRUE(std::isfinite(unit->fahrenheit()));
|
||||
EXPECT_TRUE(std::isfinite(unit->humidity()));
|
||||
EXPECT_FLOAT_EQ(unit->temperature(), unit->oldest().temperature());
|
||||
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_FALSE(std::isfinite(unit->temperature()));
|
||||
EXPECT_FALSE(std::isfinite(unit->humidity()));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue