library for AMS ENS210 temperature and humidity sensor

Dependents:   rIoTwear-temp-humid

AMS_ENS210.cpp

Committer:
batman52
Date:
2019-12-03
Revision:
9:e121ac861a82
Parent:
8:1a7d241afbcb

File content as of revision 9:e121ac861a82:


#include "AMS_ENS210.h"

AMS_ENS210::AMS_ENS210(PinName sda, PinName scl) :
    _temp_mode(CONFIG_TEMP_OP_MODE),
    _humid_mode(CONFIG_HUMID_OP_MODE),
    _power_mode(CONFIG_POWER_MODE),
    _reset(0),
    temp_reading(0),
    humid_reading(0),
    _i2c(sda, scl)
{ }

AMS_ENS210::AMS_ENS210(PinName sda, PinName scl, bool temp_single_shot, bool humid_single_shot) :
    _temp_mode(temp_single_shot),
    _humid_mode(humid_single_shot),
    _power_mode(CONFIG_POWER_MODE),
    _reset(0),
    temp_reading(0),
    humid_reading(0),
    _i2c(sda, scl)
{ }

AMS_ENS210::AMS_ENS210(PinName sda, PinName scl, bool temp_single_shot, bool humid_single_shot, bool low_power) :
    _temp_mode(temp_single_shot),
    _humid_mode(humid_single_shot),
    _power_mode(low_power),
    _reset(0),
    temp_reading(0),
    humid_reading(0),
    _i2c(sda, scl)
{ }

AMS_ENS210::~AMS_ENS210() {}

bool AMS_ENS210::init()
{

    return write_config();

}

bool AMS_ENS210::reset()
{

    _reset = true;
    bool success = write_config(true, false);
    _reset = false;

    return success;

}

bool AMS_ENS210::low_power_mode(bool low_power)
{
    _power_mode = low_power;
    return write_config(true, false);
}

bool AMS_ENS210::low_power_mode()
{
    return read_config(true, false)[0] & 1; // just mask bit 0
}

bool AMS_ENS210::is_active()
{
    char output[1];
    i2c_read(SYS_STATUS, output, 1);
    return output[0] & 1;
}

bool AMS_ENS210::temp_continuous_mode(bool continuous)
{
    _temp_mode = continuous;
    return write_config(false, true);
}

bool AMS_ENS210::temp_continuous_mode()
{
    return read_config(false, true)[0] & 1; // just mask bit 0
}

bool AMS_ENS210::humid_continuous_mode(bool continuous)
{
    _humid_mode = continuous;
    return write_config(false, true);
}

bool AMS_ENS210::humid_continuous_mode()
{
    return (read_config(false, true)[0] >> 1) & 1; // shift bit 1 and mask
}

bool AMS_ENS210::start(bool temp, bool humid)
{
    char cmd[1] = {0 | temp | (humid << 1)};
    return i2c_write(SENS_START, cmd, 1) == 1; //_i2c.write(ENS210_SLAVE_ADDR, cmd, 2) == 2;
}

bool AMS_ENS210::stop(bool temp, bool humid)
{
    char cmd[1] = {0 | temp | (humid << 1)};
    return i2c_write(SENS_STOP, cmd, 1) == 1; //_i2c.write(ENS210_SLAVE_ADDR, cmd, 2) == 2;
}

bool AMS_ENS210::temp_is_measuring()
{
    char output[1];
    i2c_read(SENS_STATUS, output, 1);
    return output[0] & 1;
}

bool AMS_ENS210::humid_is_measuring()
{
    char output[1];
    i2c_read(SENS_STATUS, output, 1);
    return output[0] >> 1 & 1;
}

bool AMS_ENS210::temp_has_data()
{

    char output[3];
    i2c_read(SENS_TEMP, output, 3);

    // do crc7
    // Store read data to avoid reading from I2C again
    temp_reading = 0 | output[0] | (output[1] << 8);    // bytes 1 and 2 make the 16 bit data

    bool valid = output[2] & 1;                         // bit 0 of byte 3 is the valid flag


    if (!valid) {
        if (!temp_continuous_mode()) {                  // when in single shot mode make sure sensor has started
            if (!temp_is_measuring())
                start(true, false);                     // set start bit if sensor is idle
        }
    }

    return valid;
}

