first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue