Program Listing for File xensiv_pas_gas_ino.cpp

Return to documentation for file (src/xensiv_pas_gas_ino.cpp)

#include "xensiv_pas_gas_ino.hpp"

#define GASINO_ASSERT_RET(x)                                                                                           \
    if (x != XENSIV_PAS_GAS_OK)                                                                                        \
    {                                                                                                                  \
        return x;                                                                                                      \
    }

#define PAS_GAS_SERIAL_PAL_INIT_EXTERNAL

XENSIV_PAS_GASIno::XENSIV_PAS_GASIno(GasType_t gasType, TwoWire *wire, uint8_t intPin)
    : i2c(wire), uart(nullptr), intPin(intPin), gasType(gasType)
{
}

XENSIV_PAS_GASIno::XENSIV_PAS_GASIno(GasType_t gasType, HardwareSerial *serial, uint8_t intPin)
    : i2c(nullptr), uart(serial), intPin(intPin), gasType(gasType)
{
}

XENSIV_PAS_GASIno::~XENSIV_PAS_GASIno() {}

Error_t XENSIV_PAS_GASIno::begin()
{
    int32_t ret = XENSIV_PAS_GAS_OK;
    xensiv_pas_gas_interface_t itf;
    void *ctx;

    if (nullptr != i2c)
    {
#ifndef PAS_GAS_SERIAL_PAL_INIT_EXTERNAL
        i2c->begin();
        i2c->setClock(freqHz);
#endif
        itf = XENSIV_PAS_GAS_INTERFACE_I2C;
        ctx = i2c;
    }
    else if (nullptr != uart)
    {
#ifndef PAS_GAS_SERIAL_PAL_INIT_EXTERNAL
        uart->begin(baudrateBps);
#endif
        itf = XENSIV_PAS_GAS_INTERFACE_UART;
        ctx = uart;
    }
    else
    {
        return XENSIV_PAS_GAS_INVALID_SENSOR_INTERFACE;
    }

    switch (gasType)
    {
    case SENSOR_R290:
        ret = xensiv_pas_gas_r290_init(&dev, itf, ctx);
        break;
    case SENSOR_CO2:
        ret = xensiv_pas_gas_co2_init(&dev, itf, ctx);
        break;
    case SENSOR_A2L:
        ret = xensiv_pas_gas_a2l_init(&dev, itf, ctx);
        break;
    default:
        return XENSIV_PAS_GAS_INVALID_SENSOR_TYPE;
    }
    if (ret != XENSIV_PAS_GAS_OK)
        return ret;

    if (unusedPin != intPin)
    {
        pinMode(intPin, INPUT_PULLUP);
    }

    // Set sensor to idle mode
    xensiv_pas_gas_measurement_config_t measConf;
    ret = xensiv_pas_gas_get_measurement_config(&dev, &measConf);
    if (ret != XENSIV_PAS_GAS_OK)
        return ret;

    measConf.b.op_mode = XENSIV_PAS_GAS_OP_MODE_IDLE;
    ret = xensiv_pas_gas_set_measurement_config(&dev, measConf);

    return ret;
}

Error_t XENSIV_PAS_GASIno::end()
{
    if (nullptr != i2c)
    {
#ifndef PAS_GAS_SERIAL_PAL_INIT_EXTERNAL
#if !defined(ARDUINO_ARCH_ESP32)
        i2c->end();
#endif
#endif
    }
    else if (nullptr != uart)
    {
#ifndef PAS_GAS_SERIAL_PAL_INIT_EXTERNAL
        uart->end();
#endif
    }

    /* Deinitialize interrupt pin */
    if (unusedPin != intPin)
    {
        detachInterrupt(digitalPinToInterrupt(intPin));
    }

    return XENSIV_PAS_GAS_OK;
}

