Source code

/******************************************************************************
Walrus.cpp
Library for Walrus pressure and temperature sensor, made by Northern Widget LLC.
Based off of the TP-Downhole
Bobby Schulz @ Northern Widget LLC
5/9/2018
Hardware info located at:
https://github.com/NorthernWidget-Skunkworks/Project-Walrus

Distributed as-is; no warranty is given.
******************************************************************************/

#include <Wire.h> // Wire library is used for I2C
#include "Walrus_I2C.h"

Walrus::Walrus()
{
}

bool Walrus::begin(uint8_t Address_)
{
    //Page 0 gates: Schema 1, the name "Walrus", firmware patch >= WALRUS_FW_MIN_PATCH.
    return _dev.begin(Address_, "Walrus", WALRUS_FW_MIN_PATCH);
}

bool Walrus::updateMeasurements(uint8_t component)
{
    bool doMS = component & MS5803, doMCP = component & MCP9808;
    if(doMS) { _pressureReadings.reset(); _tempMS5803Readings.reset(); }
    if(doMCP) _tempExtReadings.reset();
    if(doMS && doMCP && _pressureCfg.n <= 1 && _temperatureCfg.n <= 1) {
        //One reading of everything: both chips in one trigger, one 10-byte read.
        _dev.resetBatch();
        uint8_t d[10];
        if(_dev.takeReading(ALL) && _dev.readData(NW_REG_DATA, d, 10)) {
            readMS5803(d);
            readMCP9808(d + 8);
        }
    }
    else {
        //Per chip group: N readings each, appended to the arrays; a chip that
        //reports absent (not answering / self-test failed) stops its batch.
        if(doMS) _dev.takeReadings(MS5803, _pressureCfg.n, [this] { return updatePressure(); });
        if(doMCP) _dev.takeReadings(MCP9808, _temperatureCfg.n, [this] { return updateTemperature(); });
    }
    summarise(component);
    bool ok = true;
    if(doMS) ok = ok && _pressureReadings.count() > 0;
    if(doMCP) ok = ok && _tempExtReadings.count() > 0;
    return ok;
}

bool Walrus::updatePressure()
{
    uint8_t d[6];
    if(!_dev.takeReading(MS5803) || !_dev.readData(PRES_REG, d, 6)) return false;
    return readMS5803(d);
}

bool Walrus::updateTemperature()
{
    uint8_t d[2];
    if(!_dev.takeReading(MCP9808) || !_dev.readData(TEMP_EXT, d, 2)) return false;
    return readMCP9808(d);
}

bool Walrus::readMS5803(uint8_t* d)
{
    if(_dev.faulted(0)) return false;           //MS5803: pressure int32 uBar, temperature int16 0.01 C
    int32_t p = (int32_t)((uint32_t)d[0] | ((uint32_t)d[1] << 8) | ((uint32_t)d[2] << 16) | ((uint32_t)d[3] << 24));
    _pressureReadings.append(p);
    _tempMS5803Readings.append((int16_t)(d[4] | (d[5] << 8)));
    return true;
}

bool Walrus::readMCP9808(uint8_t* d)
{
    if(_dev.faulted(1)) return false;           //MCP9808: external temperature int16 0.01 C
    _tempExtReadings.append((int16_t)(d[0] | (d[1] << 8)));
    return true;
}

void Walrus::summarise(uint8_t component)
{
    //Means over the readings taken, scaled from the register units; NW_ERROR when none.
    if(component & MS5803) {
        _pressure   = nwScaled(_pressureReadings.mean(),   1000.0);
        _tempMS5803 = nwScaled(_tempMS5803Readings.mean(), 100.0);
    }
    if(component & MCP9808) {
        _tempExt = nwScaled(_tempExtReadings.mean(), 100.0);
    }
}

uint16_t Walrus::setPressureReadings(uint16_t n)    { return _pressureCfg.set(n, WALRUS_PRESSURE_CAPACITY); }
uint16_t Walrus::setTemperatureReadings(uint16_t n) { return _temperatureCfg.set(n, WALRUS_TEMPERATURE_CAPACITY); }
void     Walrus::setPressureStats(bool enable)      { _pressureCfg.stats = enable; }
void     Walrus::setTemperatureStats(bool enable)   { _temperatureCfg.stats = enable; }
uint16_t Walrus::getPressureCount()               { return _pressureReadings.count(); }
uint16_t Walrus::getTemperatureCount()            { return _tempExtReadings.count(); }

//Statistics are computed from the arrays each call (NW_Readings), in the
//register units, then scaled: uBar -> mBar, 0.01 C -> C. NW_ERROR when empty.
float Walrus::getPressureMean()   { return nwScaled(_pressureReadings.mean(),   1000.0); }
float Walrus::getPressureStd()    { return nwScaled(_pressureReadings.std(),    1000.0); }
float Walrus::getPressureSterr()  { return nwScaled(_pressureReadings.sterr(),  1000.0); }
float Walrus::getPressureMedian() { return nwScaled(_pressureReadings.median(), 1000.0); }
float Walrus::getTemperatureMean(uint8_t Location)   { return nwScaled(Location == 0 ? _tempExtReadings.mean()   : _tempMS5803Readings.mean(),   100.0); }
float Walrus::getTemperatureStd(uint8_t Location)    { return nwScaled(Location == 0 ? _tempExtReadings.std()    : _tempMS5803Readings.std(),    100.0); }
float Walrus::getTemperatureSterr(uint8_t Location)  { return nwScaled(Location == 0 ? _tempExtReadings.sterr()  : _tempMS5803Readings.sterr(),  100.0); }
float Walrus::getTemperatureMedian(uint8_t Location) { return nwScaled(Location == 0 ? _tempExtReadings.median() : _tempMS5803Readings.median(), 100.0); }

