#pragma once #include #include #include "config.h" #include "ms5611_crc.h" // // One validated MS5611 measurement channel. // // The class owns everything that is identical for both sensors - reset and // PROM/CRC handshake, per-poll validation, error accounting and the 1 second // error LED pulse. Only the five driver calls at the bottom are virtual, and // they are implemented once for the I2C part and once for the SPI part. // enum class BaroStatus : uint8_t { NotInitialised = 0, Ok, InitFailed, // reset/handshake did not complete PromCrcError, // factory calibration failed its CRC-4 or is implausible ReadError, // the driver reported a bus/ADC failure OutOfRange, // values outside the MS5611 operating envelope Stale, // sensor answers but has stopped producing new samples }; // Short, log-friendly name for a status - never returns NULL. const char *baroStatusName(BaroStatus status); class BaroChannel { public: BaroChannel(const char *name, uint8_t ledPin) : _name(name), _ledPin(ledPin) {} // Configures the LED pin and makes the first initialisation attempt. void begin(uint32_t now); // One acquisition cycle: read, validate, update status and LED. // Blocks for roughly 2x the ADC conversion time of the configured OSR. void poll(uint32_t now); // Releases the error LED once its hold time has elapsed. Cheap, call often. void updateLed(uint32_t now); const char *name() const { return _name; } BaroStatus status() const { return _status; } bool isOk() const { return _status == BaroStatus::Ok; } float pressure() const { return _pressure; } // mbar float temperature() const { return _temperature; } // degrees C uint32_t errorCount() const { return _errorCount; } protected: // Not deleted through this type - keeps the vtable free of a destructor // slot and avoids dragging in operator delete. ~BaroChannel() = default; // Reset the part and apply the configured oversampling. virtual bool driverBegin() = 0; // Fill prom[0..7] with the factory calibration words. virtual void driverReadProm(uint16_t *prom) = 0; // True when the driver reported MS5611_READ_OK. virtual bool driverRead() = 0; virtual float driverPressure() = 0; virtual float driverTemperature() = 0; private: bool tryInit(uint32_t now); void fail(BaroStatus status, uint32_t now); const char *_name; uint8_t _ledPin; BaroStatus _status = BaroStatus::NotInitialised; bool _initialised = false; uint32_t _lastInitAttempt = 0; float _pressure = NAN; float _temperature = NAN; uint8_t _repeatCount = 0; uint8_t _errorStreak = 0; uint32_t _errorCount = 0; bool _ledOn = false; uint32_t _ledOffAt = 0; }; // // The two concrete channels are built in their own translation units on // purpose: MS5611.h and MS5611_SPI.h each define `enum osr_t` and their own // MS5611_READ_OK, so including both in one file does not compile. These // accessors hand out the instances without leaking either driver header. // BaroChannel &baroI2cChannel(); BaroChannel &baroSpiChannel();