From 2bee597dacdbc39d139d64bdf509ab996214dbef Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Fri, 7 Oct 2016 06:55:48 +0200 Subject: [PATCH 1/4] Added optional timeout to all read functions to avoid infinite locks upon sensor failure or disconnection --- SI7021.cpp | 111 +++++++++++++++++++++++++++++++---------------------- SI7021.h | 18 +++++---- 2 files changed, 75 insertions(+), 54 deletions(-) diff --git a/SI7021.cpp b/SI7021.cpp index 4d06046..d90e0b6 100644 --- a/SI7021.cpp +++ b/SI7021.cpp @@ -3,10 +3,13 @@ Copyright 2014 Marcus Sorensen This program is licensed, please check with the copyright holder for terms -Updated: Jul 16, 2015: TomWS1: - eliminated Byte constants, - fixed 'sizeof' error in _command(), - added getTempAndRH() function to simplify calls for C & RH only +Updated: + * Jul 16, 2015: TomWS1: + eliminated Byte constants, + fixed 'sizeof' error in _command(), + added getTempAndRH() function to simplify calls for C & RH only + * Aug 25, 2016: jlblancoc + added an optional timeout to all read functions to avoid infinite locks upon sensor failure or disconnection. */ #include "Arduino.h" #include "SI7021.h" @@ -54,41 +57,61 @@ int SI7021::getFahrenheitHundredths() { return (1.8 * c) + 3200; } -int SI7021::getCelsiusHundredths() { +int SI7021::getCelsiusHundredths(bool *timeout /*= NULL*/, int timeout_ms/*=0*/) +{ byte tempbytes[2]; - _command(TEMP_READ, tempbytes); + if (!_command(TEMP_READ, tempbytes, timeout_ms)) { + if (timeout) *timeout = true; + return 0; + } + if (timeout) *timeout = false; long tempraw = (long)tempbytes[0] << 8 | tempbytes[1]; return ((17572 * tempraw) >> 16) - 4685; } -int SI7021::_getCelsiusPostHumidity() { +int SI7021::_getCelsiusPostHumidity(bool *timeout /*= NULL*/, int timeout_ms/*=0*/) +{ byte tempbytes[2]; - _command(POST_RH_TEMP_READ, tempbytes); + if (!_command(POST_RH_TEMP_READ, tempbytes, timeout_ms)) { + if (timeout) *timeout = true; + return 0; + } + if (timeout) *timeout = false; long tempraw = (long)tempbytes[0] << 8 | tempbytes[1]; return ((17572 * tempraw) >> 16) - 4685; } -unsigned int SI7021::getHumidityPercent() { +unsigned int SI7021::getHumidityPercent(bool *timeout /*= NULL*/, int timeout_ms/*=0*/) +{ byte humbytes[2]; - _command(RH_READ, humbytes); + if (!_command(RH_READ, humbytes, timeout_ms)) { + if (timeout) *timeout = true; + return 0; + } + if (timeout) *timeout = false; long humraw = (long)humbytes[0] << 8 | humbytes[1]; return ((125 * humraw) >> 16) - 6; } -unsigned int SI7021::getHumidityBasisPoints() { +unsigned int SI7021::getHumidityBasisPoints(bool *timeout /*= NULL*/, int timeout_ms/*=0*/) +{ byte humbytes[2]; - _command(RH_READ, humbytes); + if (!_command(RH_READ, humbytes, timeout_ms)) { + if (timeout) *timeout = true; + return 0; + } + if (timeout) *timeout = false; long humraw = (long)humbytes[0] << 8 | humbytes[1]; return ((12500 * humraw) >> 16) - 600; } -void SI7021::_command(byte cmd, byte * buf ) { +bool SI7021::_command(byte cmd, byte * buf, int timeout_ms ) { _writeReg(&cmd, sizeof cmd); #if defined(ARDUINO_ARCH_ESP8266) delay(25); #endif - _readReg(buf, 2); + return _readReg(buf, 2,timeout_ms); } void SI7021::_writeReg(byte * reg, int reglen) { @@ -100,44 +123,40 @@ void SI7021::_writeReg(byte * reg, int reglen) { Wire.endTransmission(); } -int SI7021::_readReg(byte * reg, int reglen) { +bool SI7021::_readReg(byte * reg, int reglen, int timeout_ms) { Wire.requestFrom(I2C_ADDR, reglen); while(Wire.available() < reglen) { + if (timeout_ms) + { + if (!--timeout_ms) + return false; + delay(1); + } } for(int i = 0; i < reglen; i++) { reg[i] = Wire.read(); } - return 1; -} - -int SI7021::getSerialBytes(byte * buf) { - byte serial[8]; - _writeReg(SERIAL1_READ, sizeof SERIAL1_READ); - _readReg(serial, 8); - - //Page23 - https://www.silabs.com/Support%20Documents%2FTechnicalDocs%2FSi7021-A20.pdf - buf[0] = serial[0]; //SNA_3 - buf[1] = serial[2]; //SNA_2 - buf[2] = serial[4]; //SNA_1 - buf[3] = serial[6]; //SNA_0 - - _writeReg(SERIAL2_READ, sizeof SERIAL2_READ); - _readReg(serial, 6); - buf[4] = serial[0]; //SNB_3 - device ID byte - buf[5] = serial[1]; //SNB_2 - buf[6] = serial[3]; //SNB_1 - buf[7] = serial[4]; //SNB_0 - return 1; -} - -int SI7021::getDeviceId() { - //0x0D=13=Si7013 - //0x14=20=Si7020 - //0x15=21=Si7021 - byte serial[8]; - getSerialBytes(serial); - int id = serial[4]; - return id; + return true; +} + +//note this has crc bytes embedded, per datasheet, so provide 12 byte buf +bool SI7021::getSerialBytes(byte * buf,int timeout_ms) { + _writeReg(SERIAL1_READ, sizeof SERIAL1_READ); + if (!_readReg(buf, 6,timeout_ms)) return false; + + _writeReg(SERIAL2_READ, sizeof SERIAL2_READ); + if (!_readReg(buf + 6, 6,timeout_ms)) return false; + + // could verify crc here and return only the 8 bytes that matter + return true; +} + +int SI7021::getDeviceId(int timeout_ms /*= 0*/) +{ + byte serial[12]; + getSerialBytes(serial,timeout_ms); + int id = serial[6]; + return id; } void SI7021::setHeater(bool on) { diff --git a/SI7021.h b/SI7021.h index 52febe5..a1e113d 100644 --- a/SI7021.h +++ b/SI7021.h @@ -47,19 +47,21 @@ class SI7021 #endif bool sensorExists(); int getFahrenheitHundredths(); - int getCelsiusHundredths(); - unsigned int getHumidityPercent(); - unsigned int getHumidityBasisPoints(); + int getCelsiusHundredths(bool *timeout = NULL, int timeout_ms=0); + unsigned int getHumidityPercent(bool *timeout = NULL, int timeout_ms=0); + unsigned int getHumidityBasisPoints(bool *timeout = NULL, int timeout_ms=0); struct si7021_env getHumidityAndTemperature(); struct si7021_thc getTempAndRH(); - int getSerialBytes(byte * buf); - int getDeviceId(); + /** Return false on timeout */ + bool getSerialBytes(byte * buf, int timeout_ms = 0); + int getDeviceId(int timeout_ms = 0); void setHeater(bool on); private: - void _command(byte cmd, byte * buf ); + bool _command(byte cmd, byte * buf, int timeout_ms = 0 ); void _writeReg(byte * reg, int reglen); - int _readReg(byte * reg, int reglen); - int _getCelsiusPostHumidity(); + /** return true on success, false on timeout. If timeout_ms is 0, infinite wait. */ + bool _readReg(byte * reg, int reglen, int timeout_ms=0); + int _getCelsiusPostHumidity(bool *timeout = NULL, int timeout_ms=0); }; #endif From c33fc883c9b24b748aa414b98a952f28fe59eac3 Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Fri, 7 Oct 2016 06:56:14 +0200 Subject: [PATCH 2/4] Better render of README online --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f0dd2a5..290a8af 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ SI7021 ====== -Arduino library for SI7020 and SI7021 environmental sensors +Arduino library for SI7020 and SI7021 environmental sensors. + Install as usual in your Arduino/libraries folder, restart IDE. \ No newline at end of file From a0b8bcb86304ae2bd0326972672f02370eda8514 Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Fri, 7 Oct 2016 07:08:37 +0200 Subject: [PATCH 3/4] fix overwritten getDeviceId() and getSerialBytes() --- SI7021.cpp | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/SI7021.cpp b/SI7021.cpp index d90e0b6..1efede6 100644 --- a/SI7021.cpp +++ b/SI7021.cpp @@ -139,25 +139,36 @@ bool SI7021::_readReg(byte * reg, int reglen, int timeout_ms) { return true; } -//note this has crc bytes embedded, per datasheet, so provide 12 byte buf bool SI7021::getSerialBytes(byte * buf,int timeout_ms) { - _writeReg(SERIAL1_READ, sizeof SERIAL1_READ); - if (!_readReg(buf, 6,timeout_ms)) return false; - - _writeReg(SERIAL2_READ, sizeof SERIAL2_READ); - if (!_readReg(buf + 6, 6,timeout_ms)) return false; - - // could verify crc here and return only the 8 bytes that matter - return true; + byte serial[8]; + _writeReg(SERIAL1_READ, sizeof SERIAL1_READ); + if (!_readReg(serial, 8, timeout_ms)) return false; + + //Page23 - https://www.silabs.com/Support%20Documents%2FTechnicalDocs%2FSi7021-A20.pdf + buf[0] = serial[0]; //SNA_3 + buf[1] = serial[2]; //SNA_2 + buf[2] = serial[4]; //SNA_1 + buf[3] = serial[6]; //SNA_0 + + _writeReg(SERIAL2_READ, sizeof SERIAL2_READ); + if (!_readReg(serial, 6)) return false; + buf[4] = serial[0]; //SNB_3 - device ID byte + buf[5] = serial[1]; //SNB_2 + buf[6] = serial[3]; //SNB_1 + buf[7] = serial[4]; //SNB_0 + return true; +} + +uint8_t SI7021::getDeviceId(int timeout_ms /*= 0*/) { + //0x0D=13=Si7013 + //0x14=20=Si7020 + //0x15=21=Si7021 + byte serial[8]; + getSerialBytes(serial); + uint8_t id = serial[4]; + return id; } -int SI7021::getDeviceId(int timeout_ms /*= 0*/) -{ - byte serial[12]; - getSerialBytes(serial,timeout_ms); - int id = serial[6]; - return id; -} void SI7021::setHeater(bool on) { byte userbyte; From 6ba726acf8172099cd672cbcabef2e63375fba3d Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Fri, 7 Oct 2016 07:09:58 +0200 Subject: [PATCH 4/4] docs and return type of getDeviceId() --- SI7021.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SI7021.h b/SI7021.h index a1e113d..d837e62 100644 --- a/SI7021.h +++ b/SI7021.h @@ -54,7 +54,13 @@ class SI7021 struct si7021_thc getTempAndRH(); /** Return false on timeout */ bool getSerialBytes(byte * buf, int timeout_ms = 0); - int getDeviceId(int timeout_ms = 0); + + /*Return: + * 0x0D=13=Si7013 + * 0x14=20=Si7020 + * 0x15=21=Si7021 + */ + uint8_t getDeviceId(int timeout_ms = 0); void setHeater(bool on); private: bool _command(byte cmd, byte * buf, int timeout_ms = 0 );