float Walrus::getTemperature(uint8_t Location) //Returns temp in C from either subsensor
{
    return (Location == 0) ? _tempExt : _tempMS5803;
}

float Walrus::getTemperature() //By default get thermistor temp value
{
    return getTemperature(1);
}

float Walrus::getPressure()
{
    return _pressure;
}

bool Walrus::newData()  //Checks for updated/valid data
{
    return _dev.ready();
}

bool    Walrus::ready()            { return _dev.ready(); }
bool    Walrus::newReading()       { return _dev.newReading(); }
bool    Walrus::requestReading()   { return _dev.requestReading(0x03); }
bool    Walrus::faulted(uint8_t chip) { return _dev.faulted(chip); }
bool    Walrus::anyFault()         { return _dev.anyFault(); }
uint8_t Walrus::reportChip()        { return _dev.reportChip(); }
uint8_t Walrus::reportKind()        { return _dev.reportKind(); }
String  Walrus::beginFailure()     { return _dev.beginFailure(); }
uint8_t Walrus::getHardwareMajor() { return _dev.hardwareMajor(); }
uint8_t Walrus::getHardwareMinor() { return _dev.hardwareMinor(); }
uint8_t Walrus::getFirmwareVersion() { return _dev.firmwareVersion(); }

size_t Walrus::printReport(Print& out)
{
    //The chip names are Walrus's own (the spec's chip table); NW_Report prints the rest.
    static const char* const chips[] = {"MS5803", "MCP9808"};
    return _dev.report().print(out, chips, 2);
}

size_t Walrus::printStatus(Print& out, bool boot)
{
    static const char* const chips[] = {"MS5803", "MCP9808"};
    return _dev.printSnapshot(out, chips, 2, boot, WALRUS_LIBRARY_VERSION, WALRUS_LIBRARY_COMMIT);
}

bool    Walrus::reportIsFault()   { return _dev.report().isFault(); }
uint8_t Walrus::bootReportKind()  { return _dev.bootReport().kind(); }
void    Walrus::clearBootReport() { _dev.clearBootReport(); }

String Walrus::reportNote()
{
    //One word for a data-table note: the chip, then the kind ("MS5803NotAnswering").
    static const char* const chips[] = {"MS5803", "MCP9808"};
    return _dev.report().note(chips, 2);
}

String Walrus::getHeader()
{
    String h = "Pressure [mBar],"; //return header string
    if(_pressureCfg.columns()) h += "Pressure std [mBar],Pressure sterr [mBar],";
    h += "Temp DH [C],";
    if(_temperatureCfg.columns()) h += "Temp DH std [C],Temp DH sterr [C],";
    h += "Temp DHt [C],";
    if(_pressureCfg.columns()) h += "Temp DHt std [C],Temp DHt sterr [C],";
    return h;
}

String Walrus::getString()
{
    updateMeasurements();                           //NW_ERROR (-9999) where a reading failed
    String s = String(getPressure()) + ",";
    if(_pressureCfg.columns()) s += String(getPressureStd()) + "," + String(getPressureSterr()) + ",";
    s += String(getTemperature(0)) + ",";
    if(_temperatureCfg.columns()) s += String(getTemperatureStd(0)) + "," + String(getTemperatureSterr(0)) + ",";
    s += String(getTemperature(1)) + ",";
    if(_pressureCfg.columns()) s += String(getTemperatureStd(1)) + "," + String(getTemperatureSterr(1)) + ",";
    return s;
}

//The reading interface: one reading per logReading(), printed as it is taken.
void Walrus::beginReadings(uint8_t component, uint16_t n)
{
    _component = component;
    if(component & MS5803) { _pressureReadings.reset(); _tempMS5803Readings.reset(); }
    if(component & MCP9808) _tempExtReadings.reset();
    _dev.beginBatch(n);
}

void Walrus::endReadings()
{
    //No cleanup required currently
}

size_t Walrus::printHeader(Print& out)
{
    size_t n = 0;
    if(_component & MS5803) n += out.print("Pressure [mBar],Temp DHt [C],");
    if(_component & MCP9808) n += out.print("Temp DH [C],");
    return n;
}

size_t Walrus::printReading(Print& out)
{
    size_t n = 0;
    if(_component & MS5803) { n += out.print(_pressure); n += out.print(','); n += out.print(_tempMS5803); n += out.print(','); }
    if(_component & MCP9808) { n += out.print(_tempExt); n += out.print(','); }
    return n;
}

size_t Walrus::logReading(Print& out)
{
    //One acquisition per chip group selected, then the values just taken.
    if(_component & MS5803) {
        _pressure = _tempMS5803 = NW_ERROR;
        if(updatePressure()) {
            _pressure = _pressureReadings.last() / 1000.0;
            _tempMS5803 = _tempMS5803Readings.last() / 100.0;
        }
    }
    if(_component & MCP9808) {
        _tempExt = NW_ERROR;
        if(updateTemperature()) _tempExt = _tempExtReadings.last() / 100.0;
    }
    return printReading(out);
}

Updated on 2026-09-23 at 22:42:33 +0000