/* * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD * * SPDX-License-Identifier: MIT */ /*! @file unit_BME688.hpp @brief BME688 Unit for M5UnitUnified */ #ifndef M5_UNIT_ENV_UNIT_BME688_HPP #define M5_UNIT_ENV_UNIT_BME688_HPP #include #include #if defined(ARDUINO) #include #else #include #endif #if defined(CONFIG_IDF_TARGET_ESP32C6) #pragma message "Not using bsec2" #else #pragma message "Using bsec2" #define UNIT_BME688_USING_BSEC2 #if defined(ARDUINO) #include #else #include #endif #endif #include #include #include namespace m5 { namespace unit { namespace bme688 { /*! @enum Mode @brief Operation mode same as BME68X_xxx_MODE */ enum class Mode : uint8_t { Sleep, //!< No measurements are performed Forced, //!< Single TPHG cycle is performed Parallel, //!< Multiple TPHG cycles are performed Sequential, //!< Sequential mode is similar as forced mode, but it provides //!< temperature, pressure, humidity one by one }; ///@name Aliases for bme68x structures ///@{ /*! @typedef bme68xData @brief Raw data */ using bme68xData = struct bme68x_data; /*! @typedef bme68xDev @brief bme68x device */ using bme68xDev = struct bme68x_dev; /*! @typedef bme68xConf @brief Setting for temperature, pressure, humidity... */ using bme68xConf = struct bme68x_conf; /*! @struct bme68xHeatrConf @brief Setting for gas heater @note Always valid pointers in derivation */ struct bme68xHeatrConf : bme68x_heatr_conf { uint16_t temp_prof[10]{}; uint16_t dur_prof[10]{}; bme68xHeatrConf() : bme68x_heatr_conf() { heatr_temp_prof = temp_prof; heatr_dur_prof = dur_prof; } }; /*! @typedef bme68xCalibration @brief Calibration parameters */ using bme68xCalibration = struct bme68x_calib_data; ///@} /*! @enum Oversamping @brief Sampling setting */ enum class Oversampling : uint8_t { None, //!< Skipped x1, //!< x1 x2, //!< x2 x4, //!< x4 x8, //!< x8 x16, //!< x16 }; /*! @enum Filter @brief IIR Filter setting */ enum class Filter : uint8_t { None, Coeff_1, Coeff_3, Coeff_7, Coeff_15, Coeff_31, Coeff_63, Coeff_127, }; /*! @enum ODR @brief bme68xConf::odr settings (standbytime Unit:ms) */ enum class ODR : uint8_t { MS_0_59, //< 0.59 ms MS_62_5, //< 62.5 ms MS_125, //< 125 ms MS_250, //!< 250 ms MS_500, //!< 500 ms MS_1000, //!< 1000 ms MS_10, //!< 10 ms MS_20, //!< 20 ms None, //!< No standbytime }; /*! @struct GasWait @brief GasSensor heater-on time @note Forced mode and Parallel mode are interpreted differently */ struct GasWait { GasWait() : value{0} { } /*! @enum Factor @brief Multiplier in Forced mode */ enum class Factor { x1, x4, x16, x64 }; ///@name Getter ///@{ inline uint8_t step() const { return value & 0x3F; } inline Factor factor() const { return static_cast((value >> 6) & 0x03); } ///@} ///@name Setter ///@{ inline void step(const uint8_t s) { value = (value & ~0x3F) | (s & 0x3F); } inline void factor(const Factor f) { value = (value & ~(0x03 << 6)) | (m5::stl::to_underlying(f) << 6); } ///@} //! @brief Conversion from duration to register value for Force/Sequencial //! mode static uint8_t from(const uint16_t duration) { uint8_t f{}; uint16_t d{duration}; while (d > 0x3F) { d >>= 2; ++f; } return (f <= 0x03) ? ((uint8_t)d | (f << 6)) : 0xFF; } //! @brief Conversion from register value to duration for Force/Sequencial //! mode static uint16_t to(const uint8_t v) { constexpr uint16_t tbl[] = {1, 4, 16, 64}; return (v & 0x3F) * tbl[(v >> 6) & 0x03]; } uint8_t value{}; //!< Use the value as it is in parallel mode }; #if defined(UNIT_BME688_USING_BSEC2) namespace bsec2 { /*! @enum SampleRate @brief Sample rate for BSEC2 */ enum class SampleRate : uint8_t { Disabled, //!< Sample rate of a disabled sensor LowPower, //!< Sample rate in case of Low Power Mode (0.33Hz) interval 3 sec. UltraLowPower, //!< Sample rate in case of Ultra Low Power Mode (3.3 mHz) interval 300 sec. UltraLowPowerMeasurementOnDemand, //!< Input value used to trigger an extra measurment (ULP plus) (0.33Hz //!< [T,p,h] 3.3mHz [IAQ]) Scan, //!< Sample rate in case of scan mode (1/10.8 s) Continuous, //!< Sample rate in case of Continuous Mode (1Hz) interval 1 sec. }; ///@cond template void is_bsec_virtual_sensor_t() { static_assert(std::is_same::value, "Argument must be of type bsec_virtual_sensor_t"); } ///@endcond //! @brief Conversion from BSEC2 subscription array to bits inline uint32_t virtual_sensor_array_to_bits(const bsec_virtual_sensor_t* ss, const size_t len) { uint32_t ret{}; for (size_t i = 0; i < len; ++i) { ret |= ((uint32_t)1U) << ss[i]; } return ret; } /*! @brief Make subscribe bits from bsec_virtual_sensor_t */ template uint32_t subscribe_to_bits(Args... args) { // In a C++17 or later environment, it can be written like this... // static_assert(std::conjunction...>::value, // "All arguments must be of type bsec_virtual_sensor_t"); int discard[] = {(is_bsec_virtual_sensor_t(), 0)...}; (void)discard; bsec_virtual_sensor_t tmp[] = {args...}; constexpr size_t n = sizeof...(args); return virtual_sensor_array_to_bits(tmp, n); } } // namespace bsec2 #endif /*! @struct Data @brief Measurement data group */ struct Data { bme688::bme68xData raw{}; #if defined(UNIT_BME688_USING_BSEC2) bsecOutputs raw_outputs{}; float get(const bsec_virtual_sensor_t vs) const; inline float iaq() const { return get(BSEC_OUTPUT_IAQ); } inline float static_iaq() const { return get(BSEC_OUTPUT_STATIC_IAQ); } inline float co2() const { return get(BSEC_OUTPUT_CO2_EQUIVALENT); } inline float voc() const { return get(BSEC_OUTPUT_BREATH_VOC_EQUIVALENT); } inline float temperature() const { return get(BSEC_OUTPUT_RAW_TEMPERATURE); } inline float pressure() const { return get(BSEC_OUTPUT_RAW_PRESSURE); } inline float humidity() const { return get(BSEC_OUTPUT_RAW_HUMIDITY); } inline float gas() const { return get(BSEC_OUTPUT_RAW_GAS); } inline bool gas_stabilization() const { return get(BSEC_OUTPUT_STABILIZATION_STATUS) == 1.0f; } inline bool gas_run_in_status() const { return get(BSEC_OUTPUT_RUN_IN_STATUS) == 1.0f; } inline float heat_compensated_temperature() const { return get(BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE); } inline float heat_compensated_humidity() const { return get(BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY); } inline float gas_percentage() const { return get(BSEC_OUTPUT_GAS_PERCENTAGE); } inline float gas_estimate_1() const { return get(BSEC_OUTPUT_GAS_ESTIMATE_1); } inline float gas_estimate_2() const { return get(BSEC_OUTPUT_GAS_ESTIMATE_2); } inline float gas_estimate_3() const { return get(BSEC_OUTPUT_GAS_ESTIMATE_3); } inline float gas_estimate_4() const { return get(BSEC_OUTPUT_GAS_ESTIMATE_4); } inline uint32_t gas_index() const { return get(BSEC_OUTPUT_RAW_GAS_INDEX); } inline float regression_estimate_1() const { return get(BSEC_OUTPUT_REGRESSION_ESTIMATE_1); } inline float regression_estimate_2() const { return get(BSEC_OUTPUT_REGRESSION_ESTIMATE_2); } inline float regression_estimate_3() const { return get(BSEC_OUTPUT_REGRESSION_ESTIMATE_3); } inline float regression_estimate_4() const { return get(BSEC_OUTPUT_REGRESSION_ESTIMATE_4); } #endif inline float raw_temperature() const { return raw.temperature; } inline float raw_pressure() const { return raw.pressure; } inline float raw_humidity() const { return raw.humidity; } inline float raw_gas() const { return raw.gas_resistance; } }; } // namespace bme688 /*! @class UnitBME688 @brief BME688 unit @note Using config/bme688/bme688_sel_33v_3s_4d/bsec_selectivity.txt for default configuration @note If other settings are used, call bsec2SetConfig */ class UnitBME688 : public Component, public PeriodicMeasurementAdapter { M5_UNIT_COMPONENT_HPP_BUILDER(UnitBME688, 0x77); public: /*! @struct config_t @brief Settings for begin */ struct config_t { //! Start periodic measurement on begin? bool start_periodic{true}; //! ambient temperature int8_t ambient_temperature{25}; #if defined(UNIT_BME688_USING_BSEC2) || defined(DOXYGEN_PROCESS) ///@name Exclude NanoC6 ///@{ /*! @brief Subscribe BSEC2 sensors bits if start on begin */ uint32_t subscribe_bits{1U << BSEC_OUTPUT_IAQ | 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}; /*! @brief Sampling rate for BSEC2 if start on begin @warning Depending on the value specified for the sample rate, appropriate configuration settings may be required in advance. */ bme688::bsec2::SampleRate sample_rate{bme688::bsec2::SampleRate::LowPower}; #endif #if !defined(UNIT_BME688_USING_BSEC2) || defined(DOXYGEN_PROCESS) ///@name Only Nano6 ///@{ /*! @brief Measurement mode if start on begin */ bme688::Mode mode{bme688::Mode::Forced}; //! Temperature oversampling if start on begin bme688::Oversampling oversampling_temperature{bme688::Oversampling::x2}; //! Pressure oversampling if start on begin bme688::Oversampling oversampling_pressure{bme688::Oversampling::x1}; //! Humidity oversampling if start on begin bme688::Oversampling oversampling_humidity{bme688::Oversampling::x16}; //! Filter coefficient if start on begin bme688::Filter filter{bme688::Filter::None}; //! Standby time between sequential mode measurement profiles if start on begin bme688::ODR odr{bme688::ODR::None}; //! Enable gas measurement if start on begin bool heater_enable{true}; //! The heater temperature for forced mode degree Celsius if start on begin uint16_t heater_temperature{300}; //! The heating duration for forced mode in milliseconds if start on begin uint16_t heater_duration{100}; ///@} #endif }; ///@name Configuration for begin ///@{ /*! @brief Gets the configration */ inline config_t config() { return _cfg; } //! @brief Set the configration inline void config(const config_t& cfg) { _cfg = cfg; } ///@} explicit UnitBME688(const uint8_t addr = DEFAULT_ADDRESS); virtual ~UnitBME688() { } virtual bool begin() override; virtual void update(const bool force = false) override; ///@name Properties ///@{ //! @brief Current mode inline bme688::Mode mode() const { return _mode; } //!@brief Gets the Calibration inline const bme688::bme68xCalibration& calibration() const { return _dev.calib; } //! @brief Gets the TPH setting inline const bme688::bme68xConf& tphSetting() const { return _tphConf; } //! @brief Gets the heater setiing inline const bme688::bme68xHeatrConf& heaterSetting() const { return _heaterConf; } //! @brief Gets the ambient temperature inline int8_t ambientTemperature() const { return _dev.amb_temp; } ///@} ///@name Measurement data by periodic ///@{ #if defined(UNIT_BME688_USING_BSEC2) /*! @brief Oldest measured IAQ @warning Exclude NanoC6 */ inline float iaq() const { return !empty() ? oldest().iaq() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured temperature (Celsius) inline float temperature() const { return !empty() ? oldest().temperature() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured pressure (Pa) inline float pressure() const { return !empty() ? oldest().pressure() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured humidity (%) inline float humidity() const { return !empty() ? oldest().humidity() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured gas (Ohm) inline float gas() const { return !empty() ? oldest().gas() : std::numeric_limits::quiet_NaN(); } #else //! @brief Oldest measured temperature (Celsius) inline float temperature() const { return !empty() ? oldest().raw_temperature() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured pressure (Pa) inline float pressure() const { return !empty() ? oldest().raw_pressure() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured humidity (%) inline float humidity() const { return !empty() ? oldest().raw_humidity() : std::numeric_limits::quiet_NaN(); } //! @brief Oldest measured gas (Ohm) inline float gas() const { return !empty() ? oldest().raw_gas() : std::numeric_limits::quiet_NaN(); } #endif ///@} #if 0 /*! @brief Number of valid latest raw data @return between 0 and 3 @note 0 or 1 in Forced mode */ inline uint8_t numberOfRawData() const { return _num_of_data; } /*! @brief Obtaining the specified latest raw data pointer @param idx What number of the data @retval != nullptr Data pointer @retval == nullptr Failed @warning If it is not a valid range, nullptr is returned */ inline const bme688::bme68xData* data(const uint8_t idx) { return (idx < _num_of_data) ? &_raw_data[idx] : nullptr; } #endif //! @brief Sets the ambient temperature inline void setAambientTemperature(const int8_t temp) { _dev.amb_temp = temp; } /*! @brief Read calibration @param[out] c output value @return True if successful */ bool readCalibration(bme688::bme68xCalibration& c); /*! @brief write calibration @param c Calibration parameter @return True if successful */ bool writeCalibration(const bme688::bme68xCalibration& c); /*! @brief Calculation of measurement intervals without heater @return interval time (Unit: us) */ uint32_t calculateMeasurementInterval(const bme688::Mode mode, const bme688::bme68xConf& s); /*! @brief Read unique ID @param[out] id output value @return True if successful */ bool readUniqueID(uint32_t& id); /*! @brief Software reset @return True if successful */ bool softReset(); /*! @brief Self-test @return True if successful */ bool selfTest(); /*! @brief Write operation mode @param m Mode @return True if successful */ bool writeMode(const bme688::Mode m); /*! @brief Read operation mode @param[out] m Mode @return True if successful */ bool readMode(bme688::Mode& m); ///@name TPH(Temperature,Pressure,Humidity) ///@{ /*! @brief Read TPH setting @param[out] s output value @return True if successful */ bool readTPHSetting(bme688::bme68xConf& s); /*! @brief Read temperature oversampling @param[out] os output value @return True if successful */ bool readOversamplingTemperature(bme688::Oversampling& os); /*! @brief Read pressure oversampling @param[out] os output value @return True if successful */ bool readOversamplingPressure(bme688::Oversampling& os); /*! @brief Read IIRFilter @param[out] f output value @return True if successful */ bool readIIRFilter(bme688::Filter& f); /*! @brief Read humidity oversampling @param[out] os output value @return True if successful */ bool readOversamplingHumidity(bme688::Oversampling& os); /*! @brief Write TPH setting @param s Setting @return True if successful */ bool writeTPHSetting(const bme688::bme68xConf& s); /*! @brief Wite oversamplings @param t oversampling for temperature @param p oversampling for pressure @param h oversampling for humidity */ bool writeOversampling(const bme688::Oversampling t, const bme688::Oversampling p, const bme688::Oversampling h); /*! @brief Write temperature oversampling @param os enum value @return True if successful */ bool writeOversamplingTemperature(const bme688::Oversampling os); /*! @brief Write pressure oversampling @param os enum value @return True if successful */ bool writeOversamplingPressure(const bme688::Oversampling os); /*! @brief Write humidity oversampling @param os enum value @return True if successful */ bool writeOversamplingHumidity(const bme688::Oversampling os); /*! @brief Write IIRFilter @param[out] f enum value @return True if successful */ bool writeIIRFilter(const bme688::Filter f); ///@} ///@name Heater ///@{ /*! @brief Read heater setting @param hs Setting @return True if successful @warning Only heatr_dur_prof and heatr_temp_prof can be obtained */ bool readHeaterSetting(bme688::bme68xHeatrConf& hs); /*! @brief Write heater setting @param mode Expected operation mode of the sensor @param hs Setting @return True if successful */ bool writeHeaterSetting(const bme688::Mode mode, const bme688::bme68xHeatrConf& hs); ///@} ///@name Periodic measurement ///@{ /*! @brief Start periodic measurement without BSEC2 @param m Mode for measurement @return True if successful @pre Calibration,TPH and heater must already be set up @warning Measurement intervals are not constant in Parallel mode */ inline bool startPeriodicMeasurement(const bme688::Mode m) { return PeriodicMeasurementAdapter::startPeriodicMeasurement(m); } #if defined(UNIT_BME688_USING_BSEC2) || defined(DOXYGEN_PROCESS) /*! @brief Start periodic measurement using BSEC2 @param subscribe_bits Measurement type bits @return True if successful @warning Not available for NanoC6 */ inline bool startPeriodicMeasurement(const uint32_t subscribe_bits, const bme688::bsec2::SampleRate sr = bme688::bsec2::SampleRate::LowPower) { return PeriodicMeasurementAdapter::startPeriodicMeasurement(subscribe_bits, sr); } /*! @brief Start periodic measurement using BSEC2 @param ss Array of requested virtual sensor (output) configurations for the library @param len Number of array elements @return True if successful @warning Not available for NanoC6 */ inline bool startPeriodicMeasurement(const bsec_virtual_sensor_t* ss, const size_t len, const bme688::bsec2::SampleRate sr = bme688::bsec2::SampleRate::LowPower) { return ss ? startPeriodicMeasurement(bme688::bsec2::virtual_sensor_array_to_bits(ss, len), sr) : false; } #endif /*! @brief Stop periodic measurement @return True if successful */ inline bool stopPeriodicMeasurement() { return PeriodicMeasurementAdapter::stopPeriodicMeasurement(); } ///@} ///@name Single shot measurement ///@{ /*! @brief Take a single measurement @param[out] data output value @return True if successful @pre Calibration,TPH and heater must already be set up @note Measure once by Force mode @note Blocked until it can be measured. */ bool measureSingleShot(bme688::bme68xData& data); ///@} #if defined(UNIT_BME688_USING_BSEC2) || defined(DOXYGEN_PROCESS) ///@warning Not available for NanoC6 ///@name Bosch BSEC2 wrapper ///@{ /*! @brief Gets the temperature offset(Celsius) */ float bsec2GetTemperatureOffset() const { return _temperatureOffset; } /*! @brief Set the temperature offset(Celsius) @param offset offset value */ void bsec2SetTemperatureOffset(const float offset) { _temperatureOffset = offset; } /*! @brief Gets the BSEC2 library version @return reference of the version structure @warning Call after begin */ const bsec_version_t& bsec2Version() const { return _bsec2_version; } /*! @brief Update algorithm configuration parameters Update bsec2 configuration settings @param cfg Settings serialized to a binary blob @param sz size of cfg @return True if successful @note See also BSEC2 src/config/bme688 for configuration data */ bool bsec2SetConfig(const uint8_t* cfg, const size_t sz = BSEC_MAX_PROPERTY_BLOB_SIZE); /*! @brief Retrieve the current library configuration @param[out] cfg Buffer to hold the serialized config blob @param[out] actualSize Actual size of the returned serialized configuration blob @return True if successful @warning cfg size must be greater than or equal to BSEC_MAX_PROPERTY_BLOB_SIZE */ bool bsec2GetConfig(uint8_t* cfg, uint32_t& actualSize); /*! @brief Restore the internal state @param state pointer of the state array @return True if successful */ bool bsec2SetState(const uint8_t* state); /*! @brief Retrieve the current internal library state @param[out] state Buffer to hold the serialized state blob @param[out] actualSize Actual size of the returned serialized blob @return True if successful @warning cfg size must be greater than or equal to BSEC_MAX_STATE_BLOB_SIZE */ bool bsec2GetState(uint8_t* state, uint32_t& actualSize); /*! @brief Subscribe to library virtual sensors outputs @param sensorBits Requested virtual sensor (output) configurations for the library @param sr Sample rate @return True if successful @warning Depending on the value specified for the sample rate, appropriate configuration settings may be required in advance. */ bool bsec2UpdateSubscription(const uint32_t sensorBits, const bme688::bsec2::SampleRate sr); /*! @brief Subscribe to library virtual sensors outputs @param ss Array of requested virtual sensor (output) configurations for the library @param len Number of array elements @param sr Sample rate @return True if successful @warning Depending on the value specified for the sample rate, appropriate configuration settings may be required in advance. */ inline bool bsec2UpdateSubscription(const bsec_virtual_sensor_t* ss, const size_t len, const bme688::bsec2::SampleRate sr) { return bsec2UpdateSubscription(bme688::bsec2::virtual_sensor_array_to_bits(ss, len), sr); } /*! @brief is virtual sensor Subscribed? @param id virtual sensor (output) @return True if subscribed */ inline bool bsec2IsSubscribed(const bsec_virtual_sensor_t id) { return _bsec2_subscription & (1U << id); } /*! @brief Gets the subscription bits @return Subscribed sensor id bits @note If BSEC_OUTPUT_IAQ is subscribed, then bit 2 (means 1U << BSEC_OUTPUT_IAQ) is 1 */ uint32_t bsec2Subscription() const { return _bsec2_subscription; } /*! @brief Subscribe virtual sensor @param id virtual sensor (output) @return True if successful @note SampleRate uses the value that is currently set or has been set in the past */ bool bsec2Subscribe(const bsec_virtual_sensor_t id); /*! @brief Unsubscribe virtual sensor @param id virtual sensor (output) @return True if successful */ bool bsec2Unsubscribe(const bsec_virtual_sensor_t id); /*! @brief Unsubacribe currentt all sensors @return True if successful */ bool bsec2UnsubscribeAll(); ///@} #endif protected: static int8_t read_function(uint8_t reg_addr, uint8_t* reg_data, uint32_t length, void* intf_ptr); static int8_t write_function(uint8_t reg_addr, const uint8_t* reg_data, uint32_t length, void* intf_ptr); bool start_periodic_measurement(const bme688::Mode m); bool stop_periodic_measurement(); #if defined(UNIT_BME688_USING_BSEC2) bool start_periodic_measurement(const uint32_t subscribe_bits, const bme688::bsec2::SampleRate sr); #endif bool write_mode_forced(); bool write_mode_parallel(); bool fetch_data(); void update_bme688(const bool force); bool read_measurement(); #if defined(UNIT_BME688_USING_BSEC2) bool process_data(bsecOutputs& outouts, const int64_t ns, const bme688::bme68xData& data); void update_bsec2(const bool force); #endif inline virtual bool in_periodic() const override { return _periodic || (_bsec2_subscription != 0); } M5_UNIT_COMPONENT_PERIODIC_MEASUREMENT_ADAPTER_HPP_BUILDER(UnitBME688, bme688::Data); protected: bme688::Mode _mode{bme688::Mode::Sleep}; // bme68x bme688::bme68xData _raw_data[3]{}; // latest data uint8_t _num_of_data{}; bme688::bme68xDev _dev{}; bme688::bme68xConf _tphConf{}; bme688::bme68xHeatrConf _heaterConf{}; // BSEC2 uint32_t _bsec2_subscription{}; // Enabled virtual sensor bit #if defined(UNIT_BME688_USING_BSEC2) bsec_version_t _bsec2_version{}; std::unique_ptr _bsec2_work{}; bsec_bme_settings_t _bsec2_settings{}; bme688::Mode _bsec2_mode{}; bme688::bsec2::SampleRate _bsec2_sr{}; bsecOutputs _outputs{}; float _temperatureOffset{}; #endif std::unique_ptr> _data{}; bool _waiting{}; types::elapsed_time_t _can_measure_time{}; config_t _cfg{}; }; ///@cond 0 namespace bme688 { namespace command { constexpr uint8_t CHIP_ID{0xD0}; constexpr uint8_t RESET{0xE0}; constexpr uint8_t VARIANT_ID{0xF0}; constexpr uint8_t IDAC_HEATER_0{0x50}; // ...9 constexpr uint8_t RES_HEAT_0{0x5A}; // ...9 constexpr uint8_t GAS_WAIT_0{0x64}; // ...9 constexpr uint8_t GAS_WAIT_SHARED{0x6E}; constexpr uint8_t CTRL_GAS_0{0x70}; constexpr uint8_t CTRL_GAS_1{0x71}; constexpr uint8_t CTRL_HUMIDITY{0x72}; constexpr uint8_t CTRL_MEASUREMENT{0x74}; constexpr uint8_t CONFIG{0x75}; constexpr uint8_t MEASUREMENT_STATUS_0{0x1D}; constexpr uint8_t MEASUREMENT_STATUS_1{0x2E}; constexpr uint8_t MEASUREMENT_STATUS_2{0x3F}; constexpr uint8_t MEASUREMENT_GROUP_INDEX_0{0x1F}; constexpr uint8_t MEASUREMENT_GROUP_INDEX_1{0x30}; constexpr uint8_t MEASUREMENT_GROUP_INDEX_2{0x41}; constexpr uint8_t UNIQUE_ID{0x83}; // calibration constexpr uint8_t CALIBRATION_GROUP_0{0x8A}; constexpr uint8_t CALIBRATION_GROUP_1{0xE1}; constexpr uint8_t CALIBRATION_GROUP_2{0x00}; constexpr uint8_t CALIBRATION_TEMPERATURE_1_LOW{0xE9}; constexpr uint8_t CALIBRATION_TEMPERATURE_2_LOW{0x8A}; constexpr uint8_t CALIBRATION_TEMPERATURE_3{0x8C}; constexpr uint8_t CALIBRATION_PRESSURE_1_LOW{0x8E}; constexpr uint8_t CALIBRATION_PRESSURE_2_LOW{0x90}; constexpr uint8_t CALIBRATION_PRESSURE_3{0x92}; constexpr uint8_t CALIBRATION_PRESSURE_4_LOW{0x94}; constexpr uint8_t CALIBRATION_PRESSURE_5_LOW{0x96}; constexpr uint8_t CALIBRATION_PRESSURE_6{0x99}; constexpr uint8_t CALIBRATION_PRESSURE_7{0x98}; constexpr uint8_t CALIBRATION_PRESSURE_8_LOW{0x9C}; constexpr uint8_t CALIBRATION_PRESSURE_9_LOW{0x9E}; constexpr uint8_t CALIBRATION_PRESSURE_10{0xA0}; constexpr uint8_t CALIBRATION_HUMIDITY_12{0xE2}; constexpr uint8_t CALIBRATION_HUMIDITY_1_HIGH{0xE3}; constexpr uint8_t CALIBRATION_HUMIDITY_2_HIGH{0xE1}; constexpr uint8_t CALIBRATION_HUMIDITY_3{0xE4}; constexpr uint8_t CALIBRATION_HUMIDITY_4{0xE5}; constexpr uint8_t CALIBRATION_HUMIDITY_5{0xE6}; constexpr uint8_t CALIBRATION_HUMIDITY_6{0xE7}; constexpr uint8_t CALIBRATION_HUMIDITY_7{0xE8}; constexpr uint8_t CALIBRATION_GAS_1{0xED}; constexpr uint8_t CALIBRATION_GAS_2_LOW{0xEB}; constexpr uint8_t CALIBRATION_GAS_3{0xEE}; constexpr uint8_t CALIBRATION_RES_HEAT_RANGE{0x02}; // [5:4] constexpr uint8_t CALIBRATION_RES_HEAT_VAL{0x00}; } // namespace command } // namespace bme688 ///@endcond } // namespace unit } // namespace m5 #endif