Error_t XENSIV_PAS_GASIno::startMeasure(int16_t periodInSec, int16_t alarmTh, void (*cback)(void *),
                                        bool earlyNotification)
{
    xensiv_pas_gas_measurement_config_t measConf;
    xensiv_pas_gas_interrupt_config_t intConf;
    int32_t ret = XENSIV_PAS_GAS_OK;

    /* Get meas configuration*/
    ret = xensiv_pas_gas_get_measurement_config(&dev, &measConf);
    GASINO_ASSERT_RET(ret);

    measConf.b.op_mode = XENSIV_PAS_GAS_OP_MODE_IDLE;

    ret = xensiv_pas_gas_set_measurement_config(&dev, measConf);
    GASINO_ASSERT_RET(ret);

    /* Get int configuration */
    ret = xensiv_pas_gas_get_interrupt_config(&dev, &intConf);
    GASINO_ASSERT_RET(ret);

    /* Default configuration */
    measConf.b.op_mode = XENSIV_PAS_GAS_OP_MODE_SINGLE;
    intConf.b.int_func = XENSIV_PAS_GAS_INTERRUPT_FUNCTION_DRDY;

    if (periodInSec > 0)
    {
        ret = xensiv_pas_gas_set_measurement_rate(&dev, periodInSec);
        GASINO_ASSERT_RET(ret);

        measConf.b.op_mode = XENSIV_PAS_GAS_OP_MODE_CONTINUOUS;
    }

    if (alarmTh > 0)
    {
        ret = xensiv_pas_gas_set_alarm_threshold(&dev, alarmTh);
        GASINO_ASSERT_RET(ret);

        intConf.b.alarm_typ = XENSIV_PAS_GAS_ALARM_TYPE_LOW_TO_HIGH;
        intConf.b.int_func = XENSIV_PAS_GAS_INTERRUPT_FUNCTION_ALARM;
    }
    else
    {
        ret = xensiv_pas_gas_set_alarm_threshold(&dev, 0x0000);
        GASINO_ASSERT_RET(ret);

        intConf.b.alarm_typ = XENSIV_PAS_GAS_ALARM_TYPE_HIGH_TO_LOW;
    }

    if (cback != nullptr)
    {
        /* Enable sensor interrupt */
        intConf.b.int_typ = XENSIV_PAS_GAS_INTERRUPT_TYPE_HIGH_ACTIVE;
#if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_PSOC6)
        PinStatus int_event;
#else
        uint8_t int_event;
#endif
        int_event = RISING;

        if (true == earlyNotification)
        {
            /* In this case it would be useful to have an interrupt
               for both the rising and falling edge. */
            int_event = CHANGE;
        }

        /* Enable mcu interrupt */
        attachInterrupt(digitalPinToInterrupt(intPin), (void (*)())cback, int_event);
    }
    else
    {
        /* Disable sensor interrupt */
        intConf.b.int_func = XENSIV_PAS_GAS_INTERRUPT_FUNCTION_NONE;

        if (unusedPin != intPin)
        {
            /* Disable mcu interrupt */
            detachInterrupt(digitalPinToInterrupt(intPin));
        }
    }

    /* This option will disable the alarm interrupt function */
    if (true == earlyNotification)
    {
        intConf.b.int_func = XENSIV_PAS_GAS_INTERRUPT_FUNCTION_EARLY;
    }

    ret = xensiv_pas_gas_set_interrupt_config(&dev, intConf);
    GASINO_ASSERT_RET(ret);

    ret = xensiv_pas_gas_set_measurement_config(&dev, measConf);

    return ret;
}

Error_t XENSIV_PAS_GASIno::getGasConcentration(float &gasRawValue)
{
    int32_t ret = XENSIV_PAS_GAS_OK;
    int16_t raw = 0;
    /* Initially set to 0.*/
    gasRawValue = 0;

    /* Read the data */
    ret = xensiv_pas_gas_get_result(&dev, (uint16_t *)&raw);
    GASINO_ASSERT_RET(ret);

    switch (gasType)
    {
    case SENSOR_R290:
        /* Convert to float */
        gasRawValue = static_cast<float>(raw) / 100.0f; // R290: convert to %LFL
        break;
    case SENSOR_A2L:
        /* Convert to float */
        gasRawValue = static_cast<float>(raw) / 100.0f; // A2L: convert to %LFL
        break;
    case SENSOR_CO2:
        /* Convert to float */
        gasRawValue = static_cast<float>(raw); // CO2: convert to ppm
        break;
    default:
        return XENSIV_PAS_GAS_INVALID_SENSOR_TYPE;
    }

    /* Clear masks from status register */
    ret = xensiv_pas_gas_clear_measurement_status(
        &dev, (XENSIV_PAS_GAS_REG_MEAS_STS_INT_STS_CLR_MSK | XENSIV_PAS_GAS_REG_MEAS_STS_ALARM_CLR_MSK));
    GASINO_ASSERT_RET(ret);

    return ret;
}

Error_t XENSIV_PAS_GASIno::stopMeasure()
{
    int32_t ret = XENSIV_PAS_GAS_OK;
    xensiv_pas_gas_measurement_config_t measConf;

    /* Get meas configuration*/
    ret = xensiv_pas_gas_get_measurement_config(&dev, &measConf);
    GASINO_ASSERT_RET(ret);

    /* Set meas configuration to idle mode */
    measConf.b.op_mode = XENSIV_PAS_GAS_OP_MODE_IDLE;
    ret = xensiv_pas_gas_set_measurement_config(&dev, measConf);

    return ret;
}

