Skip to content

Commit

Permalink
Merge pull request #6 from hoffmannjan/master
Browse files Browse the repository at this point in the history
code cleanup + doxygen + readme
  • Loading branch information
siddacious committed Apr 19, 2019
2 parents 0d33274 + bc3a63d commit f0f80ad
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 119 deletions.
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
*~
Doxyfile*
doxygen_sqlite3.db
html
html# osx
.DS_Store

# doxygen
Doxyfile*
doxygen_sqlite3.db
html
*.tmp
208 changes: 105 additions & 103 deletions Adafruit_SGP30.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,169 +25,164 @@
*
*/


#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Arduino.h"

#include "Adafruit_SGP30.h"

//#define I2C_DEBUG

/**************************************************************************/
/*!
@brief Instantiates a new SGP30 class
*/
/**************************************************************************/
Adafruit_SGP30::Adafruit_SGP30() {
}
/*!
* @brief Instantiates a new SGP30 class
*/
Adafruit_SGP30::Adafruit_SGP30() {}

/**************************************************************************/
/*!
@brief Setups the hardware and detects a valid SGP30. Initializes I2C
then reads the serialnumber and checks that we are talking to an SGP30
@param theWire Optional pointer to I2C interface, otherwise use Wire
@returns True if SGP30 found on I2C, False if something went wrong!
*/
/**************************************************************************/
/*!
* @brief Setups the hardware and detects a valid SGP30. Initializes I2C
* then reads the serialnumber and checks that we are talking to an
* SGP30
* @param theWire
* Optional pointer to I2C interface, otherwise use Wire
* @return True if SGP30 found on I2C, False if something went wrong!
*/
boolean Adafruit_SGP30::begin(TwoWire *theWire) {
_i2caddr = SGP30_I2CADDR_DEFAULT;
if (theWire == NULL) {
_i2c = &Wire;
} else {
_i2c = theWire;
}
_i2c = theWire;

_i2c->begin();


uint8_t command[2];
command[0] = 0x36;
command[1] = 0x82;
if (! readWordFromCommand(command, 2, 10, serialnumber, 3))
if (!readWordFromCommand(command, 2, 10, serialnumber, 3))
return false;

uint16_t featureset;
command[0] = 0x20;
command[1] = 0x2F;
if (! readWordFromCommand(command, 2, 10, &featureset, 1))
if (!readWordFromCommand(command, 2, 10, &featureset, 1))
return false;
//Serial.print("Featureset 0x"); Serial.println(featureset, HEX);
if (featureset != SGP30_FEATURESET)
// Serial.print("Featureset 0x"); Serial.println(featureset, HEX);
if (featureset != SGP30_FEATURESET)
return false;
if (! IAQinit())
if (!IAQinit())
return false;

return true;
}

/**************************************************************************/
/*!
@brief Commands the sensor to begin the IAQ algorithm. Must be called after startup.
@returns True if command completed successfully, false if something went wrong!
*/
/**************************************************************************/
/*!
* @brief Commands the sensor to begin the IAQ algorithm. Must be called
* after startup.
* @returns True if command completed successfully, false if something went
* wrong!
*/
boolean Adafruit_SGP30::IAQinit(void) {
uint8_t command[2];
command[0] = 0x20;
command[1] = 0x03;
return readWordFromCommand(command, 2, 10);
}

/**************************************************************************/
/*!
@brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2}
@returns True if command completed successfully, false if something went wrong!
*/
/**************************************************************************/
/*!
* @brief Commands the sensor to take a single eCO2/VOC measurement. Places
* results in {@link TVOC} and {@link eCO2}
* @return True if command completed successfully, false if something went
* wrong!
*/
boolean Adafruit_SGP30::IAQmeasure(void) {
uint8_t command[2];
command[0] = 0x20;
command[1] = 0x08;
uint16_t reply[2];
if (! readWordFromCommand(command, 2, 12, reply, 2))
if (!readWordFromCommand(command, 2, 12, reply, 2))
return false;
TVOC = reply[1];
eCO2 = reply[0];
return true;
}

