From 2cc55757798c786cba0c0e9710957ba4ff56ac3f Mon Sep 17 00:00:00 2001 From: GOB Date: Mon, 30 Sep 2024 13:39:41 +0900 Subject: [PATCH 01/10] Fixes doxygen comment --- src/unit/unit_MAX30100.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unit/unit_MAX30100.hpp b/src/unit/unit_MAX30100.hpp index 36a6008..9deb8d4 100644 --- a/src/unit/unit_MAX30100.hpp +++ b/src/unit/unit_MAX30100.hpp @@ -387,7 +387,7 @@ class UnitMAX30100 : public Component, public PeriodicMeasurementAdapter Date: Wed, 16 Oct 2024 16:01:57 +0900 Subject: [PATCH 02/10] Fixes BPM/SpO2 calculation mechanism --- .../PlotToSerial/main/PlotToSerial.cpp | 59 +++--- src/M5UnitUnifiedHEART.hpp | 2 +- src/unit/unit_MAX30100.cpp | 29 ++- src/unit/unit_MAX30100.hpp | 37 ++-- src/utility/heart_rate.cpp | 187 ------------------ src/utility/heart_rate.hpp | 124 ------------ src/utility/pulse_monitor.cpp | 100 ++++++++++ src/utility/pulse_monitor.hpp | 161 +++++++++++++++ 8 files changed, 334 insertions(+), 365 deletions(-) delete mode 100644 src/utility/heart_rate.cpp delete mode 100644 src/utility/heart_rate.hpp create mode 100644 src/utility/pulse_monitor.cpp create mode 100644 src/utility/pulse_monitor.hpp diff --git a/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp b/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp index 4ee4d91..f1840a0 100644 --- a/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp +++ b/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #if !defined(USING_M5HAL) #include #endif @@ -19,27 +18,25 @@ namespace { auto& lcd = M5.Display; m5::unit::UnitUnified Units; -m5::unit::UnitHEART unitHeart; -m5::max30100::HeartRate heartRate(100 /*sample rate*/); +m5::unit::UnitHEART unit; +m5::heart::PulseMonitor monitor(100.f); + } // namespace void setup() { - m5::utility::delay(1500); - M5.begin(); // Another settings if (0) { - auto cfg = unitHeart.config(); - cfg.sample_rate = m5::unit::max30100::Sample::Rate400; - cfg.pulse_width = m5::unit::max30100::LedPulseWidth::PW400; - cfg.ir_current = m5::unit::max30100::CurrentControl::mA7_6; - cfg.red_current = m5::unit::max30100::CurrentControl::mA7_6; - heartRate.setSampleRate(m5::max30100::HeartRate::getSampleRate(cfg.sample_rate)); - // heartRate.setThreshold(25.0f); // depends on ir/redCurrent - // cfg.mode = m5::unit::max30100::Mode::HROnly; - unitHeart.config(cfg); + auto cfg = unit.config(); + cfg.sampling_rate = m5::unit::max30100::Sampling::Rate200; + cfg.pulse_width = m5::unit::max30100::LedPulseWidth::PW200; + cfg.ir_current = m5::unit::max30100::CurrentControl::mA7_6; + cfg.red_current = m5::unit::max30100::CurrentControl::mA7_6; + auto sr = m5::unit::max30100::getSamplingRate(cfg.sampling_rate); + monitor.setSamplingRate(sr); + unit.config(cfg); } auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda); @@ -54,7 +51,7 @@ void setup() i2c_cfg.pin_scl = m5::hal::gpio::getPin(pin_num_scl); auto i2c_bus = m5::hal::bus::i2c::getBus(i2c_cfg); M5_LOGI("Bus:%d", i2c_bus.has_value()); - if (!Units.add(unitHeart, i2c_bus ? i2c_bus.value() : nullptr) || !Units.begin()) { + if (!Units.add(unit, i2c_bus ? i2c_bus.value() : nullptr) || !Units.begin()) { M5_LOGE("Failed to begin"); lcd.clear(TFT_RED); while (true) { @@ -65,7 +62,7 @@ void setup() #pragma message "Using Wire" // Using TwoWire Wire.begin(pin_num_sda, pin_num_scl, 400000U); - if (!Units.add(unitHeart, Wire) || !Units.begin()) { + if (!Units.add(unit, Wire) || !Units.begin()) { M5_LOGE("Failed to begin"); lcd.clear(TFT_RED); while (true) { @@ -84,25 +81,29 @@ void loop() { M5.update(); Units.update(); - if (unitHeart.updated()) { - while (unitHeart.available()) { - M5_LOGI("\n>IR:%u\n>RED:%u", unitHeart.ir(), unitHeart.red()); - bool beat = heartRate.push_back((float)unitHeart.ir(), (float)unitHeart.red()); - if (beat) { - M5_LOGI("Beat!"); - } + if (unit.updated()) { + // WARNING + // If overflow is occurring, the sampling rate should be reduced because the processing is not up to par + if (unit.overflow()) { + M5_LOGW("\n>OVERFLOW:%u", unit.overflow()); + } - unitHeart.discard(); + bool beat{}; + // MAX30100 is equipped with a FIFO, so multiple data may be stored + while (unit.available()) { + monitor.push_back(unit.ir(), unit.red()); // Push back the oldest data + //M5_LOGI("\n>MIR:%f\n>MRED:%f", monitor.latestIR(), monitor.latestRED()); + monitor.update(); + beat = monitor.isBeat(); + unit.discard(); // Discard the oldest data } - auto bpm = heartRate.calculate(); - M5_LOGW("\n>HRR:%f\n>SpO2:%f", bpm, heartRate.SpO2()); + M5_LOGI("\n>BPM:%f\n>SpO2:%f\n>BEAT:%u", monitor.bpm(), monitor.SpO2(), beat); } - // buffer clear and measure tempeature + // Measure tempeature if (M5.BtnA.wasClicked()) { - heartRate.clear(); m5::unit::max30100::TemperatureData td{}; - if (unitHeart.measureTemperatureSingleshot(td)) { + if (unit.measureTemperatureSingleshot(td)) { M5_LOGI("\n>Temp:%f", td.celsius()); } } diff --git a/src/M5UnitUnifiedHEART.hpp b/src/M5UnitUnifiedHEART.hpp index 53927ee..b7c32bf 100644 --- a/src/M5UnitUnifiedHEART.hpp +++ b/src/M5UnitUnifiedHEART.hpp @@ -14,7 +14,7 @@ #define M5_UNIT_HEART_HPP #include "unit/unit_MAX30100.hpp" -#include "utility/heart_rate.hpp" +#include "utility/pulse_monitor.hpp" /*! @namespace m5 diff --git a/src/unit/unit_MAX30100.cpp b/src/unit/unit_MAX30100.cpp index 378414b..5089442 100644 --- a/src/unit/unit_MAX30100.cpp +++ b/src/unit/unit_MAX30100.cpp @@ -24,6 +24,8 @@ constexpr elapsed_time_t interval_table[] = { 1000 / 50, 1000 / 100, 1000 / 167, 1000 / 200, 1000 / 400, 1000 / 600, 1000 / 800, 1000 / 1000, }; +constexpr uint32_t sr_table[] = {50, 100, 167, 200, 400, 600, 800, 1000}; + constexpr uint32_t MEASURE_TEMPERATURE_DURATION{29}; // 29ms constexpr uint8_t allowed_spo2_table[] = { @@ -34,7 +36,7 @@ constexpr uint8_t allowed_hr_table[] = { // LSB:200 MSB:1600 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x03, 0x03, 0x03, }; -bool is_allowed_settings(const Mode mode, const Sample rate, const LedPulseWidth pw) +bool is_allowed_settings(const Mode mode, const Sampling rate, const LedPulseWidth pw) { return (mode != Mode::None) ? (mode == Mode::SPO2 ? allowed_spo2_table : allowed_hr_table)[m5::stl::to_underlying(rate)] & @@ -48,6 +50,11 @@ namespace m5 { namespace unit { namespace max30100 { +uint32_t getSamplingRate(Sampling rate) +{ + return sr_table[m5::stl::to_underlying(rate)]; +} + uint16_t Data::ir() const { return m5::types::big_uint16_t(raw[0], raw[1]).get(); @@ -100,7 +107,7 @@ bool UnitMAX30100::begin() return false; } - return _cfg.start_periodic ? startPeriodicMeasurement(_cfg.mode, _cfg.sample_rate, _cfg.pulse_width, + return _cfg.start_periodic ? startPeriodicMeasurement(_cfg.mode, _cfg.sampling_rate, _cfg.pulse_width, _cfg.ir_current, _cfg.high_resolution, _cfg.red_current) : true; } @@ -111,7 +118,11 @@ void UnitMAX30100::update(const bool force) if (inPeriodic()) { auto at = m5::utility::millis(); if (force || !_latest || at >= _latest + _interval) { + // Reduce interval if overflow _updated = read_FIFO(); + if (_interval && overflow()) { + --_interval; + } if (_updated) { _latest = at; } @@ -141,7 +152,7 @@ bool UnitMAX30100::start_periodic_measurement() return false; } -bool UnitMAX30100::start_periodic_measurement(const max30100::Mode mode, const max30100::Sample sample_rate, +bool UnitMAX30100::start_periodic_measurement(const max30100::Mode mode, const max30100::Sampling sampling_rate, const max30100::LedPulseWidth pulse_width, const max30100::CurrentControl ir_current, const bool high_resolution, const max30100::CurrentControl red_current) @@ -151,7 +162,7 @@ bool UnitMAX30100::start_periodic_measurement(const max30100::Mode mode, const m } SpO2Configuration sc{}; - sc.sampleRate(sample_rate); + sc.samplingRate(sampling_rate); sc.ledPulseWidth(pulse_width); sc.highResolution(high_resolution); @@ -220,11 +231,11 @@ bool UnitMAX30100::writeSpO2Configuration(const max30100::SpO2Configuration sc) return write_spo2_configration(sc.value); } -bool UnitMAX30100::writeSampleRate(const max30100::Sample rate) +bool UnitMAX30100::writeSamplingRate(const max30100::Sampling rate) { max30100::SpO2Configuration sc{}; if (read_spo2_configration(sc.value)) { - sc.sampleRate(rate); + sc.samplingRate(rate); return write_spo2_configration(sc.value); } return false; @@ -363,13 +374,13 @@ bool UnitMAX30100::write_spo2_configration(const uint8_t c) max30100::SpO2Configuration sc; sc.value = c; - if (!is_allowed_settings(_mode, sc.sampleRate(), sc.ledPulseWidth())) { - M5_LIB_LOGW("Invalid combination %u:%u:%u", _mode, sc.sampleRate(), sc.ledPulseWidth()); + if (!is_allowed_settings(_mode, sc.samplingRate(), sc.ledPulseWidth())) { + M5_LIB_LOGW("Invalid combination %u:%u:%u", _mode, sc.samplingRate(), sc.ledPulseWidth()); return false; } if (writeRegister8(SPO2_CONFIGURATION, c) && read_spo2_configration(chk) && (chk == c)) { - _interval = interval_table[m5::stl::to_underlying(sc.sampleRate())]; + _interval = interval_table[m5::stl::to_underlying(sc.samplingRate())]; return true; } return false; diff --git a/src/unit/unit_MAX30100.hpp b/src/unit/unit_MAX30100.hpp index 9deb8d4..6022fa1 100644 --- a/src/unit/unit_MAX30100.hpp +++ b/src/unit/unit_MAX30100.hpp @@ -81,11 +81,11 @@ struct ModeConfiguration { }; /*! - @enum Sample - @brief Sample rate for pulse + @enum Sampling + @brief Sampling rate for pulse @details Unit is the number of sample per second */ -enum class Sample : uint8_t { +enum class Sampling : uint8_t { Rate50, //!< 50 sps Rate100, //!< 100 sps Rate167, //!< 167 sps @@ -96,6 +96,13 @@ enum class Sample : uint8_t { Rate1000, //!< 1000 sps }; +/*! + @brief Enum to sampling rate value + @param rate Enum value + @return sampling rate + */ +uint32_t getSamplingRate(const Sampling rate); + /*! @enum LedPulseWidth @brief LED pulse width (the IR and RED have the same pulse width) @@ -114,7 +121,7 @@ enum class LedPulseWidth { on the mode - Mode:SPO2 - |Sample\PulseWidth|200 |400 |800 |1600| + |Sampling\PulseWidth|200 |400 |800 |1600| |---|---|---|---|---| | 50|o|o|o|o| | 100|o|o|o|o| @@ -125,7 +132,7 @@ enum class LedPulseWidth { | 800|o|x|x|x| |1000|o|x|x|x| - Mode:HROnly - |Sample\PulseWidth|200 |400 |800 |1600| + |Sampling\PulseWidth|200 |400 |800 |1600| |---|---|---|---|---| | 50|o|o|o|o| | 100|o|o|o|o| @@ -143,9 +150,9 @@ struct SpO2Configuration { { // for SpO2 return value & (1U << 6); } - Sample sampleRate() const + Sampling samplingRate() const { - return static_cast((value >> 2) & 0x07); + return static_cast((value >> 2) & 0x07); } LedPulseWidth ledPulseWidth() const { @@ -159,7 +166,7 @@ struct SpO2Configuration { { // for SpO2 value = (value & ~(1U << 6)) | ((b ? 1 : 0) << 6); } - void sampleRate(const Sample rate) + void samplingRate(const Sampling rate) { value = (value & ~(0x07 << 2)) | ((m5::stl::to_underlying(rate) & 0x07) << 2); } @@ -268,15 +275,15 @@ class UnitMAX30100 : public Component, public PeriodicMeasurementAdapter -#include -#include -#include - -using namespace m5::max30100; - -namespace { - -constexpr float ALPHA{0.95f}; // for removeDC - -void calculateButterworthCoefficients(float Fs, float Fc, float& a0, float& a1, float& b1) -{ - float tanWc = std::tan(M_PI * Fc / Fs); - float sqrt2 = std::sqrt(2.0f); - - a0 = tanWc / (tanWc + sqrt2); - a1 = a0; - b1 = (tanWc - sqrt2) / (tanWc + sqrt2); -} - -inline dcFilter_t removeDC(const float x, const float prev_w, const float alpha) -{ - dcFilter_t filtered; - filtered.w = x + alpha * prev_w; - filtered.result = filtered.w - prev_w; - return filtered; -} - -float meanDiff(const float M, meanDiffFilter_t& filterValues) -{ - float avg{}; - - filterValues.sum -= filterValues.values[filterValues.index]; - filterValues.values[filterValues.index] = M; - filterValues.sum += filterValues.values[filterValues.index]; - - filterValues.index++; - filterValues.index = filterValues.index % meanDiffFilter_t::MEAN_FILTER_SIZE; - - if (filterValues.count < meanDiffFilter_t::MEAN_FILTER_SIZE) { - filterValues.count++; - } - - avg = filterValues.sum / filterValues.count; - return avg - M; -} - -void lowPassButterworthFilter(const float x, butterworthFilter_t& fr) -{ - fr.v[0] = fr.v[1]; - fr.v[1] = (fr.a0 * x) + (fr.a1 * fr.v[0]) - (fr.b1 * fr.v[1]); - fr.result = fr.v[0] + fr.v[1]; -} - -#if 0 -std::pair calculateACDC( - const std::deque& data) { - float maxVal = *std::max_element(data.begin(), data.end()); - float minVal = *std::min_element(data.begin(), data.end()); - return {maxVal - minVal, - std::accumulate(data.begin(), data.end(), 0.0f) / data.size()}; -} -#endif - -} // namespace - -namespace m5 { -namespace max30100 { - -HeartRate::HeartRate(const uint32_t srate, const float threshold, const size_t max_data_size) - : _sampleRate{(float)srate}, _threshold(threshold), _maxDataSize{max_data_size} -{ - assert(srate && "SampleRate must not be zero"); - if (!max_data_size) { - _maxDataSize = (size_t)srate * 30U; - } - calculateButterworthCoefficients(_sampleRate, 10.0f, _bwfIR.a0, _bwfIR.a1, _bwfIR.b1); -} - -void HeartRate::setSampleRate(const uint32_t sr) -{ - _sampleRate = sr; - calculateButterworthCoefficients(_sampleRate, 10.0f, _bwfIR.a0, _bwfIR.a1, _bwfIR.b1); - clear(); -} - -void HeartRate::clear() -{ - _dataIR.clear(); - _peakDowns.clear(); - _incrasing = false; - _dcIR = dcFilter_t{}; - _mdIR = meanDiffFilter_t{}; - _bwfIR = butterworthFilter_t{}; - calculateButterworthCoefficients(_sampleRate, 10.0f, _bwfIR.a0, _bwfIR.a1, _bwfIR.b1); -} - -bool HeartRate::push_back(const float ir, const float red) -{ - // Filtering (IR) - _dcIR = removeDC(ir, _dcIR.w, ALPHA); - // M5_LIB_LOGI("\n>ACIR:%f", _dcIR.result); - auto md = meanDiff(_dcIR.result, _mdIR); - // M5_LIB_LOGI("\n>MD:%f", md); - lowPassButterworthFilter(md, _bwfIR); - // M5_LIB_LOGI("\n>LP:%f", _bwfIR.result); - - // Filtering (RED) - _dcRED = removeDC(red, _dcRED.w, ALPHA); - // M5_LIB_LOGI("\n>ACRED:%f", _dcRED.result); - - // Store - _dataIR.push_back(_bwfIR.result); - if (_dataIR.size() > _maxDataSize) { - _dataIR.pop_front(); - } - - // Heart beat - _beat = detect_beat(); - - // SpO2 - _acSqIR += _dcIR.result * _dcIR.result; - //_acSqRED += _dcRED.result * _dcRED.result; - _acSqRED = _dcRED.result * _dcRED.result; - ++_count; - if (_beat) { - float rr = std::log(std::sqrt(_acSqRED / _count)) / std::log(std::sqrt(_acSqIR / _count)); - auto s = 110.0f - _coeffSpO2 * rr; - _SpO2 = std::fmin(std::fmax(s, 80.f), 100.f); - _acSqIR = _acSqRED = 0.0f; - _count = 0; - } - return _beat; -} - -float HeartRate::calculate() const -{ - if (_peakDowns.size() < 2) { - return 0.0f; - } - - float total{}; - for (size_t i = 1; i < _peakDowns.size(); ++i) { - total += _peakDowns[i] - _peakDowns[i - 1]; - } - float avg = total / (_peakDowns.size() - 1); - return 1.0f / avg * 60000.0f; -} - -bool HeartRate::detect_beat() -{ - auto now = m5::utility::millis(); - bool beat{}; - - if (_dataIR.size() >= 4) { - auto d3 = _dataIR.back(); - auto d2 = _dataIR[_dataIR.size() - 2]; - auto d1 = _dataIR[_dataIR.size() - 3]; - auto d0 = _dataIR[_dataIR.size() - 4]; - if (!_incrasing && (d0 > _threshold) && (d1 > d0) && (d2 > d1) && (d3 > d2)) { - _incrasing = true; - } else if (_incrasing && (d1 < d0) && (d2 < d1) && (d3 < d2)) { - _incrasing = false; - beat = true; - _peakDowns.push_back(now); - } - } - // Remove old peaks from the window - while (!_peakDowns.empty() && now - _peakDowns.front() > 1000 * 10) { - _peakDowns.pop_front(); - } - return beat; -} - -} // namespace max30100 -} // namespace m5 diff --git a/src/utility/heart_rate.hpp b/src/utility/heart_rate.hpp deleted file mode 100644 index 4f54a7a..0000000 --- a/src/utility/heart_rate.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD - * - * SPDX-License-Identifier: MIT - */ -/*! - @file heart_rate.hpp - @brief Calculate heart rate and SpO2 -*/ -#ifndef M5_UNIT_HEART_UTILITY_HEART_RATE_HPP -#define M5_UNIT_HEART_UTILITY_HEART_RATE_HPP - -#include -#include -#include -#include "../unit/unit_MAX30100.hpp" - -namespace m5 { -namespace max30100 { - -struct dcFilter_t { - float w; - float result; -}; - -struct meanDiffFilter_t { - static constexpr uint32_t MEAN_FILTER_SIZE{15}; - float values[MEAN_FILTER_SIZE]; - uint8_t index; - float sum; - uint8_t count; -}; - -struct butterworthFilter_t { - float v[2]; - float result; - float a0, a1, b1; -}; - -/*! - @class HeartRate - @brief Utility class for calcurate heart beat rate and SpO2 - */ -class HeartRate { -public: - /*! - @brief Conversion m5::unit::max30100::Sample to sapling rate - @param rate bm5::unit::max30100::Sample value - @return Sample rate - */ - static uint32_t getSampleRate(const m5::unit::max30100::Sample rate) - { - static constexpr uint32_t table[] = {50, 100, 167, 200, 400, 600, 800, 1000}; - return table[m5::stl::to_underlying(rate)]; - } - - /*! - @param sr Sample rate (e.g. 167 if max30100::Sample::Rate167) - @param threshold Threshold for detect beat (depends on ir/redCUrrent) - @param store_size Stored data size(0U means auto) - */ - explicit HeartRate(const uint32_t srate = 1, const float threshold = 125.f, const size_t max_data_size = 0U); - - ///@name Settings - ///@{ - //! @brief Set sample rate - void setSampleRate(const uint32_t sr); - //! @brief Set threshold - void setThreshold(const float t) - { - _threshold = t; - } - //! @brief Set coefficients for SpO2 calculations - void setSpO2Coefficients(const float coeff) - { - _coeffSpO2 = coeff; - } - ///@} - - //! @brief Stock sample value - bool push_back(const float ir, const float red); - /*! - @brief Clear inner buffer - @note When starting measurement again, etc - */ - void clear(); - - ///@name Gets the values - ///@{ - /*! - @brief Calculate heart rate from data stocked at the time of call - @return heart beat rate - */ - float calculate() const; - //! @brief Gets the latest SpO2 - float SpO2() const - { - return _SpO2; - } - ///@} - -private: - bool detect_beat(); - - float _sampleRate{}, _threshold{}; - size_t _maxDataSize{}; - std::deque _dataIR{}; - std::deque _peakDowns{}; - bool _incrasing{}, _beat{}; - uint32_t _count{}; - - dcFilter_t _dcIR{}, _dcRED{}; - meanDiffFilter_t _mdIR{}; - butterworthFilter_t _bwfIR{}; - - float _acSqIR{}, _acSqRED{}; - float _SpO2{}, _coeffSpO2{18.0f}; - - // float _calibrationSpO2{}; -}; - -} // namespace max30100 -} // namespace m5 -#endif diff --git a/src/utility/pulse_monitor.cpp b/src/utility/pulse_monitor.cpp new file mode 100644 index 0000000..3520bfb --- /dev/null +++ b/src/utility/pulse_monitor.cpp @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file pulse_monitor.cpp + @brief Calculate BPM and SpO2 +*/ +#include "pulse_monitor.hpp" +#include + +namespace m5 { +namespace heart { + +void PulseMonitor::setSamplingRate(const float samplingRate) +{ + if (samplingRate < 1.0f) { + M5_LIB_LOGE("SamplingRate must be greater equal than 1.0f"); + return; + } + _sampling_rate = samplingRate; + _max_samples = (size_t)samplingRate * _range; + + _filterIR.setSamplingRate(5.0f, samplingRate); + _filterRED.setSamplingRate(5.0f, samplingRate); + _dataIR.clear(); + _dataRED.clear(); + _beat = false; + _bpm = _SpO2 = 0.0f; + + _count = 0; + _avered = _aveir = _sumredrms = _sumirrms = 0; +} + +void PulseMonitor::push_back(const float ir) +{ + _dataIR.push_back(_filterIR.process(ir)); + if (_dataIR.size() > _max_samples) { + _dataIR.pop_front(); + } +} + +void PulseMonitor::push_back(const float ir, const float red) +{ + push_back(ir); + _dataRED.push_back(_filterRED.process(red)); + if (_dataRED.size() > _max_samples) { + _dataRED.pop_front(); + } + + // For SpO2 (each second) + _avered = _avered * 0.95f + red * (1.0f - 0.95f); + _aveir = _aveir * 0.95f + ir * (1.0f - 0.95f); + _sumredrms += (red - _avered) * (red - _avered); + _sumirrms += (ir - _aveir) * (ir - _aveir); + if (++_count == (uint32_t)_sampling_rate) { + float R = (std::sqrt(_sumredrms) / _avered) / (std::sqrt(_sumirrms) / _aveir); + _SpO2 = -23.3f * (R - 0.4f) + 100; + _SpO2 = std::fmax(std::fmin(100.0f, _SpO2), 80.0f); // clamp 80-100 + _sumredrms = _sumirrms = 0; + _count = 0; + } +} + +void PulseMonitor::update() +{ + _bpm = calculate_bpm(); +} + +float PulseMonitor::calculate_bpm() +{ + std::vector peaks; + float threshold = 50.f; + bool negatived{}; + for (uint32_t i = 1; i < _dataIR.size() - 1; ++i) { + if (negatived && (_dataIR[i] > threshold) && _dataIR[i] > _dataIR[i - 1] && _dataIR[i] > _dataIR[i + 1]) { + peaks.push_back(i); + negatived = false; + _beat = (i == (_dataIR.size() - 2)); // last? + } else if (!negatived && _dataIR[i] < 0.0f) { + negatived = true; + } + } + if (peaks.size() < 2) { + return 0.0f; + } + + float isum{}; + uint32_t cnt{}; + for (size_t i = 1; i < peaks.size(); ++i) { + isum += (peaks[i] - peaks[i - 1]) / _sampling_rate; + ++cnt; + } + float average_rr = isum / cnt; + return 60.0f / average_rr; +} + +} // namespace heart +} // namespace m5 diff --git a/src/utility/pulse_monitor.hpp b/src/utility/pulse_monitor.hpp new file mode 100644 index 0000000..fb57a87 --- /dev/null +++ b/src/utility/pulse_monitor.hpp @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file pulse_monitor.hpp + @brief Calculate BPM and SpO2 +*/ +#ifndef M5_UNIT_HEART_UTILITY_PULSE_MONITOR_HPP +#define M5_UNIT_HEART_UTILITY_PULSE_MONITOR_HPP + +#include +#include +#include +#include +#include "../unit/unit_MAX30100.hpp" + +namespace m5 { +/*! + @namepsace heart + @brief Unit-HEART releated + */ +namespace heart { + +/*! + @class EMA + @brief Exponential Moving Average + */ +class EMA { +public: + explicit EMA(float factor) : _alpha(factor) + { + } + + inline void clear() + { + _ema_value = std::numeric_limits::quiet_NaN(); + } + + inline float update(float new_value) + { + if (!std::isnan(_ema_value)) { + _ema_value = _alpha * new_value + (1.0f - _alpha) * _ema_value; + } else { + _ema_value = new_value; + } + return _ema_value; + } + +private: + float _alpha{}, _ema_value{std::numeric_limits::quiet_NaN()}; +}; + +/*! + @class Filter + @brief Apply a high-pass filter and reverse polarity + */ +class Filter { +public: + Filter(const float cutoff, const float sampling_rate) + { + setSamplingRate(cutoff, sampling_rate); + } + + void setSamplingRate(const float cutoff, const float sampling_rate) + { + _cutoff = cutoff; + _samplingRate = sampling_rate; + _prevIn = _prevOut = 0.0f; + auto dt = 1.0f / _samplingRate; + auto RC = 1.0f / (2.0f * M_PI * _cutoff); + _alpha = RC / (RC + dt); + _ema.clear(); + } + + float process(const float value) + { + float out = _ema.update(_alpha * (_prevOut + value - _prevIn)); + _prevIn = value; + _prevOut = out; + return -out; + } + +private: + EMA _ema{0.95f}; + float _cutoff{}, _samplingRate{}; + float _prevIn{}, _prevOut{}; + float _alpha{}; +}; + +/*! + @class PulseMonitor + @brief Calculate BPM and SpO2, and detect the pulse beat + */ +class PulseMonitor { +public: + PulseMonitor(const float samplingRate, const uint32_t sec = 5) + : _range{sec}, + _sampling_rate{samplingRate}, + _max_samples{(size_t)samplingRate * sec}, + _filterIR(5.0f, samplingRate), + _filterRED(5.0f, samplingRate) + { + assert(samplingRate >= 1.0f && "SamplingRate must be greater equal than 1.0f"); + } + + void setSamplingRate(const float samplingRate); + + void push_back(const float ir); + void push_back(const float ir, const float red); + + void update(); + + bool isBeat() const + { + return _beat; + } + float bpm() const + { + return _bpm; + } + float SpO2() const + { + return _SpO2; + } + float latestIR() const + { + return !_dataIR.empty() ? _dataIR.back() : std::numeric_limits::quiet_NaN(); + } + + float latestRED() const + { + return !_dataRED.empty() ? _dataRED.back() : std::numeric_limits::quiet_NaN(); + } + +protected: + float calculate_bpm(); + +private: + uint32_t _range{}; // Sec. + float _sampling_rate{}; + size_t _max_samples{}; + Filter _filterIR{0.5f, 100.f}; + Filter _filterRED{0.5f, 100.f}; + + std::deque _dataIR; + std::deque _dataRED; + + bool _beat{}; + float _bpm{}; + float _SpO2{}; + + uint32_t _count{}; + float _avered{}, _aveir{}; + float _sumredrms{}, _sumirrms{}; +}; + +} // namespace heart +} // namespace m5 +#endif From 98e85d21f22750ffb82f3f005a0c2284c7c02382 Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 16 Oct 2024 19:12:55 +0900 Subject: [PATCH 03/10] Add GitHub Pages URL --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index af412d8..90bdd77 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ See also examples using conventional methods here. See also [examples/UnitUnified](examples/UnitUnified) ## Doxygen document +[GitHub Pages](https://m5stack.github.io/M5Unit-HEART/) + If you want to generate documents on your local machine, execute the following command ``` From 54cc017c630184f0a3d1b242e758c717ba434e04 Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 16 Oct 2024 19:13:22 +0900 Subject: [PATCH 04/10] Fixes dependencies --- library.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library.json b/library.json index 508e840..a657a43 100644 --- a/library.json +++ b/library.json @@ -11,9 +11,7 @@ "url": "https://github.com/m5stack/M5Unit-HEART.git" }, "dependencies": { - "M5UnitUnified": "https://github.com/m5stack/M5UnitUnified.git", - "M5Utility": "https://github.com/m5stack/M5Utility.git", - "M5HAL": "https://github.com/m5stack/M5HAL.git" + "M5UnitUnified": "https://github.com/m5stack/M5UnitUnified.git" }, "version": "0.0.1", "frameworks": [ From 82d8ffaa530e326f827fd8b5b5cb2c801d9808d4 Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 16 Oct 2024 19:14:12 +0900 Subject: [PATCH 05/10] Add doxyegn comment --- src/utility/pulse_monitor.cpp | 13 ++++--- src/utility/pulse_monitor.hpp | 64 +++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/utility/pulse_monitor.cpp b/src/utility/pulse_monitor.cpp index 3520bfb..6a33912 100644 --- a/src/utility/pulse_monitor.cpp +++ b/src/utility/pulse_monitor.cpp @@ -23,9 +23,12 @@ void PulseMonitor::setSamplingRate(const float samplingRate) _max_samples = (size_t)samplingRate * _range; _filterIR.setSamplingRate(5.0f, samplingRate); - _filterRED.setSamplingRate(5.0f, samplingRate); + clear(); +} + +void PulseMonitor::clear() +{ _dataIR.clear(); - _dataRED.clear(); _beat = false; _bpm = _SpO2 = 0.0f; @@ -44,10 +47,6 @@ void PulseMonitor::push_back(const float ir) void PulseMonitor::push_back(const float ir, const float red) { push_back(ir); - _dataRED.push_back(_filterRED.process(red)); - if (_dataRED.size() > _max_samples) { - _dataRED.pop_front(); - } // For SpO2 (each second) _avered = _avered * 0.95f + red * (1.0f - 0.95f); @@ -57,7 +56,7 @@ void PulseMonitor::push_back(const float ir, const float red) if (++_count == (uint32_t)_sampling_rate) { float R = (std::sqrt(_sumredrms) / _avered) / (std::sqrt(_sumirrms) / _aveir); _SpO2 = -23.3f * (R - 0.4f) + 100; - _SpO2 = std::fmax(std::fmin(100.0f, _SpO2), 80.0f); // clamp 80-100 + _SpO2 = std::fmax(std::fmin(100.0f, _SpO2), 80.0f); // clamp 80-100 _sumredrms = _sumirrms = 0; _count = 0; } diff --git a/src/utility/pulse_monitor.hpp b/src/utility/pulse_monitor.hpp index fb57a87..d08bb60 100644 --- a/src/utility/pulse_monitor.hpp +++ b/src/utility/pulse_monitor.hpp @@ -95,45 +95,75 @@ class Filter { */ class PulseMonitor { public: + /*! + @brief Costructor + @param samplingRate sampling rate + @param sec Seconds of data to be stored + */ PulseMonitor(const float samplingRate, const uint32_t sec = 5) : _range{sec}, _sampling_rate{samplingRate}, _max_samples{(size_t)samplingRate * sec}, - _filterIR(5.0f, samplingRate), - _filterRED(5.0f, samplingRate) + _filterIR(5.0f, samplingRate) { - assert(samplingRate >= 1.0f && "SamplingRate must be greater equal than 1.0f"); + assert(sec >= 1 && "sec must be greater or eaual than 1"); + assert(samplingRate >= 1.0f && "SamplingRate must be greater or equal than 1.0f"); } - void setSamplingRate(const float samplingRate); - - void push_back(const float ir); - void push_back(const float ir, const float red); - - void update(); - + //! @brief Detect beat? bool isBeat() const { return _beat; } + //! @brief Gets the BPM float bpm() const { return _bpm; } + /*! + @brief Gets the SpO2 + @warning IR and RED must be pushed back + */ float SpO2() const { return _SpO2; } + + /*! + @brief Set the sampling rate + @param samplingRate sampling rate + @note clear stored data + */ + void setSamplingRate(const float samplingRate); + + /*! + @brief Push back IR + @param ir IR data + */ + void push_back(const float ir); + /*! + @brief Push back IR and RED + @param ir IR data + @param red RED data + @note Calclate SpO2 + */ + void push_back(const float ir, const float red); + + /*! + @brief Update status + @note Calclate BPM + */ + void update(); + + //! @brief Clear inner data + void clear(); + + // filterd ir value float latestIR() const { return !_dataIR.empty() ? _dataIR.back() : std::numeric_limits::quiet_NaN(); } - float latestRED() const - { - return !_dataRED.empty() ? _dataRED.back() : std::numeric_limits::quiet_NaN(); - } - protected: float calculate_bpm(); @@ -141,11 +171,9 @@ class PulseMonitor { uint32_t _range{}; // Sec. float _sampling_rate{}; size_t _max_samples{}; - Filter _filterIR{0.5f, 100.f}; - Filter _filterRED{0.5f, 100.f}; + Filter _filterIR{0.5f, 100.f}; std::deque _dataIR; - std::deque _dataRED; bool _beat{}; float _bpm{}; From 82c11420bf23579b3aaab3b13e0cc25c68d28005 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 17 Oct 2024 17:38:14 +0900 Subject: [PATCH 06/10] Fixes conditions --- .github/workflows/ArduinoBuild_2.yml | 84 +++++++++--------------- .github/workflows/ArduinoBuild_3.yml | 84 +++++++++--------------- .github/workflows/PlatformioBuild.yml | 52 ++++++++++----- .github/workflows/clang-format-check.yml | 18 ++++- 4 files changed, 111 insertions(+), 127 deletions(-) diff --git a/.github/workflows/ArduinoBuild_2.yml b/.github/workflows/ArduinoBuild_2.yml index d221467..4cc4ebe 100644 --- a/.github/workflows/ArduinoBuild_2.yml +++ b/.github/workflows/ArduinoBuild_2.yml @@ -2,26 +2,44 @@ name: ArduinoBuild(platform-version 2.x) env: SKETCH_NAMES_FIND_START: ./examples/UnitUnified - REQUIRED_LIBRARIES: M5Unified -# M5UNITUNIFIED_BRANCH: main - M5UNITUNIFIED_BRANCH: develop + REQUIRED_LIBRARIES: M5Unified,M5UnitUnified on: push: + tags-ignore: + - '*.*.*' + branches: + - '*' paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' - '**ArduinoBuild_2.yml' pull_request: paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' - '**ArduinoBuild_2.yml' workflow_dispatch: @@ -58,51 +76,11 @@ jobs: - esp32 steps: - - - name: Running on GitHub Actions - if: env.ACT != 'true' - run: echo "This is running on GitHub Actions." - - - name: Running locally with act - if: env.ACT == 'true' - run: echo "This is running locally with act." - - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - # Checkout library from specific URL and branch - # Note that dependent libraries are not automatically installed. - -# - name: Configure git for authentication (Until each repository is published) -# run: | -# git config --global url."https://${{ secrets.TOKEN_M5UNITUNIFIED }}@github.com/".insteadOf "https://github.com/" - - - name: Checkout M5Utility - uses: actions/checkout@v3 - with: - repository: m5stack/M5Utility - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5Utility # must contain string "Custom" - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - - - name: Checkout M5HAL - uses: actions/checkout@v3 - with: - repository: m5stack/M5HAL - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5HAL # must contain string "Custom" - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - - - name: Checkout M5UnitUnified - uses: actions/checkout@v3 - with: - repository: m5stack/M5UnitUnified - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5UnitUnified - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - # Build - name: Compile examples uses: ArminJo/arduino-test-compile@master diff --git a/.github/workflows/ArduinoBuild_3.yml b/.github/workflows/ArduinoBuild_3.yml index da05778..04b6c5b 100644 --- a/.github/workflows/ArduinoBuild_3.yml +++ b/.github/workflows/ArduinoBuild_3.yml @@ -2,26 +2,44 @@ name: ArduinoBuild(platform-version 3.x) env: SKETCH_NAMES_FIND_START: ./examples/UnitUnified - REQUIRED_LIBRARIES: M5Unified -# M5UNITUNIFIED_BRANCH: main - M5UNITUNIFIED_BRANCH: develop + REQUIRED_LIBRARIES: M5Unified,M5UnitUnified on: push: + tags-ignore: + - '*.*.*' + branches: + - '*' paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' - '**ArduinoBuild_3.yml' pull_request: paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' - '**ArduinoBuild_3.yml' workflow_dispatch: @@ -64,51 +82,11 @@ jobs: - esp32 steps: - - - name: Running on GitHub Actions - if: env.ACT != 'true' - run: echo "This is running on GitHub Actions." - - - name: Running locally with act - if: env.ACT == 'true' - run: echo "This is running locally with act." - - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - # Checkout library from specific URL and branch - # Note that dependent libraries are not automatically installed. - -# - name: Configure git for authentication (Until each repository is published) -# run: | -# git config --global url."https://${{ secrets.TOKEN_M5UNITUNIFIED }}@github.com/".insteadOf "https://github.com/" - - - name: Checkout M5Utility - uses: actions/checkout@v3 - with: - repository: m5stack/M5Utility - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5Utility # must contain string "Custom" - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - - - name: Checkout M5HAL - uses: actions/checkout@v3 - with: - repository: m5stack/M5HAL - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5HAL # must contain string "Custom" - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - - - name: Checkout M5UnitUnified - uses: actions/checkout@v3 - with: - repository: m5stack/M5UnitUnified - ref: ${{ env.M5UNITUNIFIED_BRANCH }} - path: CustomLibrary_M5UnitUnified - token: ${{ secrets.TOKEN_M5UNITUNIFIED }} # Only required during development in private repo - # Build - name: Compile examples uses: ArminJo/arduino-test-compile@master diff --git a/.github/workflows/PlatformioBuild.yml b/.github/workflows/PlatformioBuild.yml index 52fbe15..74ff781 100644 --- a/.github/workflows/PlatformioBuild.yml +++ b/.github/workflows/PlatformioBuild.yml @@ -2,23 +2,43 @@ name: PlatformIOBuild on: push: + tags-ignore: + - '*.*.*' + branches: + - '*' paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' - - '**PlatformioBuild.yml' - - '**platformio.ini' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' + - '**PlatformioBuild.yml' + - '**platformio.ini' pull_request: paths: - - '**.ino' - - '**.cpp' - - '**.hpp' - - '**.h' - - '**.c' - - '**PlatformioBuild.yml' - - '**platformio.ini' + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' + - '**PlatformioBuild.yml' + - '**platformio.ini' workflow_dispatch: jobs: @@ -91,10 +111,6 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - name: Configure git for authentication (Until each repository is published) - run: | - git config --global url."https://${{ secrets.TOKEN_M5UNITUNIFIED }}@github.com/".insteadOf "https://github.com/" - - name: Build examples uses: karniv00l/platformio-run-action@v1 with: diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 0b6b959..f7d9f6c 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -5,7 +5,13 @@ env: on: push: + tags-ignore: + - '*.*.*' + - 'v*.*.*' + branches: + - '*' paths: + - '*' - '**.ino' - '**.cpp' - '**.hpp' @@ -13,7 +19,9 @@ on: - '**.c' - '**.inl' - '**clang-format-check.yml' - pull_request: + - '**.clang-format' + pull_request: + paths: - '**.ino' - '**.cpp' - '**.hpp' @@ -21,6 +29,8 @@ on: - '**.c' - '**.inl' - '**clang-format-check.yml' + - '**.clang-format' + workflow_dispatch: jobs: formatting-check: @@ -34,10 +44,12 @@ jobs: - check: 'src' - check: 'test' - check: 'examples' - # exclude: '(Fonts)' # Exclude file paths containing "Fonts" + # exclude: '(Fonts)' # Exclude file paths containing "Fonts" + #- check: 'examples' + # exclude: '' steps: - - name: Checkout # When pull_request is used, include it in the checkout https://zenn.dev/hkusu/articles/c731862051438b + - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} From fd483d18254431059d4e037360092ece3f85ebba Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 17 Oct 2024 17:40:37 +0900 Subject: [PATCH 07/10] Cosmetic change --- examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp b/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp index f1840a0..88231ca 100644 --- a/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp +++ b/examples/UnitUnified/PlotToSerial/main/PlotToSerial.cpp @@ -92,7 +92,7 @@ void loop() // MAX30100 is equipped with a FIFO, so multiple data may be stored while (unit.available()) { monitor.push_back(unit.ir(), unit.red()); // Push back the oldest data - //M5_LOGI("\n>MIR:%f\n>MRED:%f", monitor.latestIR(), monitor.latestRED()); + // M5_LOGI("\n>MIR:%f\n>MRED:%f", monitor.latestIR(), monitor.latestRED()); monitor.update(); beat = monitor.isBeat(); unit.discard(); // Discard the oldest data From 5b14c709c611bdee9a417ce91cb7fb424a632c61 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 17 Oct 2024 17:51:53 +0900 Subject: [PATCH 08/10] Fixes wrong settings --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 4d1e22a..3fb202e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -239,7 +239,7 @@ extends=Core, option_release, arduino_5_4_0 build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> [env:PlotToSerial_Core_Arduino_4_4_0] -extends=Core, option_release, arduino_5_4_0 +extends=Core, option_release, arduino_4_4_0 build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> [env:PlotToSerial_Core2_Arduino_latest] From 2ab804bf3ea6c797862ed072903576cab4fb43fa Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 24 Oct 2024 17:35:59 +0900 Subject: [PATCH 09/10] Add supported core --- ...d_2.yml => arduino-esp-v2-build-check.yml} | 21 +-- ...d_3.yml => arduino-esp-v3-build-check.yml} | 36 ++++-- .github/workflows/arduino-m5-build-check.yml | 120 ++++++++++++++++++ .github/workflows/clang-format-check.yml | 1 - ...ioBuild.yml => platformio-build-check.yml} | 95 +++++++------- boards/m5stack-atoms3r.json | 41 ++++++ boards/m5stack-nanoc6.json | 2 +- boards/m5stick-cplus2.json | 40 ++++++ platformio.ini | 67 +++++++++- test/embedded/test_max30100/max30100_test.cpp | 26 ++-- 10 files changed, 368 insertions(+), 81 deletions(-) rename .github/workflows/{ArduinoBuild_2.yml => arduino-esp-v2-build-check.yml} (86%) rename .github/workflows/{ArduinoBuild_3.yml => arduino-esp-v3-build-check.yml} (76%) create mode 100644 .github/workflows/arduino-m5-build-check.yml rename .github/workflows/{PlatformioBuild.yml => platformio-build-check.yml} (50%) create mode 100644 boards/m5stack-atoms3r.json create mode 100644 boards/m5stick-cplus2.json diff --git a/.github/workflows/ArduinoBuild_2.yml b/.github/workflows/arduino-esp-v2-build-check.yml similarity index 86% rename from .github/workflows/ArduinoBuild_2.yml rename to .github/workflows/arduino-esp-v2-build-check.yml index 4cc4ebe..efece06 100644 --- a/.github/workflows/ArduinoBuild_2.yml +++ b/.github/workflows/arduino-esp-v2-build-check.yml @@ -1,4 +1,4 @@ -name: ArduinoBuild(platform-version 2.x) +name: Build(arduino-esp32:2.x) env: SKETCH_NAMES_FIND_START: ./examples/UnitUnified @@ -8,6 +8,7 @@ on: push: tags-ignore: - '*.*.*' + - 'v*.*.*' branches: - '*' paths: @@ -24,7 +25,7 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**ArduinoBuild_2.yml' + - '**arduino-esp-v2-build-check.yml' pull_request: paths: - 'src/unit/**.cpp' @@ -40,12 +41,12 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**ArduinoBuild_2.yml' + - '**arduino-esp-v2-build-check.yml' workflow_dispatch: jobs: build: - name: ${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}} + name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}} runs-on: ubuntu-latest strategy: @@ -58,15 +59,19 @@ jobs: sketch: - PlotToSerial + unit: + - '' + board: + - m5stack-atom + - m5stack-atoms3 - m5stack-core-esp32 - m5stack-core2 - - m5stack-atoms3 + - m5stack-coreink - m5stack-cores3 + - m5stack-fire platform-version: - #- 2.0.15 - #- 2.0.16 - 2.0.17 platform: @@ -92,5 +97,5 @@ jobs: extra-arduino-cli-args: ${{ matrix.cli-args }} #build-properties: ${{ toJson(matrix.build-properties) }} sketch-names: ${{ matrix.sketch }}.ino - sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }} + sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }} #sketches-exclude: ${{ matrix.sketches-exclude }} diff --git a/.github/workflows/ArduinoBuild_3.yml b/.github/workflows/arduino-esp-v3-build-check.yml similarity index 76% rename from .github/workflows/ArduinoBuild_3.yml rename to .github/workflows/arduino-esp-v3-build-check.yml index 04b6c5b..031860d 100644 --- a/.github/workflows/ArduinoBuild_3.yml +++ b/.github/workflows/arduino-esp-v3-build-check.yml @@ -1,4 +1,4 @@ -name: ArduinoBuild(platform-version 3.x) +name: Build(arduino-esp32:3.x) env: SKETCH_NAMES_FIND_START: ./examples/UnitUnified @@ -8,6 +8,7 @@ on: push: tags-ignore: - '*.*.*' + - 'v*.*.*' branches: - '*' paths: @@ -24,7 +25,7 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**ArduinoBuild_3.yml' + - '**arduino-esp-v3-build-check.yml' pull_request: paths: - 'src/unit/**.cpp' @@ -40,12 +41,12 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**ArduinoBuild_3.yml' + - '**arduino-esp-v3-build-check.yml' workflow_dispatch: jobs: build: - name: ${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}} + name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}} runs-on: ubuntu-latest strategy: @@ -58,21 +59,36 @@ jobs: sketch: - PlotToSerial + unit: + - '' + board: + - m5stack_atom + - m5stack_atoms3 + - m5stack_capsule +# - m5stack_cardputer - m5stack_core - m5stack_core2 - - m5stack_atoms3 + - m5stack_coreink - m5stack_cores3 - m5stack_dial + - m5stack_fire - m5stack_nanoc6 - m5stack_paper +# - m5stack_poe_cam +# - m5stack_stamp_c3 +# - m5stack_stamp_pico + - m5stack_stamp_s3 +# - m5stack_station +# - m5stack_stickc - m5stack_stickc_plus + - m5stack_stickc_plus2 +# - m5stack_timer_cam +# - m5stack_tough +# - m5stack_unit_cam +# - m5stack_unit_cams3 platform-version: - #- 3.0.0 - #- 3.0.1 - #- 3.0.2 - #- 3.0.3 - 3.0.4 platform: @@ -98,5 +114,5 @@ jobs: extra-arduino-cli-args: ${{ matrix.cli-args }} #build-properties: ${{ toJson(matrix.build-properties) }} sketch-names: ${{ matrix.sketch }}.ino - sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }} + sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }} #sketches-exclude: ${{ matrix.sketches-exclude }} diff --git a/.github/workflows/arduino-m5-build-check.yml b/.github/workflows/arduino-m5-build-check.yml new file mode 100644 index 0000000..76366b3 --- /dev/null +++ b/.github/workflows/arduino-m5-build-check.yml @@ -0,0 +1,120 @@ +name: Build(arduino-m5stack) + +env: + SKETCH_NAMES_FIND_START: ./examples/UnitUnified + REQUIRED_LIBRARIES: M5Unified,M5UnitUnified + +on: + push: + tags-ignore: + - '*.*.*' + - 'v*.*.*' + branches: + - '*' + paths: + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' + - '**arduino-m5-build-check.yml' + pull_request: + paths: + - 'src/unit/**.cpp' + - 'src/unit/**.hpp' + - 'src/unit/**.h' + - 'src/unit/**.c' + - 'test/**.cpp' + - 'test/**.hpp' + - 'test/**.h' + - 'test/**.c' + - 'examples/UnitUnified/**.ino' + - 'examples/UnitUnified/**.cpp' + - 'examples/UnitUnified/**.hpp' + - 'examples/UnitUnified/**.h' + - 'examples/UnitUnified/**.c' + - '**arduino-m5-build-check.yml' + workflow_dispatch: + +jobs: + build: + name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}} + runs-on: ubuntu-latest + + strategy: + fail-fast: false +# max-parallel: 1 + matrix: + platform-url: + - https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json + + sketch: + - PlotToSerial + + unit: + - '' + + board: + - m5stack_atom + - m5stack_atoms3 + - m5stack_atoms3r + - m5stack_capsule +# - m5stack_cardputer + - m5stack_core + - m5stack_core2 + - m5stack_coreink + - m5stack_cores3 + - m5stack_dial + - m5stack_dinmeter + - m5stack_fire + - m5stack_paper +# - m5stack_poe_cam +# - m5stack_stamp_c3 +# - m5stack_stamp_pico + - m5stack_stamp_s3 +# - m5stack_station +# - m5stack_stickc + - m5stack_stickc_plus + - m5stack_stickc_plus2 +# - m5stack_timer_cam +# - m5stack_tough +# - m5stack_unit_cam +# - m5stack_unit_cams3 + + platform-version: + - 2.1.2 + + platform: + - m5stack + + archi: + - esp32 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + # Build + - name: Compile examples + uses: ArminJo/arduino-test-compile@master + with: + arduino-board-fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }} + arduino-platform: ${{ matrix.platform }}:${{ matrix.archi }}@${{ matrix.platform-version }} + platform-url: ${{ matrix.platform-url }} + required-libraries: ${{ env.REQUIRED_LIBRARIES }} + extra-arduino-cli-args: ${{ matrix.cli-args }} + #build-properties: ${{ toJson(matrix.build-properties) }} + sketch-names: ${{ matrix.sketch }}.ino + sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }} + #sketches-exclude: ${{ matrix.sketches-exclude }} + diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index f7d9f6c..74dd0e4 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -11,7 +11,6 @@ on: branches: - '*' paths: - - '*' - '**.ino' - '**.cpp' - '**.hpp' diff --git a/.github/workflows/PlatformioBuild.yml b/.github/workflows/platformio-build-check.yml similarity index 50% rename from .github/workflows/PlatformioBuild.yml rename to .github/workflows/platformio-build-check.yml index 74ff781..ab85e4c 100644 --- a/.github/workflows/PlatformioBuild.yml +++ b/.github/workflows/platformio-build-check.yml @@ -1,9 +1,10 @@ -name: PlatformIOBuild +name: Build(platformio) on: push: tags-ignore: - '*.*.*' + - 'v*.*.*' branches: - '*' paths: @@ -20,7 +21,7 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**PlatformioBuild.yml' + - '/platformio-build-check.yml' - '**platformio.ini' pull_request: paths: @@ -37,14 +38,13 @@ on: - 'examples/UnitUnified/**.hpp' - 'examples/UnitUnified/**.h' - 'examples/UnitUnified/**.c' - - '**PlatformioBuild.yml' + - '**/platformio-build-check.yml' - '**platformio.ini' workflow_dispatch: jobs: build: - name: ${{ matrix.example }}@${{ matrix.board }}:${{ matrix.framework }}:${{ matrix.espressif32 }} - + name: ${{ matrix.unit }}:${{ matrix.example }}@${{ matrix.board }}:${{ matrix.framework }}:${{ matrix.espressif32 }} runs-on: ubuntu-latest strategy: @@ -55,55 +55,62 @@ jobs: example: - PlotToSerial + unit: + - '' + board: - Core - Core2 - CoreS3 + - Fire - StampS3 - - AtomS3 - Dial + - AtomMatrix + - AtomS3 + - AtomS3R - NanoC6 - StickCPlus + - StickCPlus2 - Paper - - Fire + - CoreInk framework: - Arduino espressif32: - latest - - '5_4_0' - - '4_4_0' +# - '5_4_0' +# - '4_4_0' - exclude: - - board: CoreS3 - espressif32: '5_4_0' - - board: CoreS3 - espressif32: '4_4_0' - - board: StampS3 - espressif32: '5_4_0' - - board: StampS3 - espressif32: '4_4_0' - - board: AtomS3 - espressif32: '5_4_0' - - board: AtomS3 - espressif32: '4_4_0' - - board: Dial - espressif32: '5_4_0' - - board: Dial - espressif32: '4_4_0' - - board: NanoC6 - espressif32: '5_4_0' - - board: NanoC6 - espressif32: '4_4_0' - - board: StickCPlus - espressif32: '5_4_0' - - board: StickCPlus - espressif32: '4_4_0' - - board: Paper - espressif32: '5_4_0' - - board: Paper - espressif32: '4_4_0' +# exclude: +# - board: CoreS3 +# espressif32: '5_4_0' +# - board: CoreS3 +# espressif32: '4_4_0' +# - board: StampS3 +# espressif32: '5_4_0' +# - board: StampS3 +# espressif32: '4_4_0' +# - board: AtomS3 +# espressif32: '5_4_0' +# - board: AtomS3 +# espressif32: '4_4_0' +# - board: Dial +# espressif32: '5_4_0' +# - board: Dial +# espressif32: '4_4_0' +# - board: NanoC6 +# espressif32: '5_4_0' +# - board: NanoC6 +# espressif32: '4_4_0' +# - board: StickCPlus +# espressif32: '5_4_0' +# - board: StickCPlus +# espressif32: '4_4_0' +# - board: Paper +# espressif32: '5_4_0' +# - board: Paper +# espressif32: '4_4_0' steps: - name: Checkout @@ -114,11 +121,11 @@ jobs: - name: Build examples uses: karniv00l/platformio-run-action@v1 with: - environments: ${{ matrix.example }}_${{ matrix.board }}_${{ matrix.framework }}_${{ matrix.espressif32 }} - #targets: + environments: ${{ matrix.unit != '' && format('{0}_{1}_{2}_{3}_{4}', matrix.unit, matrix.example, matrix.board, matrix.framework, matrix.espressif32) || format('{0}_{1}_{2}_{3}', matrix.example, matrix.board, matrix.framework, matrix.espressif32) }} +# targets: project-dir: "./" project-conf: "./platformio.ini" - #jobs: 6 - #silent: false - #verbose: truee - #disable-auto-clean: false +# jobs: 6 +# silent: false +# verbose: true +# disable-auto-clean: false diff --git a/boards/m5stack-atoms3r.json b/boards/m5stack-atoms3r.json new file mode 100644 index 0000000..1c9ecce --- /dev/null +++ b/boards/m5stack-atoms3r.json @@ -0,0 +1,41 @@ +{ + "build": { + "arduino": { + "memory_type": "qio_opi", + "ldscript": "esp32s3_out.ld", + "partitions": "default_8MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_M5STACK_ATOMS3R", + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_MODE=1", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "dio", + "mcu": "esp32s3", + "variant": "m5stack_atoms3" + }, + "connectivity": [ + "bluetooth", + "wifi" + ], + "frameworks": [ + "arduino", + "espidf" + ], + "name": "M5Stack AtomS3R", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.m5stack.com/en/core/AtomS3R", + "vendor": "M5Stack" +} diff --git a/boards/m5stack-nanoc6.json b/boards/m5stack-nanoc6.json index cae742e..ddaad65 100644 --- a/boards/m5stack-nanoc6.json +++ b/boards/m5stack-nanoc6.json @@ -2,7 +2,7 @@ "build": { "core": "esp32", "extra_flags": [ - "-DARDUINO_M5Stack_NanoC6" + "-DARDUINO_M5STACK_NANOC6" ], "f_cpu": "160000000L", "f_flash": "80000000L", diff --git a/boards/m5stick-cplus2.json b/boards/m5stick-cplus2.json new file mode 100644 index 0000000..91fa2ca --- /dev/null +++ b/boards/m5stick-cplus2.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32_out.ld", + "partitions": "default_8MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DM5STACK_M5STICK_CPLUS2", + "-DBOARD_HAS_PSRAM", + "-mfix-esp32-psram-cache-issue", + "-mfix-esp32-psram-cache-strategy=memw", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "dio", + "mcu": "esp32", + "variant": "m5stick_c" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "frameworks": [ + "arduino", + "espidf" + ], + "name": "M5Stick-CPlus2", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 1500000 + }, + "url": "https://docs.m5stack.com/en/core/M5StickC%20PLUS2", + "vendor": "M5Stack" +} diff --git a/platformio.ini b/platformio.ini index 3fb202e..0f1b3b7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -3,8 +3,6 @@ ; For UnitTest and examples (Using M5UnitUnified) ;----------------------------------------------------------------------- [platformio] -;default_envs = test_UnitHEART_Core, test_UnitHEART_Core2, test_UnitHEART_CoreS3, test_UnitHEART_Fire, test_UnitHEART_StampS3, test_UnitHEART_Dial, test_UnitHEART_AtomS3, test_UnitHEART_NanoC6, test_UnitHEART_StickCPlus, test_UnitHEART_Paper -;default_envs = PlotToSerial_Core_Arduino_latest, PlotToSerial_Core_Arduino_5_4_0, PlotToSerial_Core_Arduino_4_4_0, PlotToSerial_Core2_Arduino_latest, PlotToSerial_Core2_Arduino_5_4_0, PlotToSerial_Core2_Arduino_4_4_0, PlotToSerial_CoreS3_Arduino_latest, PlotToSerial_StampS3_Arduino_latest, PlotToSerial_AtomS3_Arduino_latest, PlotToSerial_Dial_Arduino_latest, PlotToSerial_NanoC6_Arduino_latest, PlotToSerial_StickCPlus_Arduino_latest, PlotToSerial_Paper_Arduino_latest, PlotToSerial_Fire_Arduino_latest, PlotToSerial_Fire_Arduino_5_4_0, PlotToSerial_Fire_Arduino_4_4_0 [env] build_flags =-Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr @@ -45,7 +43,7 @@ board = m5stack-fire lib_deps = ${env.lib_deps} [StampS3] -;include M5Capsule +;include M5Capsule, DinMeter extends = m5base board = m5stack-stamps3 lib_deps = ${env.lib_deps} @@ -56,11 +54,22 @@ board = m5stack-stamps3 lib_deps = ${env.lib_deps} m5stack/M5Dial +[AtomMatrix] +extends = m5base +board = m5stack-atom +lib_deps = ${env.lib_deps} + [AtomS3] extends = m5base board = m5stack-atoms3 lib_deps = ${env.lib_deps} +; Using ./boards/m5stack-atoms3r.json +[AtomS3R] +extends = m5base +board = m5stack-atoms3r +lib_deps = ${env.lib_deps} + ; Using ./boards/m5stack-nanoc6.json [NanoC6] extends = m5base @@ -77,10 +86,20 @@ extends = m5base board = m5stick-c lib_deps = ${env.lib_deps} +; Using ./boards/m5stick-cplus2.json +[StickCPlus2] +extends = m5base +board = m5stick-cplus2 +lib_deps = ${env.lib_deps} + [Paper] extends = m5base board = m5stack-fire -; Using M5Fire instead of the M5Paper(Noting...) +lib_deps = ${env.lib_deps} + +[CoreInk] +extends = m5base +board = m5stack-coreink lib_deps = ${env.lib_deps} [sdl] @@ -202,12 +221,24 @@ lib_deps = ${Dial.lib_deps} ${test_fw.lib_deps} test_filter= embedded/test_max30100 +[env:test_UnitHEART_AtomMatrix] +extends=AtomMatrix, option_release, arduino_latest +lib_deps = ${AtomMatrix.lib_deps} + ${test_fw.lib_deps} +test_filter= embedded/test_max30100 + [env:test_UnitHEART_AtomS3] extends=AtomS3, option_release, arduino_latest lib_deps = ${AtomS3.lib_deps} ${test_fw.lib_deps} test_filter= embedded/test_max30100 +[env:test_UnitHEART_AtomS3R] +extends=AtomS3R, option_release, arduino_latest +lib_deps = ${AtomS3R.lib_deps} + ${test_fw.lib_deps} +test_filter= embedded/test_max30100 + [env:test_UnitHEART_NanoC6] extends=NanoC6, option_release, arduino_latest lib_deps = ${NanoC6.lib_deps} @@ -220,12 +251,24 @@ lib_deps = ${StickCPlus.lib_deps} ${test_fw.lib_deps} test_filter= embedded/test_max30100 +[env:test_UnitHEART_StickCPlus2] +extends=StickCPlus2, option_release, arduino_latest +lib_deps = ${StickCPlus2.lib_deps} + ${test_fw.lib_deps} +test_filter= embedded/test_max30100 + [env:test_UnitHEART_Paper] extends=Paper, option_release, arduino_latest lib_deps = ${Paper.lib_deps} ${test_fw.lib_deps} test_filter= embedded/test_max30100 +[env:test_UnitHEART_CoreInk] +extends=CoreInk, option_release, arduino_latest +lib_deps = ${CoreInk.lib_deps} + ${test_fw.lib_deps} +test_filter= embedded/test_max30100 + ; -------------------------------- ;Examples by M5UnitUnified ; -------------------------------- @@ -262,10 +305,18 @@ build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial extends=StampS3, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> +[env:PlotToSerial_AtomMatrix_Arduino_latest] +extends=AtomMatrix, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> + [env:PlotToSerial_AtomS3_Arduino_latest] extends=AtomS3, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> +[env:PlotToSerial_AtomS3R_Arduino_latest] +extends=AtomS3R, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> + [env:PlotToSerial_Dial_Arduino_latest] extends=Dial, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> @@ -278,10 +329,18 @@ build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial extends=StickCPlus, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> +[env:PlotToSerial_StickCPlus2_Arduino_latest] +extends=StickCPlus2, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> + [env:PlotToSerial_Paper_Arduino_latest] extends=Paper, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> +[env:PlotToSerial_CoreInk_Arduino_latest] +extends=CoreInk, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> + [env:PlotToSerial_Fire_Arduino_latest] extends=Fire, option_release, arduino_latest build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/PlotToSerial> diff --git a/test/embedded/test_max30100/max30100_test.cpp b/test/embedded/test_max30100/max30100_test.cpp index d2a33ee..d2cf28a 100644 --- a/test/embedded/test_max30100/max30100_test.cpp +++ b/test/embedded/test_max30100/max30100_test.cpp @@ -50,7 +50,7 @@ INSTANTIATE_TEST_SUITE_P(ParamValues, TestMAX30100, ::testing::Values(false)); namespace { -bool is_allowed_settings(const Mode mode, const Sample rate, const LedPulseWidth pw) +bool is_allowed_settings(const Mode mode, const Sampling rate, const LedPulseWidth pw) { constexpr uint8_t spo2_table[] = { // LSB:200 MSB:1600 @@ -69,9 +69,9 @@ constexpr Mode mode_table[] = { Mode::HROnly, }; -constexpr Sample sr_table[] = { - Sample::Rate50, Sample::Rate100, Sample::Rate167, Sample::Rate200, - Sample::Rate400, Sample::Rate600, Sample::Rate800, Sample::Rate1000, +constexpr Sampling sr_table[] = { + Sampling::Rate50, Sampling::Rate100, Sampling::Rate167, Sampling::Rate200, + Sampling::Rate400, Sampling::Rate600, Sampling::Rate800, Sampling::Rate1000, }; constexpr LedPulseWidth pw_table[] = { @@ -144,11 +144,11 @@ TEST_P(TestMAX30100, Configration) SpO2Configuration sc{}; EXPECT_TRUE(unit->readSpO2Configuration(sc)); - sc.sampleRate(rate); + sc.samplingRate(rate); sc.ledPulseWidth(pw); if (is_allowed_settings(Mode::SPO2, rate, pw)) { EXPECT_TRUE(unit->writeSpO2Configuration(sc)); - EXPECT_TRUE(unit->writeSampleRate(rate)); + EXPECT_TRUE(unit->writeSamplingRate(rate)); EXPECT_TRUE(unit->writeLedPulseWidth(pw)); } else { EXPECT_FALSE(unit->writeSpO2Configuration(sc)); @@ -165,11 +165,11 @@ TEST_P(TestMAX30100, Configration) SpO2Configuration sc{}; EXPECT_TRUE(unit->readSpO2Configuration(sc)); - sc.sampleRate(rate); + sc.samplingRate(rate); sc.ledPulseWidth(pw); if (is_allowed_settings(Mode::HROnly, rate, pw)) { EXPECT_TRUE(unit->writeSpO2Configuration(sc)); - EXPECT_TRUE(unit->writeSampleRate(rate)); + EXPECT_TRUE(unit->writeSamplingRate(rate)); EXPECT_TRUE(unit->writeLedPulseWidth(pw)); } else { EXPECT_FALSE(unit->writeSpO2Configuration(sc)); @@ -248,7 +248,7 @@ TEST_P(TestMAX30100, Temperature) EXPECT_TRUE(unit->writeMode(Mode::SPO2)); EXPECT_TRUE(unit->writePowerSaveDisable()); SpO2Configuration sc{}; - sc.sampleRate(Sample::Rate100); + sc.samplingRate(Sampling::Rate100); sc.ledPulseWidth(LedPulseWidth::PW1600); sc.highResolution(true); EXPECT_TRUE(unit->writeSpO2Configuration(sc)); @@ -276,7 +276,7 @@ TEST_P(TestMAX30100, Reset) EXPECT_TRUE(unit->writePowerSaveEnable()); SpO2Configuration sc{}; - sc.sampleRate(Sample::Rate100); + sc.samplingRate(Sampling::Rate100); sc.ledPulseWidth(LedPulseWidth::PW1600); sc.highResolution(true); EXPECT_TRUE(unit->writeSpO2Configuration(sc)); @@ -317,7 +317,7 @@ TEST_P(TestMAX30100, Periodic) EXPECT_TRUE(unit->stopPeriodicMeasurement()); EXPECT_FALSE(unit->inPeriodic()); - EXPECT_TRUE(unit->startPeriodicMeasurement(Mode::SPO2, Sample::Rate100, LedPulseWidth::PW1600, + EXPECT_TRUE(unit->startPeriodicMeasurement(Mode::SPO2, Sampling::Rate100, LedPulseWidth::PW1600, CurrentControl::mA7_6, true, CurrentControl::mA7_6)); EXPECT_TRUE(unit->inPeriodic()); @@ -343,7 +343,7 @@ TEST_P(TestMAX30100, Periodic) unit->discard(); } - m5::utility::delay(100); // Sample about 10 times (not overflow) + m5::utility::delay(100); // Sampling about 10 times (not overflow) unit->update(); EXPECT_TRUE(unit->updated()); @@ -365,7 +365,7 @@ TEST_P(TestMAX30100, Periodic) EXPECT_FALSE(unit->full()); EXPECT_TRUE(unit->empty()); - m5::utility::delay(200); // Sample about 20 times (overflow!) + m5::utility::delay(200); // Sampling about 20 times (overflow!) unit->update(); EXPECT_TRUE(unit->updated()); From 03e91f10ba9b0cbef1510ebe24b1c37df2270c88 Mon Sep 17 00:00:00 2001 From: GOB Date: Fri, 25 Oct 2024 16:01:57 +0900 Subject: [PATCH 10/10] Raise version --- library.json | 7 +++---- library.properties | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/library.json b/library.json index a657a43..27cd5d2 100644 --- a/library.json +++ b/library.json @@ -13,7 +13,7 @@ "dependencies": { "M5UnitUnified": "https://github.com/m5stack/M5UnitUnified.git" }, - "version": "0.0.1", + "version": "0.0.2", "frameworks": [ "arduino" ], @@ -23,9 +23,8 @@ "headers": "M5UnitUnifiedHEART.h", "license": "MIT", "export": { - "exclude": - [ + "exclude": [ "docs/html" ] } -} +} \ No newline at end of file diff --git a/library.properties b/library.properties index 85863cd..36d2798 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5Unit-HEART -version=0.0.1 +version=0.0.2 author=M5Stack maintainer=M5Stack sentence=Library for M5Stack UNIT HEART using M5UnitUnified