Error_t XENSIV_PAS_GASIno::getDiagnosis(Diag_t &diagnosis)
{
    int32_t ret = XENSIV_PAS_GAS_OK;

    /* Get current status */
    ret = xensiv_pas_gas_get_status(&dev, &diagnosis);
    GASINO_ASSERT_RET(ret);

    /* Clear read flags */
    ret = xensiv_pas_gas_clear_status(&dev, (XENSIV_PAS_GAS_REG_SENS_STS_ICCER_CLR_MSK |
                                             XENSIV_PAS_GAS_REG_SENS_STS_ORVS_CLR_MSK |
                                             XENSIV_PAS_GAS_REG_SENS_STS_ORTMP_CLR_MSK));

    return ret;
}

Error_t XENSIV_PAS_GASIno::setABOC(ABOC_t aboc, int16_t abocRef)
{
    xensiv_pas_gas_measurement_config_t measConf;
    int32_t ret = XENSIV_PAS_GAS_OK;

    /* Get meas configuration */
    ret = xensiv_pas_gas_get_measurement_config(&dev, &measConf);
    GASINO_ASSERT_RET(ret);

    /* Set compensation offset */
    ret = xensiv_pas_gas_set_offset_compensation(&dev, (uint16_t)abocRef);
    GASINO_ASSERT_RET(ret);

    /* Set meas configuration with ABOC */
    measConf.b.boc_cfg = aboc;
    ret = xensiv_pas_gas_set_measurement_config(&dev, measConf);

    return ret;
}

Error_t XENSIV_PAS_GASIno::performForcedCompensation(uint16_t GASRef)
{
    return xensiv_pas_gas_perform_forced_compensation(&dev, GASRef);
}

Error_t XENSIV_PAS_GASIno::setPressRef(uint16_t pressRef)
{
    int32_t ret = XENSIV_PAS_GAS_OK;

    ret = xensiv_pas_gas_set_pressure_compensation(&dev, pressRef);

    return ret;
}

Error_t XENSIV_PAS_GASIno::reset()
{
    int32_t ret = XENSIV_PAS_GAS_OK;

    ret = xensiv_pas_gas_cmd(&dev, XENSIV_PAS_GAS_CMD_SOFT_RESET);
    GASINO_ASSERT_RET(ret);

    return ret;
}

Error_t XENSIV_PAS_GASIno::getProductID(uint8_t &prodID, uint8_t &revID)
{
    int32_t ret = XENSIV_PAS_GAS_OK;
    xensiv_pas_gas_id_t id;

    ret = xensiv_pas_gas_get_id(&dev, &id);
    GASINO_ASSERT_RET(ret);

    prodID = id.b.prod;
    revID = id.b.rev;

    return ret;
}

Error_t XENSIV_PAS_GASIno::getRegister(uint8_t regAddr, uint8_t *data, uint8_t len)
{
    return xensiv_pas_gas_get_reg(&dev, regAddr, data, len);
}

Error_t XENSIV_PAS_GASIno::setRegister(uint8_t regAddr, const uint8_t *data, uint8_t len)
{
    return xensiv_pas_gas_set_reg(&dev, regAddr, data, len);
}

const char *XENSIV_PAS_GASIno::getGasConcentrationUnitStr()
{
    switch (gasType)
    {
    case SENSOR_R290:
        return "%LFL"; // R290
    case SENSOR_CO2:
        return "ppm"; // CO2
    case SENSOR_A2L:
        return "%LFL"; // A2L
    default:
        return "";
    }
}

Error_t XENSIV_PAS_GASIno::clearForcedCompensation()
{
    switch (gasType)
    {
    case SENSOR_CO2:
        return xensiv_pas_gas_cmd(&dev, (xensiv_pas_gas_cmd_t)XENSIV_PAS_GAS_CO2_CMD_RESET_FCS);
    case SENSOR_A2L:
        return xensiv_pas_gas_cmd(&dev, (xensiv_pas_gas_cmd_t)XENSIV_PAS_GAS_A2L_CMD_RESET_FCS);
    default:
        return XENSIV_PAS_GAS_OK;
    }
}

const char *XENSIV_PAS_GASIno::getPasGasErrorStr(Error_t err)
{
    switch (err)
    {
    case XENSIV_PAS_GAS_OK:
        return "OK";
    case XENSIV_PAS_GAS_ERR_COMM:
        return "Communication error";
    case XENSIV_PAS_GAS_ERR_WRITE_TOO_LARGE:
        return "Write too large";
    case XENSIV_PAS_GAS_ERR_NOT_READY:
        return "Not ready";
    case XENSIV_PAS_GAS_ICCERR:
        return "Serial command error";
    case XENSIV_PAS_GAS_ORVS:
        return "VDD5V out of range";
    case XENSIV_PAS_GAS_ORTMP:
        return "Temperature out of range";
    case XENSIV_PAS_GAS_READ_NRDY:
        return "GAS value not ready";
    case XENSIV_PAS_GAS_INVALID_SENSOR_INTERFACE:
        return "Invalid sensor interface";
    case XENSIV_PAS_GAS_INVALID_PARAMETER:
        return "Invalid parameter";
    default:
        return "Unknown error";
    }
}