Arslan Test
Dependencies: AMS_ENS210_temp_humid_sensor
Diff: AMS_CCS811.cpp
- Revision:
- 5:41e97348e9e7
- Parent:
- 4:a6b8881eae87
- Child:
- 6:22c0a7f2ece2
--- a/AMS_CCS811.cpp Thu Jan 19 14:27:44 2017 +0000 +++ b/AMS_CCS811.cpp Fri Jan 20 14:34:41 2017 +0000 @@ -1,14 +1,27 @@ #include "AMS_CCS811.h" +const char *byte_to_binary(uint8_t in) +{ + static char b[9]; + b[0] = '\0'; + + int z; + for (z = 128; z > 0; z >>= 1) + { + strcat(b, ((in & z) == z) ? "1" : "0"); + } + + return b; +} AMS_CCS811::AMS_CCS811(I2C * i2c, PinName n_wake_pin) { - _n_wake_out = new (std::nothrow) DigitalOut(n_wake_pin); + _n_wake_out = new (std::nothrow) DigitalOut(n_wake_pin, 1); _i2c = i2c; } AMS_CCS811::AMS_CCS811(I2C * i2c, PinName n_wake_pin, I2C * ens210_i2c) { - _n_wake_out = new (std::nothrow) DigitalOut(n_wake_pin); + _n_wake_out = new (std::nothrow) DigitalOut(n_wake_pin, 1); _i2c = i2c; _ens210_i2c = ens210_i2c; } @@ -20,9 +33,32 @@ } bool AMS_CCS811::init() { - enable_ens210(true); + + USBserialComms.printf("Init()\r"); - return set_defaults(); + bool success = false; + + _init_errors(); + set_defaults(); + + if (_n_wake_out) { + USBserialComms.printf("_n_wake_out: %d\r", _n_wake_out != NULL); + USBserialComms.printf("_n_wake_out I/0: %d\r", _n_wake_out->read()); + + int fw_mode = firmware_mode(); + + if (fw_mode == 1) { + USBserialComms.printf("App Mode\r"); + enable_ens210(true); + success = write_config(); + + } else if (fw_mode == 0) { // is in boot mode, needs to be loaded into app mode + USBserialComms.printf("Boot Mode\r"); + if (boot_app_start()) // if succesfully writes to app_start, retry init + init(); + } + } + return success; } void AMS_CCS811::i2c_interface(I2C * i2c) { @@ -55,6 +91,17 @@ return _ens210_poll_split; } +int AMS_CCS811::firmware_mode() { + int firmware_result = -1; + + read_byte_result read_result = read_status(); + if (read_result.success) { + firmware_result = (read_result.byte >> 7) & 1; + } // todo ... add a new "last error" here + + return firmware_result; +} + bool AMS_CCS811::mode(OP_MODES mode) { OP_MODES old = _mode; // incase the write fails, to roll back _mode = mode; @@ -67,9 +114,9 @@ } AMS_CCS811::OP_MODES AMS_CCS811::mode() { - OP_MODES result = _mode; // rather not rely on this, but just incase the read fails + OP_MODES result = INVALID; - read_config_result read_result = read_config(); + read_byte_result read_result = read_config(); if (read_result.success) { int mode = (read_result.byte >> 4) & 0b111; result = mode > 4 ? INVALID : (OP_MODES)mode; @@ -80,7 +127,7 @@ bool AMS_CCS811::addr_mode(bool high) { _addr_dir = high; - if (_addr_out != NULL) *_addr_out = _addr_dir; + if (_addr_out != NULL) _addr_out->write(_addr_dir); update_slave_addr(); @@ -89,7 +136,7 @@ bool AMS_CCS811::addr_mode() { if (_addr_out != NULL) { - _addr_dir = *_addr_out; + _addr_dir = _addr_out->read(); } return _addr_dir; @@ -112,8 +159,15 @@ } -AMS_CCS811::DATA_STATUS AMS_CCS811::has_new_data() { - return (DATA_STATUS) 0; +int AMS_CCS811::has_new_data() { + int result = -1; + + if (i2c_read(ALG_RESULT_DATA, _alg_result_data, 8) == 8) { + result = (_alg_result_data[4] >> 3) & 1; + } + USBserialComms.printf("has_new_data(addr: 0x%02X, result: %d, byte: %s(%d))\r", ALG_RESULT_DATA, result, byte_to_binary(_alg_result_data[4]), _alg_result_data[4]); + + return result; } uint16_t AMS_CCS811::co2_read() { @@ -128,8 +182,49 @@ return 0; } -const char * AMS_CCS811::last_error() { - return "TODO"; +bool AMS_CCS811::error_status() { + bool result = false; + + read_byte_result read_result = read_status(); + if (read_result.success) { + result = read_result.byte & 1; + } + + result = result || (_error_count > 0); + + return result; +} + +AMS_CCS811::ccs811_errors AMS_CCS811::errors() { + ccs811_errors error_result; + + char byte[1]; + if (i2c_read(ERROR_ID, byte, 1) == 1) { + for(int i = 0; i < CCS811_ERR_NUM; i++) { + if ((byte[0] << i) & 1) { + error_result.codes[error_result.count++] = i; + } + } + } + for(int i = 0; i < CCS811_LIB_ERR_NUM; i++) { + if (_errors[i]) { + error_result.codes[error_result.count++] = i + CCS811_ERR_NUM; + } + } + + return error_result; + +} + +const char * AMS_CCS811::error_string(int err_code){ + static char result[255]; + result[0] = 0; + if (err_code < CCS811_TOTAL_ERR_NUM && err_code > -1) + strcpy(result, _error_strings[err_code]); + else + sprintf(result, "Invalid Code: %d is out of range (0 - %d)", err_code, CCS811_TOTAL_ERR_NUM-1); + + return result; } bool AMS_CCS811::enable_interupt(bool enable) { @@ -144,10 +239,10 @@ } -bool AMS_CCS811::interupt_enabled() { - bool enabled = _int_data_enabled; // rather not rely on this, but just incase the read fails +int AMS_CCS811::interupt_enabled() { + int enabled = -1; - read_config_result read_result = read_config(); + read_byte_result read_result = read_config(); if (read_result.success) { enabled = (read_result.byte >> 3) & 1; } // todo ... add a new "last error" here? or maybe the read method itself should set that. @@ -172,7 +267,7 @@ /** Private **/ -bool AMS_CCS811::set_defaults() { +void AMS_CCS811::set_defaults() { if (_mode == NULL) _mode = CONFIG_OP_MODE; if (_addr_dir == NULL) @@ -182,9 +277,45 @@ if (_ens210_poll_split == NULL) _ens210_poll_split = CONFIG_ENS210_POLL; - update_slave_addr(); + USBserialComms.printf("Defaults set: _mode(%d), _addr_dir(%d), _int_data_enabled(%d), _ens210_poll_split(%d)\r", _mode, _addr_dir, _int_data_enabled, _ens210_poll_split); - return write_config(); + update_slave_addr(); + + USBserialComms.printf("_slave_addr: 0x%02X\r", _slave_addr); +} + +void AMS_CCS811::_init_errors() { + clear_errors(); + /* Sensor errors */ + strcpy(_error_strings[0], CCS811_WRITE_REG_INVALID); + strcpy(_error_strings[1], CCS811_READ_REG_INVALID); + strcpy(_error_strings[2], CCS811_MEASMODE_INVALID); + strcpy(_error_strings[3], CCS811_MAX_RESISTANCE); + strcpy(_error_strings[4], CCS811_HEATER_FAULT); + strcpy(_error_strings[5], CCS811_HEATER_SUPPLY); + strcpy(_error_strings[6], CCS811_RESERVED); + strcpy(_error_strings[7], CCS811_RESERVED); + /* Library errors */ + strcpy(_error_strings[CCS811_LIB_N_WAKE_ID+CCS811_ERR_NUM], CCS811_LIB_N_WAKE); + strcpy(_error_strings[CCS811_LIB_I2C_ID+CCS811_ERR_NUM], CCS811_LIB_I2C); + strcpy(_error_strings[CCS811_LIB_SLAVE_W_ID+CCS811_ERR_NUM], CCS811_LIB_SLAVE_W); + strcpy(_error_strings[CCS811_LIB_REG_ADDR_ID+CCS811_ERR_NUM], CCS811_LIB_REG_ADDR); + strcpy(_error_strings[CCS811_LIB_I2CWRITE_ID+CCS811_ERR_NUM], CCS811_LIB_I2CWRITE); + strcpy(_error_strings[CCS811_LIB_SLAVE_R_ID+CCS811_ERR_NUM], CCS811_LIB_SLAVE_R); +} + +void AMS_CCS811::clear_errors() { + _error_count = 0; + for (int i = 0; i < CCS811_LIB_ERR_NUM; i++) { + _errors[i] = false; + } +} + +void AMS_CCS811::new_error(int error_id) { + if (!_errors[error_id]) { + _errors[error_id] = true; + _error_count++; + } } void AMS_CCS811::update_ens210_timer() { @@ -197,7 +328,7 @@ } void AMS_CCS811::update_slave_addr() { - slave_addr = addr_mode() ? SLAVE_ADDR_RAW_H : SLAVE_ADDR_RAW_L; + _slave_addr = addr_mode() ? CCS811_SLAVE_ADDR_RAW_H : CCS811_SLAVE_ADDR_RAW_L; } void AMS_CCS811::_isr_data() { @@ -206,60 +337,93 @@ bool AMS_CCS811::write_config() { char cmd[1] = {0 | (_int_data_enabled << 3) | (_mode << 4)}; - return i2c_write(SYS_MODE, cmd, 1) == 1; + USBserialComms.printf("write_config(addr: 0x%02X, byte: %s(%d))\r", MEAS_MODE, byte_to_binary(cmd[0]), cmd[0]); + return i2c_write(MEAS_MODE, cmd, 1) == 1; +} + +AMS_CCS811::read_byte_result AMS_CCS811::read_config() { + read_byte_result result; + char byte[1]; + if (i2c_read(MEAS_MODE, byte, 1) == 1) { + result.success = true; + result.byte = byte[0]; + } + USBserialComms.printf("read_config(addr: 0x%02X, success: %s, byte: %s(%d))\r", MEAS_MODE, result.success ? "true" : "false", byte_to_binary(result.byte), result.byte); + return result; } -AMS_CCS811::read_config_result AMS_CCS811::read_config() { - read_config_result result; +AMS_CCS811::read_byte_result AMS_CCS811::read_status() { + read_byte_result result; char byte[1]; - if (i2c_read(SYS_MODE, byte, 1) == 1) { + if (i2c_read(STATUS, byte, 1) == 1) { result.success = true; - result.byte = byte[1]; + result.byte = byte[0]; + } + USBserialComms.printf("read_status(addr: 0x%02X, success: %s, byte: %s(%d))\r", STATUS, result.success ? "true" : "false", byte_to_binary(result.byte), result.byte); + return result; +} + +bool AMS_CCS811::boot_app_start() { + bool success = false; + + if (i2c_write(APP_START, NULL, 0) == 0) { + wait_ms(70); + success = true; } - return result; + return success; } int AMS_CCS811::i2c_read(char reg_addr, char* output, int len) { int read_count = 0; if (_n_wake_out != NULL) { // check nWAKE pin is set + _n_wake_out->write(0); // Hold low + wait_us(CCS811_T_AWAKE); // tAWAKE time to allow sensor I2C to wake up if (_i2c != NULL) { // check I2C interface is set _i2c->start(); // send start condition for write - if(_i2c->write(SLAVE_ADDR_W) == 1) { // write slave address with write bit + if(_i2c->write(CCS811_SLAVE_ADDR_W) == 1) { // write slave address with write bit if(_i2c->write(reg_addr) == 1) { // write register address _i2c->start(); // send another start condition for read - if(_i2c->write(SLAVE_ADDR_R) == 1) { // write slave address with read bit + if(_i2c->write(CCS811_SLAVE_ADDR_R) == 1) { // write slave address with read bit for (int i = 0; i < len; i++) { // read len bytes output[i] = _i2c->read(i < len-1 ? 1 : 0); // ack all reads aside from the final one (i == len-1) read_count++; } - } - } - } + } else new_error(CCS811_LIB_SLAVE_R_ID); + } else new_error(CCS811_LIB_REG_ADDR_ID); + } else new_error(CCS811_LIB_SLAVE_W_ID); _i2c->stop(); // send stop condition - } - } + } else new_error(CCS811_LIB_I2C_ID); + _n_wake_out->write(1); // Set back to high + wait_us(CCS811_T_DWAKE); // tDWAKE time to allow sensor I2C to sleep + } else new_error(CCS811_LIB_N_WAKE_ID); return read_count; } -int AMS_CCS811::i2c_write(char reg_addr, char* input, int len) { // to do... error reporting +int AMS_CCS811::i2c_write(char reg_addr, char* input, int len) { - int write_count = 0; + int write_count = -1; if (_n_wake_out != NULL) { // check nWAKE pin is set + _n_wake_out->write(0); // Hold low + wait_us(CCS811_T_AWAKE); // tAWAKE time to allow sensor I2C to wake up if (_i2c != NULL) { // check I2C interface is set _i2c->start(); // send start condition for write - if(_i2c->write(SLAVE_ADDR_W) == 1) { // write slave address + if(_i2c->write(CCS811_SLAVE_ADDR_W) == 1) { // write slave address if(_i2c->write(reg_addr) == 1) { // write register address + write_count = 0; for (int i = 0; i < len; i++) { // write len bytes if(_i2c->write(input[i]) == 1) write_count++; // write each byte, if successful increment count + else new_error(CCS811_LIB_I2CWRITE_ID); } - } - } + } else new_error(CCS811_LIB_REG_ADDR_ID); + } else new_error(CCS811_LIB_SLAVE_W_ID); _i2c->stop(); // send stop condition - } - } + } else new_error(CCS811_LIB_I2C_ID); + _n_wake_out->write(1); // set back to high + wait_us(CCS811_T_DWAKE); // tDWAKE time to allow sensor I2C to sleep + }else new_error(CCS811_LIB_N_WAKE_ID); return write_count; } \ No newline at end of file