/**************************************************************************/
/*!
@brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons.
@param eco2_base A pointer to a uint16_t which we will save the calibration value to
@param tvoc_base A pointer to a uint16_t which we will save the calibration value to
@returns True if command completed successfully, false if something went wrong!
*/
/**************************************************************************/
boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) {

/*!
* @brief Request baseline calibration values for both CO2 and TVOC IAQ
* calculations. Places results in parameter memory locaitons.
* @param eco2_base
* A pointer to a uint16_t which we will save the calibration
* value to
* @param tvoc_base
* A pointer to a uint16_t which we will save the calibration value to
* @return True if command completed successfully, false if something went
* wrong!
*/
boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base,
uint16_t *tvoc_base) {
uint8_t command[2];
command[0] = 0x20;
command[1] = 0x15;
uint16_t reply[2];
if (! readWordFromCommand(command, 2, 10, reply, 2))
if (!readWordFromCommand(command, 2, 10, reply, 2))
return false;
*eco2_base = reply[0];
*tvoc_base = reply[1];
return true;
}

/**************************************************************************/
/*!
@brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations.
@param eco2_base A uint16_t which we will save the calibration value from
@param tvoc_base A uint16_t which we will save the calibration value from
@returns True if command completed successfully, false if something went wrong!
*/
/**************************************************************************/
/*!
* @brief Assign baseline calibration values for both CO2 and TVOC IAQ
* calculations.
* @param eco2_base
* A uint16_t which we will save the calibration value from
* @param tvoc_base
* A uint16_t which we will save the calibration value from
* @return True if command completed successfully, false if something went
* wrong!
*/
boolean Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) {
uint8_t command[8];
command[0] = 0x20;
command[1] = 0x1e;
command[2] = tvoc_base >> 8;
command[3] = tvoc_base & 0xFF;
command[4] = generateCRC(command+2, 2);
command[4] = generateCRC(command + 2, 2);
command[5] = eco2_base >> 8;
command[6] = eco2_base & 0xFF;
command[7] = generateCRC(command+5, 2);
command[7] = generateCRC(command + 5, 2);

return readWordFromCommand(command, 8, 10);
}

/**************************************************************************/
/*!
@brief Set the absolute humidity value [mg/m^3] for compensation to increase precision of TVOC and eCO2.
@param absolute_humidity A uint32_t [mg/m^3] which we will be used for compensation. If the absolute humidity is set to zero, humidity compensation will be disabled.
@returns True if command completed successfully, false if something went wrong!
*/
/**************************************************************************/
* @brief Set the absolute humidity value [mg/m^3] for compensation to increase
* precision of TVOC and eCO2.
* @param absolute_humidity
* A uint32_t [mg/m^3] which we will be used for compensation.
* If the absolute humidity is set to zero, humidity compensation
* will be disabled.
* @return True if command completed successfully, false if something went
* wrong!
*/
boolean Adafruit_SGP30::setHumidity(uint32_t absolute_humidity) {
if (absolute_humidity > 256000) {
return false;
}

uint16_t ah_scaled = (uint16_t)(((uint64_t)absolute_humidity * 256 * 16777) >> 24);
uint16_t ah_scaled =
(uint16_t)(((uint64_t)absolute_humidity * 256 * 16777) >> 24);
uint8_t command[5];
command[0] = 0x20;
command[1] = 0x61;
command[2] = ah_scaled >> 8;
command[3] = ah_scaled & 0xFF;
command[4] = generateCRC(command+2, 2);
command[4] = generateCRC(command + 2, 2);

return readWordFromCommand(command, 5, 10);
}

/**************************************************************************/
/*!
@brief I2C low level interfacing
*/
/**************************************************************************/

/*!
* @brief I2C low level interfacing
*/

boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delayms, uint16_t *readdata, uint8_t readlen)
{
boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[],
uint8_t commandLength,
uint16_t delayms,
uint16_t *readdata,
uint8_t readlen) {
uint8_t data;

_i2c->beginTransmission(_i2caddr);
Expand All @@ -196,10 +191,12 @@ boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLe
Serial.print("\t\t-> ");
#endif

for (uint8_t i=0; i<commandLength; i++) {
for (uint8_t i = 0; i < commandLength; i++) {
_i2c->write(command[i]);
#ifdef I2C_DEBUG
Serial.print("0x"); Serial.print(command[i], HEX); Serial.print(", ");
Serial.print("0x");
Serial.print(command[i], HEX);
Serial.print(", ");
#endif
}
#ifdef I2C_DEBUG
Expand All @@ -209,41 +206,46 @@ boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLe

delay(delayms);

if (readlen == 0)
if (readlen == 0)
return true;

uint8_t replylen = readlen * (SGP30_WORD_LEN +1);
if (_i2c->requestFrom(_i2caddr, replylen) != replylen)
uint8_t replylen = readlen * (SGP30_WORD_LEN + 1);
if (_i2c->requestFrom(_i2caddr, replylen) != replylen)
return false;
uint8_t replybuffer[replylen];
#ifdef I2C_DEBUG
Serial.print("\t\t<- ");
#endif
for (uint8_t i=0; i<replylen; i++) {
#endif
for (uint8_t i = 0; i < replylen; i++) {
replybuffer[i] = _i2c->read();
#ifdef I2C_DEBUG
Serial.print("0x"); Serial.print(replybuffer[i], HEX); Serial.print(", ");
Serial.print("0x");
Serial.print(replybuffer[i], HEX);
Serial.print(", ");
#endif
}

#ifdef I2C_DEBUG
Serial.println();
#endif

for (uint8_t i=0; i<readlen; i++) {
uint8_t crc = generateCRC(replybuffer+i*3, 2);
for (uint8_t i = 0; i < readlen; i++) {
uint8_t crc = generateCRC(replybuffer + i * 3, 2);
#ifdef I2C_DEBUG
Serial.print("\t\tCRC calced: 0x"); Serial.print(crc, HEX);
Serial.print(" vs. 0x"); Serial.println(replybuffer[i * 3 + 2], HEX);
Serial.print("\t\tCRC calced: 0x");
Serial.print(crc, HEX);
Serial.print(" vs. 0x");
Serial.println(replybuffer[i * 3 + 2], HEX);
#endif
if (crc != replybuffer[i * 3 + 2])
return false;
// success! store it
readdata[i] = replybuffer[i*3];
readdata[i] = replybuffer[i * 3];
readdata[i] <<= 8;
readdata[i] |= replybuffer[i*3 + 1];
readdata[i] |= replybuffer[i * 3 + 1];
#ifdef I2C_DEBUG
Serial.print("\t\tRead: 0x"); Serial.println(readdata[i], HEX);
Serial.print("\t\tRead: 0x");
Serial.println(readdata[i], HEX);
#endif
}
return true;
Expand All @@ -253,13 +255,13 @@ uint8_t Adafruit_SGP30::generateCRC(uint8_t *data, uint8_t datalen) {
// calculates 8-Bit checksum with given polynomial
uint8_t crc = SGP30_CRC8_INIT;

for (uint8_t i=0; i<datalen; i++) {
for (uint8_t i = 0; i < datalen; i++) {
crc ^= data[i];
for (uint8_t b=0; b<8; b++) {
for (uint8_t b = 0; b < 8; b++) {
if (crc & 0x80)
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL;
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL;
else
crc <<= 1;
crc <<= 1;
}
}
return crc;
Expand Down
21 changes: 8 additions & 13 deletions Adafruit_SGP30.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,28 @@
#define SGP30_CRC8_INIT 0xFF ///< Init value for CRC
#define SGP30_WORD_LEN 2 ///< 2 bytes per word

/**************************************************************************/
/*! Class that stores state and functions for interacting with SGP30 Gas Sensor */
/**************************************************************************/
/*!
* @brief Class that stores state and functions for interacting with
* SGP30 Gas Sensor
*/
class Adafruit_SGP30 {
public:
Adafruit_SGP30();
boolean begin(TwoWire *theWire = NULL);
boolean begin(TwoWire *theWire = &Wire);
boolean IAQinit(void);
boolean IAQmeasure(void);

boolean getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base);
boolean setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base);
boolean setHumidity(uint32_t absolute_humidity);

/**
* The last measurement of the IAQ-calculated Total Volatile Organic Compounds in ppb. This value is set when you call {@link IAQmeasure()}
*/
/** The last measurement of the IAQ-calculated Total Volatile Organic Compounds in ppb. This value is set when you call {@link IAQmeasure()} **/
uint16_t TVOC;

/**
* The last measurement of the IAQ-calculated equivalent CO2 in ppm. This value is set when you call {@link IAQmeasure()}
*/
/** The last measurement of the IAQ-calculated equivalent CO2 in ppm. This value is set when you call {@link IAQmeasure()} **/
uint16_t eCO2;

/**
* The 48-bit serial number, this value is set when you call {@link begin()}
*/
/** The 48-bit serial number, this value is set when you call {@link begin()} **/
uint16_t serialnumber[3];
private:
TwoWire *_i2c;
Expand Down

0 comments on commit f0f80ad

Please sign in to comment.