bool AMS_ENS210::humid_has_data()
{

    char output[3];
    i2c_read(SENS_HUMID, output, 3);

    // do crc7
    // Store read data to avoid reading from I2C again
    humid_reading = 0 | output[0] | (output[1] << 8);   // bytes 1 and 2 make the 16 bit data

    bool valid = output[2] & 1;                         // bit 0 of byte 3 is the valid flag

    if (!valid) {
        if (!humid_continuous_mode()) {                 // when in single shot mode make sure sensor has started first
            if (!humid_is_measuring())
                start(false, true);                     // set start bit if sensor is idle
        }
    }

    return valid;
}

uint16_t AMS_ENS210::temp_read()
{

    uint16_t reading = 0;

    if (!temp_continuous_mode()) {                          // when in single shot mode, data is read and saved in temp_has_data()
        reading = temp_reading;
    } else {
        char output[3];
        i2c_read(SENS_TEMP, output, 3);

        // do crc7
        if (output[2] & 1)                                  // bit 0 of byte 3 is the valid flag
            reading = 0 | output[0] | (output[1] << 8);     // bytes 1 and 2 make the 16 bit data
    }

    return reading;
}

uint16_t AMS_ENS210::humid_read()
{
    uint16_t reading = 0;

    if (!humid_continuous_mode()) {                         // when in single shot mode, data is read and saved in humid_has_data()
        reading = humid_reading;
    } else {
        char output[3];
        i2c_read(SENS_HUMID, output, 3);

        // do crc7
        if (output[2] & 1)                                  // bit 0 of byte 3 is the valid flag
            reading = 0 | output[0] | (output[1] << 8);     // bytes 1 and 2 make the 16 bit data
    }

    return reading;
}

/*** Private ***/

bool AMS_ENS210::write_config(bool system, bool sensor)
{
    int w_bytes = 0;
    char cmd[1];

    if (system) {
        cmd[0] = 0 | _power_mode | _reset << 7; // bit 0 of SYS_CTRL is power mode, bit 7 is reset
        w_bytes += i2c_write(SYS_CONFIG, cmd, 1); //_i2c.write(ENS210_SLAVE_ADDR, cmd, 2);
    }

    if (sensor) {
        cmd[0] = 0 | _temp_mode | (_humid_mode << 1); // bit 0 is temp mode, bit 1 is humid mode
        w_bytes += i2c_write(SENS_OP_MODE, cmd, 1); //_i2c.write(ENS210_SLAVE_ADDR, cmd, 2);
    }

    return w_bytes == (system + sensor);
}

const char *AMS_ENS210::read_config(bool system, bool sensor)   // todo, maybe throw excpetion if i2c read fails?
{

    static char output[2] = {0, 0};

    if (system)
        i2c_read(SYS_CONFIG, output, 1);

    if (sensor)
        i2c_read(SENS_OP_MODE, output+system, 1);

    return output;

}

int AMS_ENS210::i2c_read(char reg_addr, char* output, int len)
{

    int read_count = 0;


    char reg_cmd[1];
    reg_cmd[0] = reg_addr;
    _i2c.write(ENS210_SLAVE_ADDR, reg_cmd, 1, true);
    wait_ms(10);
    int read_res = _i2c.read(ENS210_SLAVE_ADDR, output, len);
    if (read_res == 0) read_count = len;

    return read_count;
}

int AMS_ENS210::i2c_write(char reg_addr, char* input, int len)
{

    int write_count = 0;


    // char cmd[len+1]; works with mbed, but not with IAR/GCC
    char *cmd = (char *) malloc( len + 1);
    cmd[0] = reg_addr;
    memcpy(cmd+1, input, len);
    write_count = _i2c.write(ENS210_SLAVE_ADDR, cmd, len+1) + 1;
    free(cmd);
    
    return write_count;
}