From 66679515053d907c7cd81234121a0bcb106df197 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Sat, 6 Jun 2020 22:35:41 +0200 Subject: [PATCH 01/10] Working sample --- lib/LOLIN_HP303B/README.md | 4 + .../i2c_background/i2c_background.ino | 98 + .../examples/i2c_command/i2c_command.ino | 75 + .../examples/i2c_interrupt/i2c_interrupt.ino | 112 ++ lib/LOLIN_HP303B/keywords.txt | 26 + lib/LOLIN_HP303B/library.properties | 9 + lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp | 1668 +++++++++++++++++ lib/LOLIN_HP303B/src/LOLIN_HP303B.h | 144 ++ lib/LOLIN_HP303B/src/util/hp303b_consts.h | 258 +++ tasmota/support_features.ino | 4 +- tasmota/xsns_73_hp303b.ino | 161 ++ tools/decode-status.py | 2 +- 12 files changed, 2559 insertions(+), 2 deletions(-) create mode 100644 lib/LOLIN_HP303B/README.md create mode 100644 lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino create mode 100644 lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino create mode 100644 lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino create mode 100644 lib/LOLIN_HP303B/keywords.txt create mode 100644 lib/LOLIN_HP303B/library.properties create mode 100644 lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp create mode 100644 lib/LOLIN_HP303B/src/LOLIN_HP303B.h create mode 100644 lib/LOLIN_HP303B/src/util/hp303b_consts.h create mode 100644 tasmota/xsns_73_hp303b.ino diff --git a/lib/LOLIN_HP303B/README.md b/lib/LOLIN_HP303B/README.md new file mode 100644 index 000000000..24d6c2d1b --- /dev/null +++ b/lib/LOLIN_HP303B/README.md @@ -0,0 +1,4 @@ +# Arduino library for the HP303B +### Installation +- Clone this repository or download&unzip [zip file](https://github.com/wemos/LOLIN_HP303B_Library/archive/master.zip) into Arduino/libraries + diff --git a/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino b/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino new file mode 100644 index 000000000..1b9ae6e68 --- /dev/null +++ b/lib/LOLIN_HP303B/examples/i2c_background/i2c_background.ino @@ -0,0 +1,98 @@ +#include + +// HP303B Opject +LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B(); + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + //Call begin to initialize HP303BPressureSensor + //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given. + //HP303BPressureSensor.begin(Wire, 0x76); + //Use the commented line below instead to use the default I2C address. + HP303BPressureSensor.begin(); + + //temperature measure rate (value from 0 to 7) + //2^temp_mr temperature measurement results per second + int16_t temp_mr = 2; + //temperature oversampling rate (value from 0 to 7) + //2^temp_osr internal temperature measurements per result + //A higher value increases precision + int16_t temp_osr = 2; + //pressure measure rate (value from 0 to 7) + //2^prs_mr pressure measurement results per second + int16_t prs_mr = 2; + //pressure oversampling rate (value from 0 to 7) + //2^prs_osr internal pressure measurements per result + //A higher value increases precision + int16_t prs_osr = 2; + //startMeasureBothCont enables background mode + //temperature and pressure ar measured automatically + //High precision and hgh measure rates at the same time are not available. + //Consult Datasheet (or trial and error) for more information + int16_t ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr); + //Use one of the commented lines below instead to measure only temperature or pressure + //int16_t ret = HP303BPressureSensor.startMeasureTempCont(temp_mr, temp_osr); + //int16_t ret = HP303BPressureSensor.startMeasurePressureCont(prs_mr, prs_osr); + + + if (ret != 0) + { + Serial.print("Init FAILED! ret = "); + Serial.println(ret); + } + else + { + Serial.println("Init complete!"); + } +} + + + +void loop() +{ + unsigned char pressureCount = 20; + int32_t pressure[pressureCount]; + unsigned char temperatureCount = 20; + int32_t temperature[temperatureCount]; + + //This function writes the results of continuous measurements to the arrays given as parameters + //The parameters temperatureCount and pressureCount should hold the sizes of the arrays temperature and pressure when the function is called + //After the end of the function, temperatureCount and pressureCount hold the numbers of values written to the arrays + //Note: The HP303B cannot save more than 32 results. When its result buffer is full, it won't save any new measurement results + int16_t ret = HP303BPressureSensor.getContResults(temperature, temperatureCount, pressure, pressureCount); + + if (ret != 0) + { + Serial.println(); + Serial.println(); + Serial.print("FAIL! ret = "); + Serial.println(ret); + } + else + { + Serial.println(); + Serial.println(); + Serial.print(temperatureCount); + Serial.println(" temperature values found: "); + for (int16_t i = 0; i < temperatureCount; i++) + { + Serial.print(temperature[i]); + Serial.println(" degrees of Celsius"); + } + + Serial.println(); + Serial.print(pressureCount); + Serial.println(" pressure values found: "); + for (int16_t i = 0; i < pressureCount; i++) + { + Serial.print(pressure[i]); + Serial.println(" Pascal"); + } + } + + //Wait some time, so that the HP303B can refill its buffer + delay(10000); +} diff --git a/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino b/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino new file mode 100644 index 000000000..e629f7d5f --- /dev/null +++ b/lib/LOLIN_HP303B/examples/i2c_command/i2c_command.ino @@ -0,0 +1,75 @@ +#include + +// HP303B Opject +LOLIN_HP303B HP303BPressureSensor; + + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + + //Call begin to initialize HP303BPressureSensor + //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given. + //HP303BPressureSensor.begin(Wire, 0x76); + //Use the commented line below instead of the one above to use the default I2C address. + //if you are using the Pressure 3 click Board, you need 0x76 + HP303BPressureSensor.begin(); + + Serial.println("Init complete!"); +} + + + +void loop() +{ + int32_t temperature; + int32_t pressure; + int16_t oversampling = 7; + int16_t ret; + Serial.println(); + + //lets the HP303B perform a Single temperature measurement with the last (or standard) configuration + //The result will be written to the paramerter temperature + //ret = HP303BPressureSensor.measureTempOnce(temperature); + //the commented line below does exactly the same as the one above, but you can also config the precision + //oversampling can be a value from 0 to 7 + //the HP303B will perform 2^oversampling internal temperature measurements and combine them to one result with higher precision + //measurements with higher precision take more time, consult datasheet for more information + ret = HP303BPressureSensor.measureTempOnce(temperature, oversampling); + + if (ret != 0) + { + //Something went wrong. + //Look at the library code for more information about return codes + Serial.print("FAIL! ret = "); + Serial.println(ret); + } + else + { + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" degrees of Celsius"); + } + + //Pressure measurement behaves like temperature measurement + //ret = HP303BPressureSensor.measurePressureOnce(pressure); + ret = HP303BPressureSensor.measurePressureOnce(pressure, oversampling); + if (ret != 0) + { + //Something went wrong. + //Look at the library code for more information about return codes + Serial.print("FAIL! ret = "); + Serial.println(ret); + } + else + { + Serial.print("Pressure: "); + Serial.print(pressure); + Serial.println(" Pascal"); + } + + //Wait some time + delay(500); +} diff --git a/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino b/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino new file mode 100644 index 000000000..d1221109b --- /dev/null +++ b/lib/LOLIN_HP303B/examples/i2c_interrupt/i2c_interrupt.ino @@ -0,0 +1,112 @@ +#include + +// HP303B Opject +LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B(); + +void onFifoFull(); + +const unsigned char pressureLength = 50; +unsigned char pressureCount = 0; +int32_t pressure[pressureLength]; +unsigned char temperatureCount = 0; +const unsigned char temperatureLength = 50; +int32_t temperature[temperatureLength]; + + + +void setup() +{ + Serial.begin(115200); + while (!Serial); + + //Call begin to initialize HP303BPressureSensor + //The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given. + //HP303BPressureSensor.begin(Wire, 0x76); + //Use the commented line below instead to use the default I2C address. + HP303BPressureSensor.begin(); + + int16_t ret = HP303BPressureSensor.setInterruptPolarity(1); + ret = HP303BPressureSensor.setInterruptSources(1, 0, 0); + //clear interrupt flag by reading + HP303BPressureSensor.getIntStatusFifoFull(); + + //initialization of Interrupt for Controller unit + //SDO pin of HP303B has to be connected with interrupt pin + int16_t interruptPin = 3; + pinMode(interruptPin, INPUT); + attachInterrupt(digitalPinToInterrupt(interruptPin), onFifoFull, RISING); + + //start of a continuous measurement just like before + int16_t temp_mr = 3; + int16_t temp_osr = 2; + int16_t prs_mr = 1; + int16_t prs_osr = 3; + ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr); + if (ret != 0) + { + Serial.print("Init FAILED! ret = "); + Serial.println(ret); + } + else + { + Serial.println("Init complete!"); + } +} + + +void loop() +{ + //do other stuff + Serial.println("loop running"); + delay(500); + + + //if result arrays are full + //This could also be in the interrupt handler, but it would take too much time for a proper ISR + if (pressureCount == pressureLength && temperatureCount == temperatureLength) + { + //print results + Serial.println(); + Serial.println(); + Serial.print(temperatureCount); + Serial.println(" temperature values found: "); + for (int16_t i = 0; i < temperatureCount; i++) + { + Serial.print(temperature[i]); + Serial.println(" degrees of Celsius"); + } + Serial.println(); + Serial.print(pressureCount); + Serial.println(" pressure values found: "); + for (int16_t i = 0; i < pressureCount; i++) + { + Serial.print(pressure[i]); + Serial.println(" Pascal"); + } + Serial.println(); + Serial.println(); + //reset result counters + pressureCount = 0; + temperatureCount = 0; + } +} + + +//interrupt handler +void onFifoFull() +{ + //message for debugging + Serial.println("Interrupt handler called"); + + //clear interrupt flag by reading + HP303BPressureSensor.getIntStatusFifoFull(); + + //calculate the number of free indexes in the result arrays + unsigned char prs_freespace = pressureLength - pressureCount; + unsigned char temp_freespace = temperatureLength - temperatureCount; + //read the results from HP303B, new results will be added at the end of the arrays + HP303BPressureSensor.getContResults(&temperature[temperatureCount], temp_freespace, &pressure[pressureCount], prs_freespace); + //after reading the result counters are increased by the amount of new results + pressureCount += prs_freespace; + temperatureCount += temp_freespace; +} diff --git a/lib/LOLIN_HP303B/keywords.txt b/lib/LOLIN_HP303B/keywords.txt new file mode 100644 index 000000000..b283317f5 --- /dev/null +++ b/lib/LOLIN_HP303B/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For DHT12 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DHT12 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +get KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +cTemp LITERAL1 +fTemp LITERAL1 +humidity LITERAL1 + + + diff --git a/lib/LOLIN_HP303B/library.properties b/lib/LOLIN_HP303B/library.properties new file mode 100644 index 000000000..7f71ad2b2 --- /dev/null +++ b/lib/LOLIN_HP303B/library.properties @@ -0,0 +1,9 @@ +name=LOLIN_HP303B +version=1.0.0 +author=WEMOS.CC +maintainer=WEMOS.CC +sentence=Library for the HP303B.. +paragraph=LOLIN HP303B +category=Device Control +url=https://github.com/wemos/LOLIN_HP303B_Library +architectures=* diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp new file mode 100644 index 000000000..43fcd435e --- /dev/null +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp @@ -0,0 +1,1668 @@ +#include "LOLIN_HP303B.h" + + + +const int32_t LOLIN_HP303B::scaling_facts[HP303B__NUM_OF_SCAL_FACTS] + = {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960}; + + + +//////// Constructor, Destructor, begin, end //////// + + +/** + * Standard Constructor + */ +LOLIN_HP303B::LOLIN_HP303B(void) +{ + //assume that initialization has failed before it has been done + m_initFail = 1U; +} + +/** + * Standard Destructor + */ +LOLIN_HP303B::~LOLIN_HP303B(void) +{ + end(); +} + + + +/** + * Standard I2C begin function + * + * &bus: I2CBus which connects MC to HP303B + * slaveAddress: Address of the HP303B (0x77 or 0x76) + */ +void LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress) +{ + //this flag will show if the initialization was successful + m_initFail = 0U; + + //Set I2C bus connection + m_SpiI2c = 1U; + m_i2cbus = &bus; + m_slaveAddress = slaveAddress; + + // Init bus + m_i2cbus->begin(); + + delay(50); //startup time of HP303B + + init(); +} + +void LOLIN_HP303B::begin(uint8_t slaveAddress) +{ + begin(Wire,slaveAddress); +} + +/** + * SPI begin function for HP303B with 4-wire SPI + */ +void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect) +{ + begin(bus, chipSelect, 0U); +} + +/** + * Standard SPI begin function + * + * &bus: SPI bus which connects MC to HP303B + * chipSelect: Number of the CS line for the HP303B + * threeWire: 1 if HP303B is connected with 3-wire SPI + * 0 if HP303B is connected with 4-wire SPI (standard) + */ +void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire) +{ + //this flag will show if the initialization was successful + m_initFail = 0U; + + //Set SPI bus connection + m_SpiI2c = 0U; + m_spibus = &bus; + m_chipSelect = chipSelect; + + // Init bus + m_spibus->begin(); + m_spibus->setDataMode(SPI_MODE3); + + pinMode(m_chipSelect, OUTPUT); + digitalWrite(m_chipSelect, HIGH); + + delay(50); //startup time of HP303B + + //switch to 3-wire mode if necessary + //do not use writeByteBitfield or check option to set SPI mode! + //Reading is not possible until SPI-mode is valid + if(threeWire) + { + m_threeWire = 1U; + if(writeByte(HP303B__REG_ADR_SPI3W, HP303B__REG_CONTENT_SPI3W)) + { + m_initFail = 1U; + return; + } + } + + init(); +} + +/** + * End function for HP303B + * Sets the sensor to idle mode + */ +void LOLIN_HP303B::end(void) +{ + standby(); +} + + +//////// Declaration of other public functions starts here //////// + + +/** + * returns the Product ID of the connected HP303B sensor + */ +uint8_t LOLIN_HP303B::getProductId(void) +{ + return m_productID; +} + +/** + * returns the Revision ID of the connected HP303B sensor + */ +uint8_t LOLIN_HP303B::getRevisionId(void) +{ + return m_revisionID; +} + +/** + * Sets the HP303B to standby mode + * + * returns: 0 on success + * -2 if object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::standby(void) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //set device to idling mode + int16_t ret = setOpMode(IDLE); + if(ret != HP303B__SUCCEEDED) + { + return ret; + } + //flush the FIFO + ret = writeByteBitfield(1U, HP303B__REG_INFO_FIFO_FL); + if(ret < 0) + { + return ret; + } + //disable the FIFO + ret = writeByteBitfield(0U, HP303B__REG_INFO_FIFO_EN); + return ret; +} + + +/** + * performs one temperature measurement and writes result to the given address + * + * &result: reference to a 32-Bit signed Integer value where the result will be written + * It will not be written if result==NULL + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measureTempOnce(int32_t &result) +{ + return measureTempOnce(result, m_tempOsr); +} + +/** + * performs one temperature measurement and writes result to the given address + * the desired precision can be set with oversamplingRate + * + * &result: reference to a 32-Bit signed Integer where the result will be written + * It will not be written if result==NULL + * oversamplingRate: a value from 0 to 7 that decides about the precision + * of the measurement + * If this value equals n, the HP303B will perform + * 2^n measurements and combine the results + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measureTempOnce(int32_t &result, uint8_t oversamplingRate) +{ + //Start measurement + int16_t ret = startMeasureTempOnce(oversamplingRate); + if(ret!=HP303B__SUCCEEDED) + { + return ret; + } + + //wait until measurement is finished + delay(calcBusyTime(0U, m_tempOsr)/HP303B__BUSYTIME_SCALING); + delay(HP303B__BUSYTIME_FAILSAFE); + + ret = getSingleResult(result); + if(ret!=HP303B__SUCCEEDED) + { + standby(); + } + return ret; +} + +/** + * starts a single temperature measurement + * + * returns: 0 on success + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::startMeasureTempOnce(void) +{ + return startMeasureTempOnce(m_tempOsr); +} + +/** + * starts a single temperature measurement + * The desired precision can be set with oversamplingRate + * + * oversamplingRate: a value from 0 to 7 that decides about the precision + * of the measurement + * If this value equals n, the HP303B will perform + * 2^n measurements and combine the results + * returns: 0 on success + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if(m_opMode!=IDLE) + { + return HP303B__FAIL_TOOBUSY; + } + + if(oversamplingRate!=m_tempOsr) + { + //configuration of oversampling rate + if(configTemp(0U, oversamplingRate) != HP303B__SUCCEEDED) + { + return HP303B__FAIL_UNKNOWN; + } + } + + //set device to temperature measuring mode + return setOpMode(0U, 1U, 0U); +} + +/** + * performs one pressure measurement and writes result to the given address + * + * &result: reference to a 32-Bit signed Integer value where the result will be written + * It will not be written if result==NULL + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result) +{ + return measurePressureOnce(result, m_prsOsr); +} + +/** + * performs one pressure measurement and writes result to the given address + * the desired precision can be set with oversamplingRate + * + * &result: reference to a 32-Bit signed Integer where the result will be written + * It will not be written if result==NULL + * oversamplingRate: a value from 0 to 7 that decides about the precision + * of the measurement + * If this value equals n, the HP303B will perform + * 2^n measurements and combine the results + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result, uint8_t oversamplingRate) +{ + //start the measurement + int16_t ret = startMeasurePressureOnce(oversamplingRate); + if(ret != HP303B__SUCCEEDED) + { + return ret; + } + + //wait until measurement is finished + delay(calcBusyTime(0U, m_prsOsr)/HP303B__BUSYTIME_SCALING); + delay(HP303B__BUSYTIME_FAILSAFE); + + ret = getSingleResult(result); + if(ret!=HP303B__SUCCEEDED) + { + standby(); + } + return ret; +} + +/** + * starts a single pressure measurement + * + * returns: 0 on success + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::startMeasurePressureOnce(void) +{ + return startMeasurePressureOnce(m_prsOsr); +} + +/** + * starts a single pressure measurement + * The desired precision can be set with oversamplingRate + * + * oversamplingRate: a value from 0 to 7 that decides about the precision + * of the measurement + * If this value equals n, the HP303B will perform + * 2^n measurements and combine the results + * returns: 0 on success + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if(m_opMode != IDLE) + { + return HP303B__FAIL_TOOBUSY; + } + //configuration of oversampling rate, lowest measure rate to avoid conflicts + if(oversamplingRate != m_prsOsr) + { + if(configPressure(0U, oversamplingRate)) + { + return HP303B__FAIL_UNKNOWN; + } + } + //set device to pressure measuring mode + return setOpMode(0U, 0U, 1U); +} + +/** + * gets the result a single temperature or pressure measurement in °C or Pa + * + * &result: reference to a 32-Bit signed Integer value where the result will be written + * returns: 0 on success + * -4 if the HP303B is still busy + * -3 if the HP303B is not in command mode + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::getSingleResult(int32_t &result) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + + //read finished bit for current opMode + int16_t rdy; + switch(m_opMode) + { + case CMD_TEMP: //temperature + rdy = readByteBitfield(HP303B__REG_INFO_TEMP_RDY); + break; + case CMD_PRS: //pressure + rdy = readByteBitfield(HP303B__REG_INFO_PRS_RDY); + break; + default: //HP303B not in command mode + return HP303B__FAIL_TOOBUSY; + } + + //read new measurement result + switch(rdy) + { + case HP303B__FAIL_UNKNOWN: //could not read ready flag + return HP303B__FAIL_UNKNOWN; + case 0: //ready flag not set, measurement still in progress + return HP303B__FAIL_UNFINISHED; + case 1: //measurement ready, expected case + LOLIN_HP303B::Mode oldMode = m_opMode; + m_opMode = IDLE; //opcode was automatically reseted by HP303B + switch(oldMode) + { + case CMD_TEMP: //temperature + return getTemp(&result); //get and calculate the temperature value + case CMD_PRS: //pressure + return getPressure(&result); //get and calculate the pressure value + default: + return HP303B__FAIL_UNKNOWN; //should already be filtered above + } + } + return HP303B__FAIL_UNKNOWN; +} + +/** + * starts a continuous temperature measurement + * The desired precision can be set with oversamplingRate + * The desired number of measurements per second can be set with measureRate + * + * measureRate: a value from 0 to 7 that decides about + * the number of measurements per second + * If this value equals n, the HP303B will perform + * 2^n measurements per second + * oversamplingRate: a value from 0 to 7 that decides about + * the precision of the measurements + * If this value equals m, the HP303B will perform + * 2^m internal measurements and combine the results + * to one more exact measurement + * returns: 0 on success + * -4 if measureRate or oversamplingRate is too high + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + * NOTE: If measure rate is n and oversampling rate is m, + * the HP303B performs 2^(n+m) internal measurements per second. + * The HP303B cannot operate with high precision and high speed + * at the same time. + * Consult the datasheet for more information. + */ +int16_t LOLIN_HP303B::startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if(m_opMode != IDLE) + { + return HP303B__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME) + { + return HP303B__FAIL_UNFINISHED; + } + //update precision and measuring rate + if(configTemp(measureRate, oversamplingRate)) + { + return HP303B__FAIL_UNKNOWN; + } + //enable result FIFO + if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN)) + { + return HP303B__FAIL_UNKNOWN; + } + //Start measuring in background mode + if(setOpMode(1U, 1U, 0U)) + { + return HP303B__FAIL_UNKNOWN; + } + return HP303B__SUCCEEDED; +} + + +/** + * starts a continuous temperature measurement + * The desired precision can be set with oversamplingRate + * The desired number of measurements per second can be set with measureRate + * + * measureRate: a value from 0 to 7 that decides about + * the number of measurements per second + * If this value equals n, the HP303B will perform + * 2^n measurements per second + * oversamplingRate: a value from 0 to 7 that decides about the precision + * of the measurements + * If this value equals m, the HP303B will perform + * 2^m internal measurements + * and combine the results to one more exact measurement + * returns: 0 on success + * -4 if measureRate or oversamplingRate is too high + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + * NOTE: If measure rate is n and oversampling rate is m, + * the HP303B performs 2^(n+m) internal measurements per second. + * The HP303B cannot operate with high precision and high speed + * at the same time. + * Consult the datasheet for more information. + */ +int16_t LOLIN_HP303B::startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if(m_opMode != IDLE) + { + return HP303B__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if(calcBusyTime(measureRate, oversamplingRate) >= HP303B__MAX_BUSYTIME) + { + return HP303B__FAIL_UNFINISHED; + } + //update precision and measuring rate + if(configPressure(measureRate, oversamplingRate)) + return HP303B__FAIL_UNKNOWN; + //enable result FIFO + if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN)) + { + return HP303B__FAIL_UNKNOWN; + } + //Start measuring in background mode + if(setOpMode(1U, 0U, 1U)) + { + return HP303B__FAIL_UNKNOWN; + } + return HP303B__SUCCEEDED; +} + +/** + * starts a continuous temperature and pressure measurement + * The desired precision can be set with tempOsr and prsOsr + * The desired number of measurements per second can be set with tempMr and prsMr + * + * tempMr measure rate for temperature + * tempOsr oversampling rate for temperature + * prsMr measure rate for pressure + * prsOsr oversampling rate for pressure + * returns: 0 on success + * -4 if precision or speed is too high + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + * NOTE: High precision and speed for both temperature and pressure + * can not be reached at the same time. + * Estimated time for temperature and pressure measurement + * is the sum of both values. + * This sum must not be more than 1 second. + * Consult the datasheet for more information. + */ +int16_t LOLIN_HP303B::startMeasureBothCont(uint8_t tempMr, + uint8_t tempOsr, + uint8_t prsMr, + uint8_t prsOsr) +{ + //abort if initialization failed + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if(m_opMode!=IDLE) + { + return HP303B__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if(calcBusyTime(tempMr, tempOsr) + calcBusyTime(prsMr, prsOsr)>=HP303B__MAX_BUSYTIME) + { + return HP303B__FAIL_UNFINISHED; + } + //update precision and measuring rate + if(configTemp(tempMr, tempOsr)) + { + return HP303B__FAIL_UNKNOWN; + } + //update precision and measuring rate + if(configPressure(prsMr, prsOsr)) + return HP303B__FAIL_UNKNOWN; + //enable result FIFO + if(writeByteBitfield(1U, HP303B__REG_INFO_FIFO_EN)) + { + return HP303B__FAIL_UNKNOWN; + } + //Start measuring in background mode + if(setOpMode(1U, 1U, 1U)) + { + return HP303B__FAIL_UNKNOWN; + } + return HP303B__SUCCEEDED; +} + +/** + * Gets the results from continuous measurements and writes them to given arrays + * + * *tempBuffer: The start address of the buffer where the temperature results + * are written + * If this is NULL, no temperature results will be written out + * &tempCount: This has to be a reference to a number which contains + * the size of the buffer for temperature results. + * When the function ends, it will contain + * the number of bytes written to the buffer + * *prsBuffer: The start address of the buffer where the pressure results + * are written + * If this is NULL, no pressure results will be written out + * &prsCount: This has to be a reference to a number which contains + * the size of the buffer for pressure results. + * When the function ends, it will contain + * the number of bytes written to the buffer + * returns: 0 on success + * -3 if HP303B is not in background mode + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::getContResults(int32_t *tempBuffer, + uint8_t &tempCount, + int32_t *prsBuffer, + uint8_t &prsCount) +{ + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + //abort if device is not in background mode + if(!(m_opMode & INVAL_OP_CONT_NONE)) + { + return HP303B__FAIL_TOOBUSY; + } + + //prepare parameters for buffer length and count + uint8_t tempLen = tempCount; + uint8_t prsLen = prsCount; + tempCount = 0U; + prsCount = 0U; + + //while FIFO is not empty + while(readByteBitfield(HP303B__REG_INFO_FIFO_EMPTY) == 0) + { + int32_t result; + //read next result from FIFO + int16_t type = getFIFOvalue(&result); + switch(type) + { + case 0: //temperature + //calculate compensated pressure value + result = calcTemp(result); + //if buffer exists and is not full + //write result to buffer and increase temperature result counter + if(tempBuffer != NULL) + { + if(tempCount> HP303B__REG_SHIFT_INT_EN_FIFO; + tempReady &= HP303B__REG_MASK_INT_EN_TEMP >> HP303B__REG_SHIFT_INT_EN_TEMP; + prsReady &= HP303B__REG_MASK_INT_EN_PRS >> HP303B__REG_SHIFT_INT_EN_PRS; + //read old value from register + int16_t regData = readByte(HP303B__REG_ADR_INT_EN_FIFO); + if(regData <0) + { + return HP303B__FAIL_UNKNOWN; + } + uint8_t toWrite = (uint8_t)regData; + //update FIFO enable bit + toWrite &= ~HP303B__REG_MASK_INT_EN_FIFO; //clear bit + toWrite |= fifoFull << HP303B__REG_SHIFT_INT_EN_FIFO; //set new bit + //update TempReady enable bit + toWrite &= ~HP303B__REG_MASK_INT_EN_TEMP; + toWrite |= tempReady << HP303B__REG_SHIFT_INT_EN_TEMP; + //update PrsReady enable bit + toWrite &= ~HP303B__REG_MASK_INT_EN_PRS; + toWrite |= prsReady << HP303B__REG_SHIFT_INT_EN_PRS; + //write updated value to register + return writeByte(HP303B__REG_ADR_INT_EN_FIFO, toWrite); +} + +/** + * Gets the interrupt status flag of the FIFO + * + * Returns: 1 if the FIFO is full and caused an interrupt + * 0 if the FIFO is not full or FIFO interrupt is disabled + * -1 on fail + */ +int16_t LOLIN_HP303B::getIntStatusFifoFull(void) +{ + return readByteBitfield(HP303B__REG_INFO_INT_FLAG_FIFO); +} + +/** + * Gets the interrupt status flag that indicates a finished temperature measurement + * + * Returns: 1 if a finished temperature measurement caused an interrupt + * 0 if there is no finished temperature measurement + * or interrupts are disabled + * -1 on fail + */ +int16_t LOLIN_HP303B::getIntStatusTempReady(void) +{ + return readByteBitfield(HP303B__REG_INFO_INT_FLAG_TEMP); +} + +/** + * Gets the interrupt status flag that indicates a finished pressure measurement + * + * Returns: 1 if a finished pressure measurement caused an interrupt + * 0 if there is no finished pressure measurement + * or interrupts are disabled + * -1 on fail + */ +int16_t LOLIN_HP303B::getIntStatusPrsReady(void) +{ + return readByteBitfield(HP303B__REG_INFO_INT_FLAG_PRS); +} + +/** + * Function to fix a hardware problem on some devices + * You have this problem if you measure a temperature which is too high (e.g. 60°C when temperature is around 20°C) + * Call correctTemp() directly after begin() to fix this issue + */ +int16_t LOLIN_HP303B::correctTemp(void) +{ + if(m_initFail) + { + return HP303B__FAIL_INIT_FAILED; + } + writeByte(0x0E, 0xA5); + writeByte(0x0F, 0x96); + writeByte(0x62, 0x02); + writeByte(0x0E, 0x00); + writeByte(0x0F, 0x00); + + //perform a first temperature measurement (again) + //the most recent temperature will be saved internally + //and used for compensation when calculating pressure + int32_t trash; + measureTempOnce(trash); + + return HP303B__SUCCEEDED; +} + + + +//////// Declaration of private functions starts here //////// + + +/** + * Initializes the sensor. + * This function has to be called from begin() + * and requires a valid bus initialization. + */ +void LOLIN_HP303B::init(void) +{ + int16_t prodId = readByteBitfield(HP303B__REG_INFO_PROD_ID); + if(prodId != HP303B__PROD_ID) + { + //Connected device is not a HP303B + m_initFail = 1U; + return; + } + m_productID = prodId; + + int16_t revId = readByteBitfield(HP303B__REG_INFO_REV_ID); + if(revId < 0) + { + m_initFail = 1U; + return; + } + m_revisionID = revId; + + //find out which temperature sensor is calibrated with coefficients... + int16_t sensor = readByteBitfield(HP303B__REG_INFO_TEMP_SENSORREC); + if(sensor < 0) + { + m_initFail = 1U; + return; + } + + //...and use this sensor for temperature measurement + m_tempSensor = sensor; + if(writeByteBitfield((uint8_t)sensor, HP303B__REG_INFO_TEMP_SENSOR) < 0) + { + m_initFail = 1U; + return; + } + + //read coefficients + if(readcoeffs() < 0) + { + m_initFail = 1U; + return; + } + + //set to standby for further configuration + standby(); + + //set measurement precision and rate to standard values; + configTemp(HP303B__TEMP_STD_MR, HP303B__TEMP_STD_OSR); + configPressure(HP303B__PRS_STD_MR, HP303B__PRS_STD_OSR); + + //perform a first temperature measurement + //the most recent temperature will be saved internally + //and used for compensation when calculating pressure + int32_t trash; + measureTempOnce(trash); + + //make sure the HP303B is in standby after initialization + standby(); + + // Fix IC with a fuse bit problem, which lead to a wrong temperature + // Should not affect ICs without this problem + correctTemp(); +} + + +/** + * reads the compensation coefficients from the HP303B + * this is called once from init(), which is called from begin() + * + * returns: 0 on success, -1 on fail + */ +int16_t LOLIN_HP303B::readcoeffs(void) +{ + uint8_t buffer[HP303B__REG_LEN_COEF]; + //read COEF registers to buffer + int16_t ret = readBlock(HP303B__REG_ADR_COEF, + HP303B__REG_LEN_COEF, + buffer); + //abort if less than REG_LEN_COEF bytes were read + if(ret < HP303B__REG_LEN_COEF) + { + return HP303B__FAIL_UNKNOWN; + } + + //compose coefficients from buffer content + m_c0Half = ((uint32_t)buffer[0] << 4) + | (((uint32_t)buffer[1] >> 4) & 0x0F); + //this construction recognizes non-32-bit negative numbers + //and converts them to 32-bit negative numbers with 2's complement + if(m_c0Half & ((uint32_t)1 << 11)) + { + m_c0Half -= (uint32_t)1 << 12; + } + //c0 is only used as c0*0.5, so c0_half is calculated immediately + m_c0Half = m_c0Half / 2U; + + //now do the same thing for all other coefficients + m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2]; + if(m_c1 & ((uint32_t)1 << 11)) + { + m_c1 -= (uint32_t)1 << 12; + } + + m_c00 = ((uint32_t)buffer[3] << 12) + | ((uint32_t)buffer[4] << 4) + | (((uint32_t)buffer[5] >> 4) & 0x0F); + if(m_c00 & ((uint32_t)1 << 19)) + { + m_c00 -= (uint32_t)1 << 20; + } + + m_c10 = (((uint32_t)buffer[5] & 0x0F) << 16) + | ((uint32_t)buffer[6] << 8) + | (uint32_t)buffer[7]; + if(m_c10 & ((uint32_t)1<<19)) + { + m_c10 -= (uint32_t)1 << 20; + } + + m_c01 = ((uint32_t)buffer[8] << 8) + | (uint32_t)buffer[9]; + if(m_c01 & ((uint32_t)1 << 15)) + { + m_c01 -= (uint32_t)1 << 16; + } + + m_c11 = ((uint32_t)buffer[10] << 8) + | (uint32_t)buffer[11]; + if(m_c11 & ((uint32_t)1 << 15)) + { + m_c11 -= (uint32_t)1 << 16; + } + + m_c20 = ((uint32_t)buffer[12] << 8) + | (uint32_t)buffer[13]; + if(m_c20 & ((uint32_t)1 << 15)) + { + m_c20 -= (uint32_t)1 << 16; + } + + m_c21 = ((uint32_t)buffer[14] << 8) + | (uint32_t)buffer[15]; + if(m_c21 & ((uint32_t)1 << 15)) + { + m_c21 -= (uint32_t)1 << 16; + } + + m_c30 = ((uint32_t)buffer[16] << 8) + | (uint32_t)buffer[17]; + if(m_c30 & ((uint32_t)1 << 15)) + { + m_c30 -= (uint32_t)1 << 16; + } + + return HP303B__SUCCEEDED; +} + +/** + * Sets the Operation Mode of the HP303B + * + * background: determines the general behavior of the HP303B + * 0 enables command mode (only measure on commands) + * 1 enables background mode (continuous work in background) + * temperature: set 1 to measure temperature + * pressure: set 1 to measure pressure + * return: 0 on success, -1 on fail + * + * NOTE! + * You cannot set background to 1 without setting temperature and pressure + * You cannot set both temperature and pressure when background mode is disabled + */ +int16_t LOLIN_HP303B::setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure) +{ + uint8_t opMode = (background & HP303B__LSB) << 2U + | (temperature & HP303B__LSB) << 1U + | (pressure & HP303B__LSB); + return setOpMode(opMode); +} + + +/** + * Sets the Operation Mode of the HP303B + * + * opMode: the new OpMode that has to be set + * return: 0 on success, -1 on fail + * + * NOTE! + * You cannot set background to 1 without setting temperature and pressure + * You cannot set both temperature and pressure when background mode is disabled + */ +int16_t LOLIN_HP303B::setOpMode(uint8_t opMode) +{ + //Filter irrelevant bits + opMode &= HP303B__REG_MASK_OPMODE >> HP303B__REG_SHIFT_OPMODE; + //Filter invalid OpModes + if(opMode == INVAL_OP_CMD_BOTH || opMode == INVAL_OP_CONT_NONE) + { + return HP303B__FAIL_UNKNOWN; + } + //Set OpMode + if(writeByte(HP303B__REG_ADR_OPMODE, opMode)) + { + return HP303B__FAIL_UNKNOWN; + } + m_opMode = (LOLIN_HP303B::Mode)opMode; + return HP303B__SUCCEEDED; +} + +/** + * Configures temperature measurement + * + * tempMr: the new measure rate for temperature + * This can be a value from 0U to 7U. + * Actual measure rate will be 2^tempMr, + * so this will be a value from 1 to 128. + * tempOsr: the new oversampling rate for temperature + * This can be a value from 0U to 7U. + * Actual measure rate will be 2^tempOsr, + * so this will be a value from 1 to 128. + * returns: 0 normally or -1 on fail + */ +int16_t LOLIN_HP303B::configTemp(uint8_t tempMr, uint8_t tempOsr) +{ + //mask parameters + tempMr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR; + tempOsr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR; + + //set config register according to parameters + uint8_t toWrite = tempMr << HP303B__REG_SHIFT_TEMP_MR; + toWrite |= tempOsr << HP303B__REG_SHIFT_TEMP_OSR; + //using recommended temperature sensor + toWrite |= HP303B__REG_MASK_TEMP_SENSOR + & (m_tempSensor << HP303B__REG_SHIFT_TEMP_SENSOR); + int16_t ret = writeByte(HP303B__REG_ADR_TEMP_MR, toWrite); + //abort immediately on fail + if(ret != HP303B__SUCCEEDED) + { + return HP303B__FAIL_UNKNOWN; + } + + //set TEMP SHIFT ENABLE if oversampling rate higher than eight(2^3) + if(tempOsr > HP303B__OSR_SE) + { + ret=writeByteBitfield(1U, HP303B__REG_INFO_TEMP_SE); + } + else + { + ret=writeByteBitfield(0U, HP303B__REG_INFO_TEMP_SE); + } + + if(ret == HP303B__SUCCEEDED) + { //save new settings + m_tempMr = tempMr; + m_tempOsr = tempOsr; + } + else + { + //try to rollback on fail avoiding endless recursion + //this is to make sure that shift enable and oversampling rate + //are always consistent + if(tempMr != m_tempMr || tempOsr != m_tempOsr) + { + configTemp(m_tempMr, m_tempOsr); + } + } + return ret; +} + +/** + * Configures pressure measurement + * + * prsMr: the new measure rate for pressure + * This can be a value from 0U to 7U. + * Actual measure rate will be 2^prs_mr, + * so this will be a value from 1 to 128. + * prsOs: the new oversampling rate for temperature + * This can be a value from 0U to 7U. + * Actual measure rate will be 2^prsOsr, + * so this will be a value from 1 to 128. + * returns: 0 normally or -1 on fail + */ +int16_t LOLIN_HP303B::configPressure(uint8_t prsMr, uint8_t prsOsr) +{ + //mask parameters + prsMr &= HP303B__REG_MASK_PRS_MR >> HP303B__REG_SHIFT_PRS_MR; + prsOsr &= HP303B__REG_MASK_PRS_OSR >> HP303B__REG_SHIFT_PRS_OSR; + + //set config register according to parameters + uint8_t toWrite = prsMr << HP303B__REG_SHIFT_PRS_MR; + toWrite |= prsOsr << HP303B__REG_SHIFT_PRS_OSR; + int16_t ret = writeByte(HP303B__REG_ADR_PRS_MR, toWrite); + //abort immediately on fail + if(ret != HP303B__SUCCEEDED) + { + return HP303B__FAIL_UNKNOWN; + } + + //set PM SHIFT ENABLE if oversampling rate higher than eight(2^3) + if(prsOsr > HP303B__OSR_SE) + { + ret = writeByteBitfield(1U, HP303B__REG_INFO_PRS_SE); + } + else + { + ret = writeByteBitfield(0U, HP303B__REG_INFO_PRS_SE); + } + + if(ret == HP303B__SUCCEEDED) + { //save new settings + m_prsMr = prsMr; + m_prsOsr = prsOsr; + } + else + { //try to rollback on fail avoiding endless recursion + //this is to make sure that shift enable and oversampling rate + //are always consistent + if(prsMr != m_prsMr || prsOsr != m_prsOsr) + { + configPressure(m_prsMr, m_prsOsr); + } + } + return ret; +} + +/** + * calculates the time that the HP303B needs for 2^mr measurements + * with an oversampling rate of 2^osr + * + * mr: Measure rate for temperature or pressure + * osr: Oversampling rate for temperature or pressure + * returns: time that the HP303B needs for this measurement + * a value of 10000 equals 1 second + * NOTE! The measurement time for temperature and pressure + * in sum must not be more than 1 second! + * Timing behavior of pressure and temperature sensors + * can be considered as equal. + */ +uint16_t LOLIN_HP303B::calcBusyTime(uint16_t mr, uint16_t osr) +{ + //mask parameters first + mr &= HP303B__REG_MASK_TEMP_MR >> HP303B__REG_SHIFT_TEMP_MR; + osr &= HP303B__REG_MASK_TEMP_OSR >> HP303B__REG_SHIFT_TEMP_OSR; + //formula from datasheet (optimized) + return ((uint32_t)20U << mr) + ((uint32_t)16U << (osr + mr)); +} + +/** + * Gets the next temperature measurement result in degrees of Celsius + * + * result: address where the result will be written + * returns: 0 on success + * -1 on fail; + */ +int16_t LOLIN_HP303B::getTemp(int32_t *result) +{ + uint8_t buffer[3] = {0}; + //read raw pressure data to buffer + + int16_t i = readBlock(HP303B__REG_ADR_TEMP, + HP303B__REG_LEN_TEMP, + buffer); + if(i != HP303B__REG_LEN_TEMP) + { + //something went wrong + return HP303B__FAIL_UNKNOWN; + } + + //compose raw temperature value from buffer + int32_t temp = (uint32_t)buffer[0] << 16 + | (uint32_t)buffer[1] << 8 + | (uint32_t)buffer[2]; + //recognize non-32-bit negative numbers + //and convert them to 32-bit negative numbers using 2's complement + if(temp & ((uint32_t)1 << 23)) + { + temp -= (uint32_t)1 << 24; + } + + //return temperature + *result = calcTemp(temp); + return HP303B__SUCCEEDED; +} + +/** + * Gets the next pressure measurement result in Pa + * + * result: address where the result will be written + * returns: 0 on success + * -1 on fail; + */ +int16_t LOLIN_HP303B::getPressure(int32_t *result) +{ + uint8_t buffer[3] = {0}; + //read raw pressure data to buffer + int16_t i = readBlock(HP303B__REG_ADR_PRS, + HP303B__REG_LEN_PRS, + buffer); + if(i != HP303B__REG_LEN_PRS) + { + //something went wrong + //negative pressure is not allowed + return HP303B__FAIL_UNKNOWN; + } + + //compose raw pressure value from buffer + int32_t prs = (uint32_t)buffer[0] << 16 + | (uint32_t)buffer[1] << 8 + | (uint32_t)buffer[2]; + //recognize non-32-bit negative numbers + //and convert them to 32-bit negative numbers using 2's complement + if(prs & ((uint32_t)1 << 23)) + { + prs -= (uint32_t)1 << 24; + } + + *result = calcPressure(prs); + return HP303B__SUCCEEDED; +} + +/** + * reads the next raw value from the HP303B FIFO + * + * value: address where the value will be written + * returns: -1 on fail + * 0 if result is a temperature raw value + * 1 if result is a pressure raw value + */ +int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value) +{ + //abort on invalid argument + if(value == NULL) + { + return HP303B__FAIL_UNKNOWN; + } + + uint8_t buffer[HP303B__REG_LEN_PRS] = {0}; + //always read from pressure raw value register + int16_t i = readBlock(HP303B__REG_ADR_PRS, + HP303B__REG_LEN_PRS, + buffer); + if(i != HP303B__REG_LEN_PRS) + { + //something went wrong + //return error code + return HP303B__FAIL_UNKNOWN; + } + //compose raw pressure value from buffer + *value = (uint32_t)buffer[0] << 16 + | (uint32_t)buffer[1] << 8 + | (uint32_t)buffer[2]; + //recognize non-32-bit negative numbers + //and convert them to 32-bit negative numbers using 2's complement + if(*value & ((uint32_t)1 << 23)) + { + *value -= (uint32_t)1 << 24; + } + + //least significant bit shows measurement type + return buffer[2] & HP303B__LSB; +} + +/** + * Calculates a scaled and compensated pressure value from raw data + * raw: raw temperature value read from HP303B + * returns: temperature value in °C + */ +int32_t LOLIN_HP303B::calcTemp(int32_t raw) +{ + double temp = raw; + + //scale temperature according to scaling table and oversampling + temp /= scaling_facts[m_tempOsr]; + + //update last measured temperature + //it will be used for pressure compensation + m_lastTempScal = temp; + + //Calculate compensated temperature + temp = m_c0Half + m_c1 * temp; + + //return temperature + return (int32_t)temp; +} + +/** + * Calculates a scaled and compensated pressure value from raw data + * raw: raw pressure value read from HP303B + * returns: pressure value in Pa + */ +int32_t LOLIN_HP303B::calcPressure(int32_t raw) +{ + double prs = raw; + + //scale pressure according to scaling table and oversampling + prs /= scaling_facts[m_prsOsr]; + + //Calculate compensated pressure + prs = m_c00 + + prs * (m_c10 + prs * (m_c20 + prs * m_c30)) + + m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21)); + + //return pressure + return (int32_t)prs; +} + +/** + * reads a byte from HP303B + * + * regAdress: Address that has to be read + * returns: register content or -1 on fail + */ +int16_t LOLIN_HP303B::readByte(uint8_t regAddress) +{ + //delegate to specialized function if HP303B is connected via SPI + if(m_SpiI2c==0) + { + return readByteSPI(regAddress); + } + + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regAddress); + m_i2cbus->endTransmission(0); + //request 1 byte from slave + if(m_i2cbus->requestFrom(m_slaveAddress, 1U, 1U) > 0) + { + return m_i2cbus->read(); //return this byte on success + } + else + { + return HP303B__FAIL_UNKNOWN; //if 0 bytes were read successfully + } +} + +/** + * reads a byte from HP303B via SPI + * this function is automatically called by readByte + * if HP303B is connected via SPI + * + * regAdress: Address that has to be read + * returns: register content or -1 on fail + */ +int16_t LOLIN_HP303B::readByteSPI(uint8_t regAddress) +{ + //this function is only made for communication via SPI + if(m_SpiI2c != 0) + { + return HP303B__FAIL_UNKNOWN; + } + //mask regAddress + regAddress &= ~HP303B__SPI_RW_MASK; + //reserve and initialize bus + m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ, + MSBFIRST, + SPI_MODE3)); + //enable ChipSelect for HP303B + digitalWrite(m_chipSelect, LOW); + //send address with read command to HP303B + m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD); + //receive register content from HP303B + uint8_t ret = m_spibus->transfer(0xFF); //send a dummy byte while receiving + //disable ChipSelect for HP303B + digitalWrite(m_chipSelect, HIGH); + //close current SPI transaction + m_spibus->endTransaction(); + //return received data + return ret; +} + +/** + * reads a block from HP303B + * + * regAdress: Address that has to be read + * length: Length of data block + * buffer: Buffer where data will be stored + * returns: number of bytes that have been read successfully + * NOTE! This is not always equal to length + * due to rx-Buffer overflow etc. + */ +int16_t LOLIN_HP303B::readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer) +{ + //delegate to specialized function if HP303B is connected via SPI + if(m_SpiI2c == 0) + { + return readBlockSPI(regAddress, length, buffer); + } + //do not read if there is no buffer + if(buffer == NULL) + { + return 0; //0 bytes read successfully + } + + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regAddress); + m_i2cbus->endTransmission(0); + //request length bytes from slave + int16_t ret = m_i2cbus->requestFrom(m_slaveAddress, length, 1U); + //read all received bytes to buffer + for(int16_t count = 0; count < ret; count++) + { + buffer[count] = m_i2cbus->read(); + } + return ret; +} + +/** + * reads a block from HP303B via SPI + * + * regAdress: Address that has to be read + * length: Length of data block + * readbuffer: Buffer where data will be stored + * returns: number of bytes that have been read successfully + * NOTE! This is not always equal to length + * due to rx-Buffer overflow etc. + */ +int16_t LOLIN_HP303B::readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *buffer) +{ + //this function is only made for communication via SPI + if(m_SpiI2c != 0) + { + return HP303B__FAIL_UNKNOWN; + } + //do not read if there is no buffer + if(buffer == NULL) + { + return 0; //0 bytes were read successfully + } + //mask regAddress + regAddress &= ~HP303B__SPI_RW_MASK; + //reserve and initialize bus + m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ, + MSBFIRST, + SPI_MODE3)); + //enable ChipSelect for HP303B + digitalWrite(m_chipSelect, LOW); + //send address with read command to HP303B + m_spibus->transfer(regAddress | HP303B__SPI_READ_CMD); + + //receive register contents from HP303B + for(uint8_t count = 0; count < length; count++) + { + buffer[count] = m_spibus->transfer(0xFF);//send a dummy byte while receiving + } + + //disable ChipSelect for HP303B + digitalWrite(m_chipSelect, HIGH); + //close current SPI transaction + m_spibus->endTransaction(); + //return received data + return length; +} + +/** + * writes a given byte to a given register of HP303B without checking + * + * regAdress: Address of the register that has to be updated + * data: Byte that will be written to the register + * return: 0 if byte was written successfully + * or -1 on fail + */ +int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data) +{ + return writeByte(regAddress, data, 0U); +} + +/** + * writes a given byte to a given register of HP303B + * + * regAdress: Address of the register that has to be updated + * data: Byte that will be written to the register + * check: If this is true, register content will be read after writing + * to check if update was successful + * return: 0 if byte was written successfully + * or -1 on fail + */ +int16_t LOLIN_HP303B::writeByte(uint8_t regAddress, uint8_t data, uint8_t check) +{ + //delegate to specialized function if HP303B is connected via SPI + if(m_SpiI2c==0) + { + return writeByteSpi(regAddress, data, check); + } + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regAddress); //Write Register number to buffer + m_i2cbus->write(data); //Write data to buffer + if(m_i2cbus->endTransmission() != 0) //Send buffer content to slave + { + return HP303B__FAIL_UNKNOWN; + } + else + { + if(check == 0) return 0; //no checking + if(readByte(regAddress) == data) //check if desired by calling function + { + return HP303B__SUCCEEDED; + } + else + { + return HP303B__FAIL_UNKNOWN; + } + } +} + +/** + * writes a given byte to a given register of HP303B via SPI + * + * regAdress: Address of the register that has to be updated + * data: Byte that will be written to the register + * check: If this is true, register content will be read after writing + * to check if update was successful + * return: 0 if byte was written successfully + * or -1 on fail + */ +int16_t LOLIN_HP303B::writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check) +{ + //this function is only made for communication via SPI + if(m_SpiI2c != 0) + { + return HP303B__FAIL_UNKNOWN; + } + //mask regAddress + regAddress &= ~HP303B__SPI_RW_MASK; + //reserve and initialize bus + m_spibus->beginTransaction(SPISettings(HP303B__SPI_MAX_FREQ, + MSBFIRST, + SPI_MODE3)); + //enable ChipSelect for HP303B + digitalWrite(m_chipSelect, LOW); + //send address with read command to HP303B + m_spibus->transfer(regAddress | HP303B__SPI_WRITE_CMD); + + //write register content from HP303B + m_spibus->transfer(data); + + //disable ChipSelect for HP303B + digitalWrite(m_chipSelect, HIGH); + //close current SPI transaction + m_spibus->endTransaction(); + + //check if necessary + if(check == 0) + { + //no checking necessary + return HP303B__SUCCEEDED; + } + //checking necessary + if(readByte(regAddress) == data) + { + //check passed + return HP303B__SUCCEEDED; + } + else + { + //check failed + return HP303B__FAIL_UNKNOWN; + } +} + +/** + * updates some given bits of a given register of HP303B without checking + * + * regAdress: Address of the register that has to be updated + * data: BitValues that will be written to the register + * shift: Amount of bits the data byte is shifted (left) before being masked + * mask: Masks the bits of the register that have to be updated + * Bits with value 1 are updated + * Bits with value 0 are not changed + * return: 0 if byte was written successfully + * or -1 on fail + */ +int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data, + uint8_t regAddress, + uint8_t mask, + uint8_t shift) +{ + return writeByteBitfield(data, regAddress, mask, shift, 0U); +} + +/** + * updates some given bits of a given register of HP303B + * + * regAdress: Address of the register that has to be updated + * data: BitValues that will be written to the register + * shift: Amount of bits the data byte is shifted (left) before being masked + * mask: Masks the bits of the register that have to be updated + * Bits with value 1 are updated + * Bits with value 0 are not changed + * check: enables/disables check after writing + * 0 disables check + * if check fails, -1 will be returned + * return: 0 if byte was written successfully + * or -1 on fail + */ +int16_t LOLIN_HP303B::writeByteBitfield(uint8_t data, + uint8_t regAddress, + uint8_t mask, + uint8_t shift, + uint8_t check) +{ + int16_t old = readByte(regAddress); + if(old < 0) + { + //fail while reading + return old; + } + return writeByte(regAddress, ((uint8_t)old & ~mask)|((data << shift) & mask), check); +} + +/** + * reads some given bits of a given register of HP303B + * + * regAdress: Address of the register that has to be updated + * mask: Masks the bits of the register that have to be updated + * Bits masked with value 1 are read + * Bits masked with value 0 are set 0 + * shift: Amount of bits the data byte is shifted (right) after being masked + * return: read and processed bits + * or -1 on fail + */ +int16_t LOLIN_HP303B::readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift) +{ + int16_t ret = readByte(regAddress); + if(ret<0) + { + return ret; + } + return (((uint8_t)ret) & mask) >> shift; +} diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h new file mode 100644 index 000000000..f9c54e356 --- /dev/null +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h @@ -0,0 +1,144 @@ +#ifndef __LOLIN_HP303B_H +#define __LOLIN_HP303B_H + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#include +#include +#include "util/hp303b_consts.h" + +class LOLIN_HP303B +{ +public: + //constructor + LOLIN_HP303B(void); + //destructor + ~LOLIN_HP303B(void); + //begin + void begin(TwoWire &bus, uint8_t slaveAddress); + void begin(uint8_t slaveAddress=HP303B__STD_SLAVE_ADDRESS); + void begin(SPIClass &bus, int32_t chipSelect); + void begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire); + //end + void end(void); + + //general + uint8_t getProductId(void); + uint8_t getRevisionId(void); + + //Idle Mode + int16_t standby(void); + + //Command Mode + int16_t measureTempOnce(int32_t &result); + int16_t measureTempOnce(int32_t &result, uint8_t oversamplingRate); + int16_t startMeasureTempOnce(void); + int16_t startMeasureTempOnce(uint8_t oversamplingRate); + int16_t measurePressureOnce(int32_t &result); + int16_t measurePressureOnce(int32_t &result, uint8_t oversamplingRate); + int16_t startMeasurePressureOnce(void); + int16_t startMeasurePressureOnce(uint8_t oversamplingRate); + int16_t getSingleResult(int32_t &result); + + //Background Mode + int16_t startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate); + int16_t startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate); + int16_t startMeasureBothCont(uint8_t tempMr, uint8_t tempOsr, uint8_t prsMr, uint8_t prsOsr); + int16_t getContResults(int32_t *tempBuffer, uint8_t &tempCount, int32_t *prsBuffer, uint8_t &prsCount); + + //Interrupt Control + int16_t setInterruptPolarity(uint8_t polarity); + int16_t setInterruptSources(uint8_t fifoFull, uint8_t tempReady, uint8_t prsReady); + int16_t getIntStatusFifoFull(void); + int16_t getIntStatusTempReady(void); + int16_t getIntStatusPrsReady(void); + + //function to fix a hardware problem on some devices + int16_t correctTemp(void); + +private: + //scaling factor table + static const int32_t scaling_facts[HP303B__NUM_OF_SCAL_FACTS]; + + //enum for operating mode + enum Mode + { + IDLE = 0x00, + CMD_PRS = 0x01, + CMD_TEMP = 0x02, + INVAL_OP_CMD_BOTH = 0x03, //invalid + INVAL_OP_CONT_NONE = 0x04, //invalid + CONT_PRS = 0x05, + CONT_TMP = 0x06, + CONT_BOTH = 0x07 + }; + Mode m_opMode; + + //flags + uint8_t m_initFail; + uint8_t m_productID; + uint8_t m_revisionID; + + //settings + uint8_t m_tempMr; + uint8_t m_tempOsr; + uint8_t m_prsMr; + uint8_t m_prsOsr; + uint8_t m_tempSensor; + + //compensation coefficients + int32_t m_c0Half; + int32_t m_c1; + int32_t m_c00; + int32_t m_c10; + int32_t m_c01; + int32_t m_c11; + int32_t m_c20; + int32_t m_c21; + int32_t m_c30; + //last measured scaled temperature + //(necessary for pressure compensation) + double m_lastTempScal; + + //bus specific + uint8_t m_SpiI2c; //0=SPI, 1=I2C + //used for I2C + TwoWire *m_i2cbus; + uint8_t m_slaveAddress; + //used for SPI + SPIClass *m_spibus; + int32_t m_chipSelect; + uint8_t m_threeWire; + + //measurement + void init(void); + int16_t readcoeffs(void); + int16_t setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure); + int16_t setOpMode(uint8_t opMode); + int16_t configTemp(uint8_t temp_mr, uint8_t temp_osr); + int16_t configPressure(uint8_t prs_mr, uint8_t prs_osr); + uint16_t calcBusyTime(uint16_t temp_rate, uint16_t temp_osr); + int16_t getTemp(int32_t *result); + int16_t getPressure(int32_t *result); + int16_t getFIFOvalue(int32_t *value); + int32_t calcTemp(int32_t raw); + int32_t calcPressure(int32_t raw); + + //bus specific + int16_t readByte(uint8_t regAddress); + int16_t readByteSPI(uint8_t regAddress); + int16_t readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer); + int16_t readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *readbuffer); + int16_t writeByte(uint8_t regAddress, uint8_t data); + int16_t writeByte(uint8_t regAddress, uint8_t data, uint8_t check); + int16_t writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check); + int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift); + int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift, uint8_t check); + int16_t readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift); +}; + +#endif diff --git a/lib/LOLIN_HP303B/src/util/hp303b_consts.h b/lib/LOLIN_HP303B/src/util/hp303b_consts.h new file mode 100644 index 000000000..f93629e93 --- /dev/null +++ b/lib/LOLIN_HP303B/src/util/hp303b_consts.h @@ -0,0 +1,258 @@ +/** + * + * + */ + +#ifndef __HP303B_CONSTS_H_ +#define __HP303B_CONSTS_H_ + + + //general Constants +#define HP303B__PROD_ID 0U +#define HP303B__STD_SLAVE_ADDRESS 0x77U +#define HP303B__SPI_WRITE_CMD 0x00U +#define HP303B__SPI_READ_CMD 0x80U +#define HP303B__SPI_RW_MASK 0x80U +#define HP303B__SPI_MAX_FREQ 100000U + +#define HP303B__LSB 0x01U + +#define HP303B__TEMP_STD_MR 2U +#define HP303B__TEMP_STD_OSR 3U +#define HP303B__PRS_STD_MR 2U +#define HP303B__PRS_STD_OSR 3U +#define HP303B__OSR_SE 3U +//we use 0.1 mS units for time calculations, so 10 units are one millisecond +#define HP303B__BUSYTIME_SCALING 10U +// DPS310 has 10 milliseconds of spare time for each synchronous measurement / per second for asynchronous measurements +// this is for error prevention on friday-afternoon-products :D +// you can set it to 0 if you dare, but there is no warranty that it will still work +#define HP303B__BUSYTIME_FAILSAFE 10U +#define HP303B__MAX_BUSYTIME ((1000U-HP303B__BUSYTIME_FAILSAFE)*HP303B__BUSYTIME_SCALING) +#define HP303B__NUM_OF_SCAL_FACTS 8 + +#define HP303B__SUCCEEDED 0 +#define HP303B__FAIL_UNKNOWN -1 +#define HP303B__FAIL_INIT_FAILED -2 +#define HP303B__FAIL_TOOBUSY -3 +#define HP303B__FAIL_UNFINISHED -4 + + + //Constants for register manipulation + //SPI mode (3 or 4 wire) +#define HP303B__REG_ADR_SPI3W 0x09U +#define HP303B__REG_CONTENT_SPI3W 0x01U + + + //product id +#define HP303B__REG_INFO_PROD_ID HP303B__REG_ADR_PROD_ID, \ + HP303B__REG_MASK_PROD_ID, \ + HP303B__REG_SHIFT_PROD_ID +#define HP303B__REG_ADR_PROD_ID 0x0DU +#define HP303B__REG_MASK_PROD_ID 0x0FU +#define HP303B__REG_SHIFT_PROD_ID 0U + + //revision id +#define HP303B__REG_INFO_REV_ID HP303B__REG_ADR_REV_ID, \ + HP303B__REG_MASK_REV_ID, \ + HP303B__REG_SHIFT_REV_ID +#define HP303B__REG_ADR_REV_ID 0x0DU +#define HP303B__REG_MASK_REV_ID 0xF0U +#define HP303B__REG_SHIFT_REV_ID 4U + + //operating mode +#define HP303B__REG_INFO_OPMODE HP303B__REG_ADR_OPMODE, \ + HP303B__REG_MASK_OPMODE, \ + HP303B__REG_SHIFT_OPMODE +#define HP303B__REG_ADR_OPMODE 0x08U +#define HP303B__REG_MASK_OPMODE 0x07U +#define HP303B__REG_SHIFT_OPMODE 0U + + + //temperature measure rate +#define HP303B__REG_INFO_TEMP_MR HP303B__REG_ADR_TEMP_MR, \ + HP303B__REG_MASK_TEMP_MR, \ + HP303B__REG_SHIFT_TEMP_MR +#define HP303B__REG_ADR_TEMP_MR 0x07U +#define HP303B__REG_MASK_TEMP_MR 0x70U +#define HP303B__REG_SHIFT_TEMP_MR 4U + + //temperature oversampling rate +#define HP303B__REG_INFO_TEMP_OSR HP303B__REG_ADR_TEMP_OSR, \ + HP303B__REG_MASK_TEMP_OSR, \ + HP303B__REG_SHIFT_TEMP_OSR +#define HP303B__REG_ADR_TEMP_OSR 0x07U +#define HP303B__REG_MASK_TEMP_OSR 0x07U +#define HP303B__REG_SHIFT_TEMP_OSR 0U + + //temperature sensor +#define HP303B__REG_INFO_TEMP_SENSOR HP303B__REG_ADR_TEMP_SENSOR, \ + HP303B__REG_MASK_TEMP_SENSOR, \ + HP303B__REG_SHIFT_TEMP_SENSOR +#define HP303B__REG_ADR_TEMP_SENSOR 0x07U +#define HP303B__REG_MASK_TEMP_SENSOR 0x80U +#define HP303B__REG_SHIFT_TEMP_SENSOR 7U + + //temperature sensor recommendation +#define HP303B__REG_INFO_TEMP_SENSORREC HP303B__REG_ADR_TEMP_SENSORREC, \ + HP303B__REG_MASK_TEMP_SENSORREC, \ + HP303B__REG_SHIFT_TEMP_SENSORREC +#define HP303B__REG_ADR_TEMP_SENSORREC 0x28U +#define HP303B__REG_MASK_TEMP_SENSORREC 0x80U +#define HP303B__REG_SHIFT_TEMP_SENSORREC 7U + + //temperature shift enable (if temp_osr>3) +#define HP303B__REG_INFO_TEMP_SE HP303B__REG_ADR_TEMP_SE, \ + HP303B__REG_MASK_TEMP_SE, \ + HP303B__REG_SHIFT_TEMP_SE +#define HP303B__REG_ADR_TEMP_SE 0x09U +#define HP303B__REG_MASK_TEMP_SE 0x08U +#define HP303B__REG_SHIFT_TEMP_SE 3U + + + //pressure measure rate +#define HP303B__REG_INFO_PRS_MR HP303B__REG_ADR_PRS_MR, \ + HP303B__REG_MASK_PRS_MR, \ + HP303B__REG_SHIFT_PRS_MR +#define HP303B__REG_ADR_PRS_MR 0x06U +#define HP303B__REG_MASK_PRS_MR 0x70U +#define HP303B__REG_SHIFT_PRS_MR 4U + + //pressure oversampling rate +#define HP303B__REG_INFO_PRS_OSR HP303B__REG_ADR_PRS_OSR, \ + HP303B__REG_MASK_PRS_OSR, \ + HP303B__REG_SHIFT_PRS_OSR +#define HP303B__REG_ADR_PRS_OSR 0x06U +#define HP303B__REG_MASK_PRS_OSR 0x07U +#define HP303B__REG_SHIFT_PRS_OSR 0U + + //pressure shift enable (if prs_osr>3) +#define HP303B__REG_INFO_PRS_SE HP303B__REG_ADR_PRS_SE, \ + HP303B__REG_MASK_PRS_SE, \ + HP303B__REG_SHIFT_PRS_SE +#define HP303B__REG_ADR_PRS_SE 0x09U +#define HP303B__REG_MASK_PRS_SE 0x04U +#define HP303B__REG_SHIFT_PRS_SE 2U + + + //temperature ready flag +#define HP303B__REG_INFO_TEMP_RDY HP303B__REG_ADR_TEMP_RDY, \ + HP303B__REG_MASK_TEMP_RDY, \ + HP303B__REG_SHIFT_TEMP_RDY +#define HP303B__REG_ADR_TEMP_RDY 0x08U +#define HP303B__REG_MASK_TEMP_RDY 0x20U +#define HP303B__REG_SHIFT_TEMP_RDY 5U + + //pressure ready flag +#define HP303B__REG_INFO_PRS_RDY HP303B__REG_ADR_PRS_RDY, \ + HP303B__REG_MASK_PRS_RDY, \ + HP303B__REG_SHIFT_PRS_RDY +#define HP303B__REG_ADR_PRS_RDY 0x08U +#define HP303B__REG_MASK_PRS_RDY 0x10U +#define HP303B__REG_SHIFT_PRS_RDY 4U + + //pressure value +#define HP303B__REG_ADR_PRS 0x00U +#define HP303B__REG_LEN_PRS 3U + + //temperature value +#define HP303B__REG_ADR_TEMP 0x03U +#define HP303B__REG_LEN_TEMP 3U + + //compensation coefficients +#define HP303B__REG_ADR_COEF 0x10U +#define HP303B__REG_LEN_COEF 18 + + + //FIFO enable +#define HP303B__REG_INFO_FIFO_EN HP303B__REG_ADR_FIFO_EN, \ + HP303B__REG_MASK_FIFO_EN, \ + HP303B__REG_SHIFT_FIFO_EN +#define HP303B__REG_ADR_FIFO_EN 0x09U +#define HP303B__REG_MASK_FIFO_EN 0x02U +#define HP303B__REG_SHIFT_FIFO_EN 1U + + //FIFO flush +#define HP303B__REG_INFO_FIFO_FL HP303B__REG_ADR_FIFO_EN, \ + HP303B__REG_MASK_FIFO_EN, \ + HP303B__REG_SHIFT_FIFO_EN +#define HP303B__REG_ADR_FIFO_FL 0x0CU +#define HP303B__REG_MASK_FIFO_FL 0x80U +#define HP303B__REG_SHIFT_FIFO_FL 7U + + //FIFO empty +#define HP303B__REG_INFO_FIFO_EMPTY HP303B__REG_ADR_FIFO_EMPTY, \ + HP303B__REG_MASK_FIFO_EMPTY, \ + HP303B__REG_SHIFT_FIFO_EMPTY +#define HP303B__REG_ADR_FIFO_EMPTY 0x0BU +#define HP303B__REG_MASK_FIFO_EMPTY 0x01U +#define HP303B__REG_SHIFT_FIFO_EMPTY 0U + + //FIFO full +#define HP303B__REG_INFO_FIFO_FULL HP303B__REG_ADR_FIFO_FULL, \ + HP303B__REG_MASK_FIFO_FULL, \ + HP303B__REG_SHIFT_FIFO_FULL +#define HP303B__REG_ADR_FIFO_FULL 0x0BU +#define HP303B__REG_MASK_FIFO_FULL 0x02U +#define HP303B__REG_SHIFT_FIFO_FULL 1U + + + //INT HL +#define HP303B__REG_INFO_INT_HL HP303B__REG_ADR_INT_HL, \ + HP303B__REG_MASK_INT_HL, \ + HP303B__REG_SHIFT_INT_HL +#define HP303B__REG_ADR_INT_HL 0x09U +#define HP303B__REG_MASK_INT_HL 0x80U +#define HP303B__REG_SHIFT_INT_HL 7U + + //INT FIFO enable +#define HP303B__REG_INFO_INT_EN_FIFO HP303B__REG_ADR_INT_EN_FIFO, \ + HP303B__REG_MASK_INT_EN_FIFO, \ + HP303B__REG_SHIFT_INT_EN_FIFO +#define HP303B__REG_ADR_INT_EN_FIFO 0x09U +#define HP303B__REG_MASK_INT_EN_FIFO 0x40U +#define HP303B__REG_SHIFT_INT_EN_FIFO 6U + + //INT TEMP enable +#define HP303B__REG_INFO_INT_EN_TEMP HP303B__REG_ADR_INT_EN_TEMP, \ + HP303B__REG_MASK_INT_EN_TEMP, \ + HP303B__REG_SHIFT_INT_EN_TEMP +#define HP303B__REG_ADR_INT_EN_TEMP 0x09U +#define HP303B__REG_MASK_INT_EN_TEMP 0x20U +#define HP303B__REG_SHIFT_INT_EN_TEMP 5U + + //INT PRS enable +#define HP303B__REG_INFO_INT_EN_PRS HP303B__REG_ADR_INT_EN_PRS, \ + HP303B__REG_MASK_INT_EN_PRS, \ + HP303B__REG_SHIFT_INT_EN_PRS +#define HP303B__REG_ADR_INT_EN_PRS 0x09U +#define HP303B__REG_MASK_INT_EN_PRS 0x10U +#define HP303B__REG_SHIFT_INT_EN_PRS 4U + + //INT FIFO flag +#define HP303B__REG_INFO_INT_FLAG_FIFO HP303B__REG_ADR_INT_FLAG_FIFO, \ + HP303B__REG_MASK_INT_FLAG_FIFO, \ + HP303B__REG_SHIFT_INT_FLAG_FIFO +#define HP303B__REG_ADR_INT_FLAG_FIFO 0x0AU +#define HP303B__REG_MASK_INT_FLAG_FIFO 0x04U +#define HP303B__REG_SHIFT_INT_FLAG_FIFO 2U + + //INT TMP flag +#define HP303B__REG_INFO_INT_FLAG_TEMP HP303B__REG_ADR_INT_FLAG_TEMP, \ + HP303B__REG_MASK_INT_FLAG_TEMP, \ + HP303B__REG_SHIFT_INT_FLAG_TEMP +#define HP303B__REG_ADR_INT_FLAG_TEMP 0x0AU +#define HP303B__REG_MASK_INT_FLAG_TEMP 0x02U +#define HP303B__REG_SHIFT_INT_FLAG_TEMP 1U + + //INT PRS flag +#define HP303B__REG_INFO_INT_FLAG_PRS HP303B__REG_ADR_INT_FLAG_PRS, \ + HP303B__REG_MASK_INT_FLAG_PRS, \ + HP303B__REG_SHIFT_INT_FLAG_PRS +#define HP303B__REG_ADR_INT_FLAG_PRS 0x0AU +#define HP303B__REG_MASK_INT_FLAG_PRS 0x01U +#define HP303B__REG_SHIFT_INT_FLAG_PRS 0U + + + +#endif /* DPS310_CONSTS_H_ */ diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 5622bcde9..25a8a2203 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -572,8 +572,10 @@ void GetFeatures(void) #ifdef USE_MCP9808 feature6 |= 0x00002000; // xsns_72_mcp9808.ino #endif +#ifdef USE_HP303B + feature6 |= 0x00004000; // xsns_73_hp303b.ino +#endif -// feature6 |= 0x00004000; // feature6 |= 0x00008000; // feature6 |= 0x00010000; diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino new file mode 100644 index 000000000..e5df20508 --- /dev/null +++ b/tasmota/xsns_73_hp303b.ino @@ -0,0 +1,161 @@ +/* + xsns_72_hp303b.ino - HP303B digital barometric air pressure sensor support for Tasmota + + Copyright (C) 2020 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifdef USE_I2C +#ifdef USE_HP303B +/*********************************************************************************************\ + * HP303B - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) + * + * Source: Lolin LOLIN_HP303B_Library + * + * I2C Address: 0x77 or 0x76 +\*********************************************************************************************/ + +#define XSNS_73 73 +#define XI2C_52 52 // See I2CDEVICES.md + +#define HP303B_ADDR1 0x77 +#define HP303B_ADDR2 0x76 + +#include +// HP303B Opject +LOLIN_HP303B HP303BSensor = LOLIN_HP303B(); + +struct HP303BDATA +{ + uint8_t address; + uint8_t addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; + uint8_t type = 0; + uint8_t valid = 0; + int32_t temperature; + int32_t pressure; + int16_t oversampling = 7; + char types[7] = "HP303B"; +} HP303B; + +/*********************************************************************************************/ + +bool HP303B_Read(int32_t &t, int32_t &p, uint8_t hp303b_address) +{ + HP303BSensor.begin(hp303b_address); + + int16_t ret; + + ret = HP303BSensor.measureTempOnce(t, HP303B.oversampling); + if (ret != 0) + return false; + + ret = HP303BSensor.measurePressureOnce(p, HP303B.oversampling); + if (ret != 0) + return false; + + HP303B.temperature = ConvertTemp(t); + HP303B.pressure = ConvertPressure(p); + + return true; +} + +/********************************************************************************************/ + +void HP303B_Detect(void) +{ + for (uint32_t i = 0; i < sizeof(HP303B.addresses); i++) + { + if (!I2cSetDevice(HP303B.addresses[i])) + { + continue; + } + + int32_t t; + int32_t p; + if (HP303B_Read(t, p, HP303B.addresses[i])) + { + I2cSetActiveFound(HP303B.addresses[i], HP303B.types); + HP303B.address = HP303B.addresses[i]; + HP303B.type = 1; + } + } +} + +void HP303B_Show(bool json) +{ + + if (HP303B_Read(HP303B.temperature, HP303B.pressure, HP303B.address)) + { + if (json) + { + ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_PRESSURE "\":%d"), HP303B.temperature, HP303B.pressure); +#ifdef USE_DOMOTICZ + if (0 == tele_period) + { + DomoticzSensor(DZ_TEMP, HP303B.temperature); + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } + else + { + char str_temperature[12]; + char str_pressure[12]; + + itoa(HP303B.temperature, str_temperature, 10); + itoa(HP303B.pressure, str_pressure, 10); + + WSContentSend_PD(HTTP_SNS_TEMP, "HP303B", str_temperature, TempUnit()); + WSContentSend_PD(HTTP_SNS_PRESSURE, "HP303B", str_pressure, PressureUnit().c_str()); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns73(uint8_t function) +{ + if (!I2cEnabled(XI2C_52)) + { + return false; + } + + bool result = false; + + if (FUNC_INIT == function) + { + HP303B_Detect(); + } + else if (HP303B.type) + { + switch (function) + { + case FUNC_JSON_APPEND: + HP303B_Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + HP303B_Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_HP303B +#endif // USE_I2C diff --git a/tools/decode-status.py b/tools/decode-status.py index 67898d784..b77ddf2c6 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -204,7 +204,7 @@ a_features = [[ "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080", "USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING", "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", - "USE_VEML7700","USE_MCP9808","","", + "USE_VEML7700","USE_MCP9808","USE_HP303B","", "","","","", "","","","", "","","","", From 2da09526ba41f73663b7ddda55df80c3104c2407 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Sat, 6 Jun 2020 23:05:55 +0200 Subject: [PATCH 02/10] switched to float values and converted Pa to hPa --- tasmota/xsns_73_hp303b.ino | 64 ++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index e5df20508..3f508b7d8 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -36,36 +36,35 @@ // HP303B Opject LOLIN_HP303B HP303BSensor = LOLIN_HP303B(); -struct HP303BDATA -{ - uint8_t address; - uint8_t addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; - uint8_t type = 0; - uint8_t valid = 0; - int32_t temperature; - int32_t pressure; - int16_t oversampling = 7; - char types[7] = "HP303B"; -} HP303B; +uint8_t address; +uint8_t addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; +uint8_t type = 0; +uint8_t valid = 0; +float temperature; +float pressure; +int16_t oversampling = 7; +char types[7] = "HP303B"; /*********************************************************************************************/ -bool HP303B_Read(int32_t &t, int32_t &p, uint8_t hp303b_address) +bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) { HP303BSensor.begin(hp303b_address); + int32_t t; + int32_t p; int16_t ret; - ret = HP303BSensor.measureTempOnce(t, HP303B.oversampling); + ret = HP303BSensor.measureTempOnce(t, oversampling); if (ret != 0) return false; - ret = HP303BSensor.measurePressureOnce(p, HP303B.oversampling); + ret = HP303BSensor.measurePressureOnce(p, oversampling); if (ret != 0) return false; - HP303B.temperature = ConvertTemp(t); - HP303B.pressure = ConvertPressure(p); + temperature = (float)ConvertTemp(t); + pressure = (float)ConvertPressure(p) / 100; //conversion to hPa return true; } @@ -74,20 +73,20 @@ bool HP303B_Read(int32_t &t, int32_t &p, uint8_t hp303b_address) void HP303B_Detect(void) { - for (uint32_t i = 0; i < sizeof(HP303B.addresses); i++) + for (uint32_t i = 0; i < sizeof(addresses); i++) { - if (!I2cSetDevice(HP303B.addresses[i])) + if (!I2cSetDevice(addresses[i])) { continue; } - int32_t t; - int32_t p; - if (HP303B_Read(t, p, HP303B.addresses[i])) + float t; + float p; + if (HP303B_Read(t, p, addresses[i])) { - I2cSetActiveFound(HP303B.addresses[i], HP303B.types); - HP303B.address = HP303B.addresses[i]; - HP303B.type = 1; + I2cSetActiveFound(addresses[i], types); + address = addresses[i]; + type = 1; } } } @@ -95,26 +94,25 @@ void HP303B_Detect(void) void HP303B_Show(bool json) { - if (HP303B_Read(HP303B.temperature, HP303B.pressure, HP303B.address)) + if (HP303B_Read(temperature, pressure, address)) { if (json) { - ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_PRESSURE "\":%d"), HP303B.temperature, HP303B.pressure); + ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_PRESSURE "\":%d"), temperature, pressure); #ifdef USE_DOMOTICZ if (0 == tele_period) { - DomoticzSensor(DZ_TEMP, HP303B.temperature); + DomoticzSensor(DZ_TEMP, temperature); } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - char str_temperature[12]; - char str_pressure[12]; - - itoa(HP303B.temperature, str_temperature, 10); - itoa(HP303B.pressure, str_pressure, 10); + char str_temperature[33]; + dtostrfd(temperature, Settings.flag2.temperature_resolution, str_temperature); + char str_pressure[33]; + dtostrfd(pressure, Settings.flag2.pressure_resolution, str_pressure); WSContentSend_PD(HTTP_SNS_TEMP, "HP303B", str_temperature, TempUnit()); WSContentSend_PD(HTTP_SNS_PRESSURE, "HP303B", str_pressure, PressureUnit().c_str()); @@ -140,7 +138,7 @@ bool Xsns73(uint8_t function) { HP303B_Detect(); } - else if (HP303B.type) + else if (type) { switch (function) { From d3a59fd65c3f5834d9fb61eee1374d50a2f14db3 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Sun, 7 Jun 2020 16:33:28 +0200 Subject: [PATCH 03/10] Changed driver to measure float --- lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp | 82 +++++++++++++-------------- lib/LOLIN_HP303B/src/LOLIN_HP303B.h | 22 +++---- tasmota/xsns_73_hp303b.ino | 17 +++--- 3 files changed, 60 insertions(+), 61 deletions(-) diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp index 43fcd435e..fdeebd6a0 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp @@ -181,7 +181,7 @@ int16_t LOLIN_HP303B::standby(void) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measureTempOnce(int32_t &result) +int16_t LOLIN_HP303B::measureTempOnce(float &result) { return measureTempOnce(result, m_tempOsr); } @@ -202,7 +202,7 @@ int16_t LOLIN_HP303B::measureTempOnce(int32_t &result) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measureTempOnce(int32_t &result, uint8_t oversamplingRate) +int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t oversamplingRate) { //Start measurement int16_t ret = startMeasureTempOnce(oversamplingRate); @@ -286,7 +286,7 @@ int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result) +int16_t LOLIN_HP303B::measurePressureOnce(float &result) { return measurePressureOnce(result, m_prsOsr); } @@ -307,7 +307,7 @@ int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measurePressureOnce(int32_t &result, uint8_t oversamplingRate) +int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t oversamplingRate) { //start the measurement int16_t ret = startMeasurePressureOnce(oversamplingRate); @@ -388,7 +388,7 @@ int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::getSingleResult(int32_t &result) +int16_t LOLIN_HP303B::getSingleResult(float &result) { //abort if initialization failed if(m_initFail) @@ -636,9 +636,9 @@ int16_t LOLIN_HP303B::startMeasureBothCont(uint8_t tempMr, * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::getContResults(int32_t *tempBuffer, +int16_t LOLIN_HP303B::getContResults(float *tempBuffer, uint8_t &tempCount, - int32_t *prsBuffer, + float *prsBuffer, uint8_t &prsCount) { if(m_initFail) @@ -660,7 +660,7 @@ int16_t LOLIN_HP303B::getContResults(int32_t *tempBuffer, //while FIFO is not empty while(readByteBitfield(HP303B__REG_INFO_FIFO_EMPTY) == 0) { - int32_t result; + float result; //read next result from FIFO int16_t type = getFIFOvalue(&result); switch(type) @@ -820,13 +820,13 @@ int16_t LOLIN_HP303B::correctTemp(void) writeByte(0x62, 0x02); writeByte(0x0E, 0x00); writeByte(0x0F, 0x00); - + //perform a first temperature measurement (again) //the most recent temperature will be saved internally //and used for compensation when calculating pressure - int32_t trash; + float trash; measureTempOnce(trash); - + return HP303B__SUCCEEDED; } @@ -892,13 +892,13 @@ void LOLIN_HP303B::init(void) //perform a first temperature measurement //the most recent temperature will be saved internally //and used for compensation when calculating pressure - int32_t trash; + float trash; measureTempOnce(trash); //make sure the HP303B is in standby after initialization - standby(); + standby(); - // Fix IC with a fuse bit problem, which lead to a wrong temperature + // Fix IC with a fuse bit problem, which lead to a wrong temperature // Should not affect ICs without this problem correctTemp(); } @@ -1192,9 +1192,9 @@ uint16_t LOLIN_HP303B::calcBusyTime(uint16_t mr, uint16_t osr) * returns: 0 on success * -1 on fail; */ -int16_t LOLIN_HP303B::getTemp(int32_t *result) +int16_t LOLIN_HP303B::getTemp(float *result) { - uint8_t buffer[3] = {0}; + unsigned char buffer[3] = {0}; //read raw pressure data to buffer int16_t i = readBlock(HP303B__REG_ADR_TEMP, @@ -1207,14 +1207,14 @@ int16_t LOLIN_HP303B::getTemp(int32_t *result) } //compose raw temperature value from buffer - int32_t temp = (uint32_t)buffer[0] << 16 - | (uint32_t)buffer[1] << 8 - | (uint32_t)buffer[2]; + float temp = buffer[0] << 16 + | buffer[1] << 8 + | buffer[2]; //recognize non-32-bit negative numbers //and convert them to 32-bit negative numbers using 2's complement - if(temp & ((uint32_t)1 << 23)) + if(temp > 0x7FFFFF) { - temp -= (uint32_t)1 << 24; + temp = temp - 0x1000000; } //return temperature @@ -1229,9 +1229,9 @@ int16_t LOLIN_HP303B::getTemp(int32_t *result) * returns: 0 on success * -1 on fail; */ -int16_t LOLIN_HP303B::getPressure(int32_t *result) +int16_t LOLIN_HP303B::getPressure(float *result) { - uint8_t buffer[3] = {0}; + unsigned char buffer[3] = {0}; //read raw pressure data to buffer int16_t i = readBlock(HP303B__REG_ADR_PRS, HP303B__REG_LEN_PRS, @@ -1244,14 +1244,12 @@ int16_t LOLIN_HP303B::getPressure(int32_t *result) } //compose raw pressure value from buffer - int32_t prs = (uint32_t)buffer[0] << 16 - | (uint32_t)buffer[1] << 8 - | (uint32_t)buffer[2]; + float prs = buffer[0] << 16 | buffer[1] << 8 | buffer[2]; //recognize non-32-bit negative numbers //and convert them to 32-bit negative numbers using 2's complement - if(prs & ((uint32_t)1 << 23)) + if(prs > 0x7FFFFF) { - prs -= (uint32_t)1 << 24; + prs = prs - 0x1000000; } *result = calcPressure(prs); @@ -1266,7 +1264,7 @@ int16_t LOLIN_HP303B::getPressure(int32_t *result) * 0 if result is a temperature raw value * 1 if result is a pressure raw value */ -int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value) +int16_t LOLIN_HP303B::getFIFOvalue(float *value) { //abort on invalid argument if(value == NULL) @@ -1274,7 +1272,7 @@ int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value) return HP303B__FAIL_UNKNOWN; } - uint8_t buffer[HP303B__REG_LEN_PRS] = {0}; + unsigned char buffer[HP303B__REG_LEN_PRS] = {0}; //always read from pressure raw value register int16_t i = readBlock(HP303B__REG_ADR_PRS, HP303B__REG_LEN_PRS, @@ -1286,14 +1284,14 @@ int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value) return HP303B__FAIL_UNKNOWN; } //compose raw pressure value from buffer - *value = (uint32_t)buffer[0] << 16 - | (uint32_t)buffer[1] << 8 - | (uint32_t)buffer[2]; + *value = buffer[0] << 16 + | buffer[1] << 8 + | buffer[2]; //recognize non-32-bit negative numbers //and convert them to 32-bit negative numbers using 2's complement - if(*value & ((uint32_t)1 << 23)) + if(*value > 0x7FFFFF) { - *value -= (uint32_t)1 << 24; + *value = *value - 0x1000000; } //least significant bit shows measurement type @@ -1305,10 +1303,10 @@ int16_t LOLIN_HP303B::getFIFOvalue(int32_t* value) * raw: raw temperature value read from HP303B * returns: temperature value in °C */ -int32_t LOLIN_HP303B::calcTemp(int32_t raw) +float LOLIN_HP303B::calcTemp(float raw) { double temp = raw; - + //scale temperature according to scaling table and oversampling temp /= scaling_facts[m_tempOsr]; @@ -1320,7 +1318,7 @@ int32_t LOLIN_HP303B::calcTemp(int32_t raw) temp = m_c0Half + m_c1 * temp; //return temperature - return (int32_t)temp; + return (float)temp; } /** @@ -1328,7 +1326,7 @@ int32_t LOLIN_HP303B::calcTemp(int32_t raw) * raw: raw pressure value read from HP303B * returns: pressure value in Pa */ -int32_t LOLIN_HP303B::calcPressure(int32_t raw) +float LOLIN_HP303B::calcPressure(float raw) { double prs = raw; @@ -1341,7 +1339,7 @@ int32_t LOLIN_HP303B::calcPressure(int32_t raw) + m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21)); //return pressure - return (int32_t)prs; + return (float)prs; } /** @@ -1357,7 +1355,7 @@ int16_t LOLIN_HP303B::readByte(uint8_t regAddress) { return readByteSPI(regAddress); } - + m_i2cbus->beginTransmission(m_slaveAddress); m_i2cbus->write(regAddress); m_i2cbus->endTransmission(0); @@ -1429,7 +1427,7 @@ int16_t LOLIN_HP303B::readBlock(uint8_t regAddress, uint8_t length, uint8_t *buf { return 0; //0 bytes read successfully } - + m_i2cbus->beginTransmission(m_slaveAddress); m_i2cbus->write(regAddress); m_i2cbus->endTransmission(0); diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h index f9c54e356..ce65e17f1 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h @@ -34,21 +34,21 @@ public: int16_t standby(void); //Command Mode - int16_t measureTempOnce(int32_t &result); - int16_t measureTempOnce(int32_t &result, uint8_t oversamplingRate); + int16_t measureTempOnce(float &result); + int16_t measureTempOnce(float &result, uint8_t oversamplingRate); int16_t startMeasureTempOnce(void); int16_t startMeasureTempOnce(uint8_t oversamplingRate); - int16_t measurePressureOnce(int32_t &result); - int16_t measurePressureOnce(int32_t &result, uint8_t oversamplingRate); + int16_t measurePressureOnce(float &result); + int16_t measurePressureOnce(float &result, uint8_t oversamplingRate); int16_t startMeasurePressureOnce(void); int16_t startMeasurePressureOnce(uint8_t oversamplingRate); - int16_t getSingleResult(int32_t &result); + int16_t getSingleResult(float &result); //Background Mode int16_t startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate); int16_t startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate); int16_t startMeasureBothCont(uint8_t tempMr, uint8_t tempOsr, uint8_t prsMr, uint8_t prsOsr); - int16_t getContResults(int32_t *tempBuffer, uint8_t &tempCount, int32_t *prsBuffer, uint8_t &prsCount); + int16_t getContResults(float *tempBuffer, uint8_t &tempCount, float *prsBuffer, uint8_t &prsCount); //Interrupt Control int16_t setInterruptPolarity(uint8_t polarity); @@ -122,11 +122,11 @@ private: int16_t configTemp(uint8_t temp_mr, uint8_t temp_osr); int16_t configPressure(uint8_t prs_mr, uint8_t prs_osr); uint16_t calcBusyTime(uint16_t temp_rate, uint16_t temp_osr); - int16_t getTemp(int32_t *result); - int16_t getPressure(int32_t *result); - int16_t getFIFOvalue(int32_t *value); - int32_t calcTemp(int32_t raw); - int32_t calcPressure(int32_t raw); + int16_t getTemp(float *result); + int16_t getPressure(float *result); + int16_t getFIFOvalue(float *value); + float calcTemp(float raw); + float calcPressure(float raw); //bus specific int16_t readByte(uint8_t regAddress); diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index 3f508b7d8..926a437ad 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -51,8 +51,8 @@ bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) { HP303BSensor.begin(hp303b_address); - int32_t t; - int32_t p; + float t; + float p; int16_t ret; ret = HP303BSensor.measureTempOnce(t, oversampling); @@ -96,9 +96,15 @@ void HP303B_Show(bool json) if (HP303B_Read(temperature, pressure, address)) { + char str_temperature[33]; + dtostrfd(temperature, Settings.flag2.temperature_resolution, str_temperature); + char str_pressure[33]; + dtostrfd(pressure, Settings.flag2.pressure_resolution, str_pressure); + if (json) { - ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_PRESSURE "\":%d"), temperature, pressure); + ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), str_temperature, str_pressure); + ResponseJsonEnd(); #ifdef USE_DOMOTICZ if (0 == tele_period) { @@ -109,11 +115,6 @@ void HP303B_Show(bool json) } else { - char str_temperature[33]; - dtostrfd(temperature, Settings.flag2.temperature_resolution, str_temperature); - char str_pressure[33]; - dtostrfd(pressure, Settings.flag2.pressure_resolution, str_pressure); - WSContentSend_PD(HTTP_SNS_TEMP, "HP303B", str_temperature, TempUnit()); WSContentSend_PD(HTTP_SNS_PRESSURE, "HP303B", str_pressure, PressureUnit().c_str()); #endif // USE_WEBSERVER From aa5587f9e19444d33aae379e8f9dcadc1d2cad30 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Mon, 8 Jun 2020 08:58:38 +0200 Subject: [PATCH 04/10] Mover begin() to detect function --- tasmota/xsns_73_hp303b.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index 926a437ad..abff91f09 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -49,8 +49,6 @@ char types[7] = "HP303B"; bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) { - HP303BSensor.begin(hp303b_address); - float t; float p; int16_t ret; @@ -80,6 +78,8 @@ void HP303B_Detect(void) continue; } + HP303BSensor.begin(addresses[i]); + float t; float p; if (HP303B_Read(t, p, addresses[i])) @@ -87,6 +87,7 @@ void HP303B_Detect(void) I2cSetActiveFound(addresses[i], types); address = addresses[i]; type = 1; + break; } } } From d6e1ecbe2624695552c101d501ea8ded9193d12e Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Mon, 8 Jun 2020 09:13:01 +0200 Subject: [PATCH 05/10] Moved global variables to struct --- tasmota/xsns_73_hp303b.ino | 47 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index abff91f09..5a16ca905 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -35,16 +35,17 @@ #include // HP303B Opject LOLIN_HP303B HP303BSensor = LOLIN_HP303B(); +uint8_t bhp303b_addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; -uint8_t address; -uint8_t addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; -uint8_t type = 0; -uint8_t valid = 0; -float temperature; -float pressure; -int16_t oversampling = 7; -char types[7] = "HP303B"; - +struct BHP303B { + uint8_t address; + uint8_t type = 0; + uint8_t valid = 0; + float temperature; + float pressure; + int16_t oversampling = 7; + char types[7] = "HP303B"; +} bhp303b_sensor; /*********************************************************************************************/ bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) @@ -53,11 +54,11 @@ bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) float p; int16_t ret; - ret = HP303BSensor.measureTempOnce(t, oversampling); + ret = HP303BSensor.measureTempOnce(t, bhp303b_sensor.oversampling); if (ret != 0) return false; - ret = HP303BSensor.measurePressureOnce(p, oversampling); + ret = HP303BSensor.measurePressureOnce(p, bhp303b_sensor.oversampling); if (ret != 0) return false; @@ -71,22 +72,22 @@ bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) void HP303B_Detect(void) { - for (uint32_t i = 0; i < sizeof(addresses); i++) + for (uint32_t i = 0; i < sizeof(bhp303b_addresses); i++) { - if (!I2cSetDevice(addresses[i])) + if (!I2cSetDevice(bhp303b_addresses[i])) { continue; } - HP303BSensor.begin(addresses[i]); + HP303BSensor.begin(bhp303b_addresses[i]); float t; float p; - if (HP303B_Read(t, p, addresses[i])) + if (HP303B_Read(t, p, bhp303b_addresses[i])) { - I2cSetActiveFound(addresses[i], types); - address = addresses[i]; - type = 1; + I2cSetActiveFound(bhp303b_addresses[i], bhp303b_sensor.types); + bhp303b_sensor.address = bhp303b_addresses[i]; + bhp303b_sensor.type = 1; break; } } @@ -95,12 +96,12 @@ void HP303B_Detect(void) void HP303B_Show(bool json) { - if (HP303B_Read(temperature, pressure, address)) + if (HP303B_Read(bhp303b_sensor.temperature, bhp303b_sensor.pressure, bhp303b_sensor.address)) { char str_temperature[33]; - dtostrfd(temperature, Settings.flag2.temperature_resolution, str_temperature); + dtostrfd(bhp303b_sensor.temperature, Settings.flag2.temperature_resolution, str_temperature); char str_pressure[33]; - dtostrfd(pressure, Settings.flag2.pressure_resolution, str_pressure); + dtostrfd(bhp303b_sensor.pressure, Settings.flag2.pressure_resolution, str_pressure); if (json) { @@ -109,7 +110,7 @@ void HP303B_Show(bool json) #ifdef USE_DOMOTICZ if (0 == tele_period) { - DomoticzSensor(DZ_TEMP, temperature); + DomoticzSensor(DZ_TEMP, bhp303b_sensor.temperature); } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER @@ -140,7 +141,7 @@ bool Xsns73(uint8_t function) { HP303B_Detect(); } - else if (type) + else if (bhp303b_sensor.type) { switch (function) { From abfa4f4fcd8fb24b5d47a8a599cadd5acd8e5bda Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Mon, 8 Jun 2020 10:19:51 +0200 Subject: [PATCH 06/10] refactored implementation --- tasmota/xsns_73_hp303b.ino | 50 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index 5a16ca905..ad439e555 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -44,12 +44,14 @@ struct BHP303B { float temperature; float pressure; int16_t oversampling = 7; - char types[7] = "HP303B"; + char name[7] = "HP303B"; } bhp303b_sensor; /*********************************************************************************************/ -bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) +bool HP303B_Read() { + if (bhp303b_sensor.valid) { bhp303b_sensor.valid--; } + float t; float p; int16_t ret; @@ -62,9 +64,10 @@ bool HP303B_Read(float &temperature, float &pressure, uint8_t hp303b_address) if (ret != 0) return false; - temperature = (float)ConvertTemp(t); - pressure = (float)ConvertPressure(p) / 100; //conversion to hPa + bhp303b_sensor.temperature = (float)ConvertTemp(t); + bhp303b_sensor.pressure = (float)ConvertPressure(p) / 100; //conversion to hPa + bhp303b_sensor.valid = SENSOR_MAX_MISS; return true; } @@ -74,29 +77,33 @@ void HP303B_Detect(void) { for (uint32_t i = 0; i < sizeof(bhp303b_addresses); i++) { - if (!I2cSetDevice(bhp303b_addresses[i])) - { - continue; - } + if (I2cActive(bhp303b_addresses[i])) { return; } - HP303BSensor.begin(bhp303b_addresses[i]); + bhp303b_sensor.address = bhp303b_addresses[i]; - float t; - float p; - if (HP303B_Read(t, p, bhp303b_addresses[i])) + HP303BSensor.begin( bhp303b_sensor.address); + + if (HP303B_Read()) { - I2cSetActiveFound(bhp303b_addresses[i], bhp303b_sensor.types); - bhp303b_sensor.address = bhp303b_addresses[i]; + I2cSetActiveFound(bhp303b_sensor.address, bhp303b_sensor.name); bhp303b_sensor.type = 1; break; } } } +void HP303B_EverySecond(void) +{ + if (uptime &1) { + if (!HP303B_Read()) { + AddLogMissed(bhp303b_sensor.name, bhp303b_sensor.valid); + } + } +} + void HP303B_Show(bool json) { - - if (HP303B_Read(bhp303b_sensor.temperature, bhp303b_sensor.pressure, bhp303b_sensor.address)) + if (bhp303b_sensor.valid) { char str_temperature[33]; dtostrfd(bhp303b_sensor.temperature, Settings.flag2.temperature_resolution, str_temperature); @@ -130,21 +137,20 @@ void HP303B_Show(bool json) bool Xsns73(uint8_t function) { - if (!I2cEnabled(XI2C_52)) - { - return false; - } + if (!I2cEnabled(XI2C_52)) { return false; } bool result = false; - if (FUNC_INIT == function) - { + if (FUNC_INIT == function) { HP303B_Detect(); } else if (bhp303b_sensor.type) { switch (function) { + case FUNC_EVERY_SECOND: + HP303B_EverySecond(); + break; case FUNC_JSON_APPEND: HP303B_Show(1); break; From 92643e89d023aafbfc4af8e09cc4de9771f5627b Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Mon, 8 Jun 2020 20:37:04 +0200 Subject: [PATCH 07/10] Added support for multiple i2c addresses --- lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp | 32 +++---- lib/LOLIN_HP303B/src/LOLIN_HP303B.h | 10 +-- tasmota/xsns_73_hp303b.ino | 115 ++++++++++++++------------ 3 files changed, 84 insertions(+), 73 deletions(-) diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp index fdeebd6a0..7f7f60a3f 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp @@ -35,7 +35,7 @@ LOLIN_HP303B::~LOLIN_HP303B(void) * &bus: I2CBus which connects MC to HP303B * slaveAddress: Address of the HP303B (0x77 or 0x76) */ -void LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress) +uint8_t LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress) { //this flag will show if the initialization was successful m_initFail = 0U; @@ -50,20 +50,20 @@ void LOLIN_HP303B::begin(TwoWire &bus, uint8_t slaveAddress) delay(50); //startup time of HP303B - init(); + return init(); } -void LOLIN_HP303B::begin(uint8_t slaveAddress) +uint8_t LOLIN_HP303B::begin(uint8_t slaveAddress) { - begin(Wire,slaveAddress); + return begin(Wire,slaveAddress); } /** * SPI begin function for HP303B with 4-wire SPI */ -void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect) +uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect) { - begin(bus, chipSelect, 0U); + return begin(bus, chipSelect, 0U); } /** @@ -74,7 +74,7 @@ void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect) * threeWire: 1 if HP303B is connected with 3-wire SPI * 0 if HP303B is connected with 4-wire SPI (standard) */ -void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire) +uint8_t LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire) { //this flag will show if the initialization was successful m_initFail = 0U; @@ -102,11 +102,11 @@ void LOLIN_HP303B::begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire) if(writeByte(HP303B__REG_ADR_SPI3W, HP303B__REG_CONTENT_SPI3W)) { m_initFail = 1U; - return; + return 0U; } } - init(); + return init(); } /** @@ -840,14 +840,14 @@ int16_t LOLIN_HP303B::correctTemp(void) * This function has to be called from begin() * and requires a valid bus initialization. */ -void LOLIN_HP303B::init(void) +uint8_t LOLIN_HP303B::init(void) { int16_t prodId = readByteBitfield(HP303B__REG_INFO_PROD_ID); if(prodId != HP303B__PROD_ID) { //Connected device is not a HP303B m_initFail = 1U; - return; + return 0U; } m_productID = prodId; @@ -855,7 +855,7 @@ void LOLIN_HP303B::init(void) if(revId < 0) { m_initFail = 1U; - return; + return 0U; } m_revisionID = revId; @@ -864,7 +864,7 @@ void LOLIN_HP303B::init(void) if(sensor < 0) { m_initFail = 1U; - return; + return 0U; } //...and use this sensor for temperature measurement @@ -872,14 +872,14 @@ void LOLIN_HP303B::init(void) if(writeByteBitfield((uint8_t)sensor, HP303B__REG_INFO_TEMP_SENSOR) < 0) { m_initFail = 1U; - return; + return 0U; } //read coefficients if(readcoeffs() < 0) { m_initFail = 1U; - return; + return 0U; } //set to standby for further configuration @@ -901,6 +901,8 @@ void LOLIN_HP303B::init(void) // Fix IC with a fuse bit problem, which lead to a wrong temperature // Should not affect ICs without this problem correctTemp(); + + return 1U; } diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h index ce65e17f1..651b80380 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h @@ -19,10 +19,10 @@ public: //destructor ~LOLIN_HP303B(void); //begin - void begin(TwoWire &bus, uint8_t slaveAddress); - void begin(uint8_t slaveAddress=HP303B__STD_SLAVE_ADDRESS); - void begin(SPIClass &bus, int32_t chipSelect); - void begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire); + uint8_t begin(TwoWire &bus, uint8_t slaveAddress); + uint8_t begin(uint8_t slaveAddress=HP303B__STD_SLAVE_ADDRESS); + uint8_t begin(SPIClass &bus, int32_t chipSelect); + uint8_t begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire); //end void end(void); @@ -115,7 +115,7 @@ private: uint8_t m_threeWire; //measurement - void init(void); + uint8_t init(void); int16_t readcoeffs(void); int16_t setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure); int16_t setOpMode(uint8_t opMode); diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index ad439e555..b56fa6ded 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -29,45 +29,47 @@ #define XSNS_73 73 #define XI2C_52 52 // See I2CDEVICES.md -#define HP303B_ADDR1 0x77 -#define HP303B_ADDR2 0x76 - #include -// HP303B Opject +// HP303B Object LOLIN_HP303B HP303BSensor = LOLIN_HP303B(); -uint8_t bhp303b_addresses[2] = {HP303B_ADDR1, HP303B_ADDR2}; + +#define HP303B_MAX_SENSORS 2 +#define HP303B_START_ADDRESS 0x76 + +struct { +char types[7] = "HP303B"; +uint8_t count = 0; +int16_t oversampling = 7; +} hp303b_cfg; struct BHP303B { uint8_t address; - uint8_t type = 0; uint8_t valid = 0; - float temperature; - float pressure; - int16_t oversampling = 7; - char name[7] = "HP303B"; -} bhp303b_sensor; + float temperature = NAN; + float pressure = NAN; +} hp303b_sensor[HP303B_MAX_SENSORS]; /*********************************************************************************************/ -bool HP303B_Read() +bool HP303B_Read(uint8_t hp303b_idx) { - if (bhp303b_sensor.valid) { bhp303b_sensor.valid--; } + if (hp303b_sensor[hp303b_idx].valid) { hp303b_sensor[hp303b_idx].valid--; } float t; float p; int16_t ret; - ret = HP303BSensor.measureTempOnce(t, bhp303b_sensor.oversampling); + ret = HP303BSensor.measureTempOnce(t, hp303b_cfg.oversampling); if (ret != 0) return false; - ret = HP303BSensor.measurePressureOnce(p, bhp303b_sensor.oversampling); + ret = HP303BSensor.measurePressureOnce(p, hp303b_cfg.oversampling); if (ret != 0) return false; - bhp303b_sensor.temperature = (float)ConvertTemp(t); - bhp303b_sensor.pressure = (float)ConvertPressure(p) / 100; //conversion to hPa + hp303b_sensor[hp303b_idx].temperature = (float)ConvertTemp(t); + hp303b_sensor[hp303b_idx].pressure = (float)ConvertPressure(p) / 100; //conversion to hPa - bhp303b_sensor.valid = SENSOR_MAX_MISS; + hp303b_sensor[hp303b_idx].valid = SENSOR_MAX_MISS; return true; } @@ -75,18 +77,15 @@ bool HP303B_Read() void HP303B_Detect(void) { - for (uint32_t i = 0; i < sizeof(bhp303b_addresses); i++) + for (uint32_t i = 0; i < HP303B_MAX_SENSORS; i++) { - if (I2cActive(bhp303b_addresses[i])) { return; } + if (I2cActive(HP303B_START_ADDRESS + i)) { return; } - bhp303b_sensor.address = bhp303b_addresses[i]; - - HP303BSensor.begin( bhp303b_sensor.address); - - if (HP303B_Read()) + if (HP303BSensor.begin(HP303B_START_ADDRESS + i)) { - I2cSetActiveFound(bhp303b_sensor.address, bhp303b_sensor.name); - bhp303b_sensor.type = 1; + hp303b_sensor[hp303b_cfg.count].address = HP303B_START_ADDRESS + i; + I2cSetActiveFound(hp303b_sensor[hp303b_cfg.count].address, hp303b_cfg.types); + hp303b_cfg.count++; break; } } @@ -94,39 +93,49 @@ void HP303B_Detect(void) void HP303B_EverySecond(void) { - if (uptime &1) { - if (!HP303B_Read()) { - AddLogMissed(bhp303b_sensor.name, bhp303b_sensor.valid); + for (uint32_t i = 0; i < hp303b_cfg.count; i++) { + if (uptime &1) { + if (!HP303B_Read(i)) { + AddLogMissed(hp303b_cfg.types, hp303b_sensor[i].valid); } } + } } void HP303B_Show(bool json) { - if (bhp303b_sensor.valid) - { - char str_temperature[33]; - dtostrfd(bhp303b_sensor.temperature, Settings.flag2.temperature_resolution, str_temperature); - char str_pressure[33]; - dtostrfd(bhp303b_sensor.pressure, Settings.flag2.pressure_resolution, str_pressure); - - if (json) - { - ResponseAppend_P(PSTR(",\"HP303B\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), str_temperature, str_pressure); - ResponseJsonEnd(); -#ifdef USE_DOMOTICZ - if (0 == tele_period) - { - DomoticzSensor(DZ_TEMP, bhp303b_sensor.temperature); - } -#endif // USE_DOMOTICZ -#ifdef USE_WEBSERVER + for (uint32_t i = 0; i < hp303b_cfg.count; i++) { + char sensor_name[12]; + strlcpy(sensor_name, hp303b_cfg.types, sizeof(sensor_name)); + if (hp303b_cfg.count > 1) { + snprintf_P(sensor_name, sizeof(sensor_name), PSTR("%s%c0x%02X"), sensor_name, IndexSeparator(), hp303b_sensor[i].address); // MCP9808-18, MCP9808-1A etc. } - else + + if (hp303b_sensor[i].valid) { - WSContentSend_PD(HTTP_SNS_TEMP, "HP303B", str_temperature, TempUnit()); - WSContentSend_PD(HTTP_SNS_PRESSURE, "HP303B", str_pressure, PressureUnit().c_str()); -#endif // USE_WEBSERVER + char str_temperature[33]; + dtostrfd(hp303b_sensor[i].temperature, Settings.flag2.temperature_resolution, str_temperature); + char str_pressure[33]; + dtostrfd(hp303b_sensor[i].pressure, Settings.flag2.pressure_resolution, str_pressure); + + if (json) + { + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), sensor_name, str_temperature, str_pressure); + ResponseJsonEnd(); + #ifdef USE_DOMOTICZ + if (0 == tele_period) + { + DomoticzSensor(DZ_TEMP, hp303b_sensor[i].temperature); + } + #endif // USE_DOMOTICZ + #ifdef USE_WEBSERVER + } + else + { + WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, str_temperature, TempUnit()); + WSContentSend_PD(HTTP_SNS_PRESSURE, sensor_name, str_pressure, PressureUnit().c_str()); + #endif // USE_WEBSERVER + } } } } @@ -144,7 +153,7 @@ bool Xsns73(uint8_t function) if (FUNC_INIT == function) { HP303B_Detect(); } - else if (bhp303b_sensor.type) + else if (hp303b_cfg.count) { switch (function) { From 9d2d22558c9150a23eb86a88ba4fad0a4a9a22a5 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Tue, 9 Jun 2020 09:14:44 +0200 Subject: [PATCH 08/10] Resolved review comments --- tasmota/xsns_73_hp303b.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index b56fa6ded..01145e0d1 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -79,14 +79,13 @@ void HP303B_Detect(void) { for (uint32_t i = 0; i < HP303B_MAX_SENSORS; i++) { - if (I2cActive(HP303B_START_ADDRESS + i)) { return; } + if (!I2cSetDevice(HP303B_START_ADDRESS + i )) { continue; } if (HP303BSensor.begin(HP303B_START_ADDRESS + i)) { hp303b_sensor[hp303b_cfg.count].address = HP303B_START_ADDRESS + i; I2cSetActiveFound(hp303b_sensor[hp303b_cfg.count].address, hp303b_cfg.types); hp303b_cfg.count++; - break; } } } @@ -108,7 +107,7 @@ void HP303B_Show(bool json) char sensor_name[12]; strlcpy(sensor_name, hp303b_cfg.types, sizeof(sensor_name)); if (hp303b_cfg.count > 1) { - snprintf_P(sensor_name, sizeof(sensor_name), PSTR("%s%c0x%02X"), sensor_name, IndexSeparator(), hp303b_sensor[i].address); // MCP9808-18, MCP9808-1A etc. + snprintf_P(sensor_name, sizeof(sensor_name), PSTR("%s%c0x%02X"), sensor_name, IndexSeparator(), hp303b_sensor[i].address); // HP303B-0x76, HP303B-0x77 } if (hp303b_sensor[i].valid) @@ -123,8 +122,8 @@ void HP303B_Show(bool json) ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), sensor_name, str_temperature, str_pressure); ResponseJsonEnd(); #ifdef USE_DOMOTICZ - if (0 == tele_period) - { + // Domoticz and knx only support one temp sensor + if ((0 == tele_period) && (0 == i)) { DomoticzSensor(DZ_TEMP, hp303b_sensor[i].temperature); } #endif // USE_DOMOTICZ From 325564fbc7da74211b70b166f27bcea9d832a022 Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Wed, 10 Jun 2020 10:03:02 +0200 Subject: [PATCH 09/10] Added option to set i2c address in measure...Once in lib --- lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp | 46 ++++++++++++++++++++++++--- lib/LOLIN_HP303B/src/LOLIN_HP303B.h | 6 ++-- tasmota/xsns_73_hp303b.ino | 4 +-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp index 7f7f60a3f..b73e12b83 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp @@ -183,7 +183,23 @@ int16_t LOLIN_HP303B::standby(void) */ int16_t LOLIN_HP303B::measureTempOnce(float &result) { - return measureTempOnce(result, m_tempOsr); + return measureTempOnce(result, m_slaveAddress, m_tempOsr); +} + +/** + * performs one temperature measurement and writes result to the given address + * + * &result: reference to a 32-Bit signed Integer value where the result will be written + * It will not be written if result==NULL + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress) +{ + return measureTempOnce(result, slaveAddress, m_tempOsr); } /** @@ -202,8 +218,11 @@ int16_t LOLIN_HP303B::measureTempOnce(float &result) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t oversamplingRate) +int16_t LOLIN_HP303B::measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate) { + //Set I2C bus connection + m_slaveAddress = slaveAddress; + //Start measurement int16_t ret = startMeasureTempOnce(oversamplingRate); if(ret!=HP303B__SUCCEEDED) @@ -288,7 +307,23 @@ int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate) */ int16_t LOLIN_HP303B::measurePressureOnce(float &result) { - return measurePressureOnce(result, m_prsOsr); + return measurePressureOnce(result, m_slaveAddress, m_prsOsr); +} + +/** + * performs one pressure measurement and writes result to the given address + * + * &result: reference to a 32-Bit signed Integer value where the result will be written + * It will not be written if result==NULL + * returns: 0 on success + * -4 if the HP303B is could not finish its measurement in time + * -3 if the HP303B is already busy + * -2 if the object initialization failed + * -1 on other fail + */ +int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress) +{ + return measurePressureOnce(result, slaveAddress, m_prsOsr); } /** @@ -307,8 +342,11 @@ int16_t LOLIN_HP303B::measurePressureOnce(float &result) * -2 if the object initialization failed * -1 on other fail */ -int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t oversamplingRate) +int16_t LOLIN_HP303B::measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate) { + //Set I2C bus connection + m_slaveAddress = slaveAddress; + //start the measurement int16_t ret = startMeasurePressureOnce(oversamplingRate); if(ret != HP303B__SUCCEEDED) diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h index 651b80380..4d04ff6da 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.h +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.h @@ -35,11 +35,13 @@ public: //Command Mode int16_t measureTempOnce(float &result); - int16_t measureTempOnce(float &result, uint8_t oversamplingRate); + int16_t measureTempOnce(float &result, uint8_t slaveAddress); + int16_t measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate); int16_t startMeasureTempOnce(void); int16_t startMeasureTempOnce(uint8_t oversamplingRate); int16_t measurePressureOnce(float &result); - int16_t measurePressureOnce(float &result, uint8_t oversamplingRate); + int16_t measurePressureOnce(float &result, uint8_t slaveAddress); + int16_t measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate); int16_t startMeasurePressureOnce(void); int16_t startMeasurePressureOnce(uint8_t oversamplingRate); int16_t getSingleResult(float &result); diff --git a/tasmota/xsns_73_hp303b.ino b/tasmota/xsns_73_hp303b.ino index 01145e0d1..1be0a1606 100644 --- a/tasmota/xsns_73_hp303b.ino +++ b/tasmota/xsns_73_hp303b.ino @@ -58,11 +58,11 @@ bool HP303B_Read(uint8_t hp303b_idx) float p; int16_t ret; - ret = HP303BSensor.measureTempOnce(t, hp303b_cfg.oversampling); + ret = HP303BSensor.measureTempOnce(t, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling); if (ret != 0) return false; - ret = HP303BSensor.measurePressureOnce(p, hp303b_cfg.oversampling); + ret = HP303BSensor.measurePressureOnce(p, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling); if (ret != 0) return false; From 8cbb35ec4fbb00e29e754c0602c75af1a2c70fce Mon Sep 17 00:00:00 2001 From: Robert Jaakke Date: Wed, 10 Jun 2020 21:54:32 +0200 Subject: [PATCH 10/10] Removed m_initFail check because we moved it to begin() --- lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp index b73e12b83..c6f8aeb1d 100644 --- a/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp +++ b/lib/LOLIN_HP303B/src/LOLIN_HP303B.cpp @@ -147,11 +147,6 @@ uint8_t LOLIN_HP303B::getRevisionId(void) */ int16_t LOLIN_HP303B::standby(void) { - //abort if initialization failed - if(m_initFail) - { - return HP303B__FAIL_INIT_FAILED; - } //set device to idling mode int16_t ret = setOpMode(IDLE); if(ret != HP303B__SUCCEEDED) @@ -270,11 +265,6 @@ int16_t LOLIN_HP303B::startMeasureTempOnce(void) */ int16_t LOLIN_HP303B::startMeasureTempOnce(uint8_t oversamplingRate) { - //abort if initialization failed - if(m_initFail) - { - return HP303B__FAIL_INIT_FAILED; - } //abort if device is not in idling mode if(m_opMode!=IDLE) { @@ -394,11 +384,6 @@ int16_t LOLIN_HP303B::startMeasurePressureOnce(void) */ int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate) { - //abort if initialization failed - if(m_initFail) - { - return HP303B__FAIL_INIT_FAILED; - } //abort if device is not in idling mode if(m_opMode != IDLE) { @@ -428,12 +413,6 @@ int16_t LOLIN_HP303B::startMeasurePressureOnce(uint8_t oversamplingRate) */ int16_t LOLIN_HP303B::getSingleResult(float &result) { - //abort if initialization failed - if(m_initFail) - { - return HP303B__FAIL_INIT_FAILED; - } - //read finished bit for current opMode int16_t rdy; switch(m_opMode)