101 lines
3.2 KiB
C++
101 lines
3.2 KiB
C++
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
#include <math.h>
|
|
|
|
#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();
|