mirror of https://github.com/arendst/Tasmota.git
Add SEN5X to I2C devices (#17736)
This commit is contained in:
parent
9e522e8fa3
commit
2ed602057c
|
@ -118,6 +118,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
|
|||
| USE_MGS | - | - / x | - | x | - | - |
|
||||
| USE_SGP30 | - | - / x | - | x | - | - |
|
||||
| USE_SGP40 | - | - / x | - | x | - | - |
|
||||
| USE_SEN5X | - | - / x | - | x | - | - |
|
||||
| USE_SI1145 | - | - / - | - | - | - | - |
|
||||
| USE_LM75AD | - | - / x | - | x | - | - |
|
||||
| USE_APDS9960 | - | - / - | - | - | - | - |
|
||||
|
|
|
@ -198,6 +198,7 @@ In addition to @arendst the following code is mainly owned by:
|
|||
| xsns_100_ina3221 | @barbudor
|
||||
| xsns_101_hmc5883l | Andreas Achtzehn
|
||||
| xsns_102_ld2410 | @arendst
|
||||
| xsns_103_sen5x | @tyeth
|
||||
| |
|
||||
| Libraries |
|
||||
| |
|
||||
|
|
|
@ -111,3 +111,4 @@ Index | Define | Driver | Device | Address(es) | Description
|
|||
73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor
|
||||
74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller
|
||||
75 | USE_PCA9632 | xdrv_64 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver
|
||||
76 | USE_SEN5X | xsns_103 | SEN5X | 0x69 | Gas (VOC/NOx index) and air quality (PPM <1,<2.5,<4,<10)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
AlignAfterOpenBracket: Align
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
IndentCaseLabels: true
|
||||
SpacesBeforeTrailingComments: 2
|
||||
PointerAlignment: Left
|
||||
AlignEscapedNewlines: Left
|
||||
ForEachMacros: ['TEST_GROUP', 'TEST']
|
||||
...
|
|
@ -0,0 +1,161 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_
|
||||
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
|
||||
|
||||
`Unreleased`_
|
||||
-------------
|
||||
|
||||
|
||||
`0.6.0`_ 2022-06-22
|
||||
-------------------
|
||||
|
||||
- Fix compiler warnings in SensirionErrors.cpp
|
||||
- Allow drivers to choose CRC function
|
||||
|
||||
`0.5.3`_ 2021-10-19
|
||||
-------------------
|
||||
|
||||
- Add support for sensor specific errors
|
||||
- Update keywords.txt
|
||||
|
||||
|
||||
`0.5.2`_ 2021-08-03
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
.....
|
||||
|
||||
- Fix CRC insertion in ``SensirionI2CTxFrame`` when more then one parameter
|
||||
is sent to the sensor.
|
||||
|
||||
`0.5.1`_ 2021-07-08
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Adjusted deprecation warnings
|
||||
|
||||
`0.5.0`_ 2021-07-07
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Enable SensirionTxFrame to incorporate Uint8 and Uint16 commands
|
||||
|
||||
|
||||
`0.4.3`_ 2021-02-12
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Added ``const`` modifier to functions which process MOSI array data.
|
||||
|
||||
`0.4.2`_ 2021-01-29
|
||||
-------------------
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Renamed the library header from ``SensirionCoreArduinoLibrary.h`` to ``SensirionCore.h``.
|
||||
We keep the old header for legacy support.
|
||||
|
||||
`0.4.1`_ 2021-01-28
|
||||
-------------------
|
||||
|
||||
Fixed
|
||||
.....
|
||||
|
||||
- Properly handle I2C write errors
|
||||
|
||||
|
||||
`0.4.0`_ 2021-01-20
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Documentation for all functions.
|
||||
|
||||
Breaking
|
||||
........
|
||||
|
||||
- Change interface of ``errorToString()`` function to include length of the
|
||||
provided buffer.
|
||||
|
||||
Removed
|
||||
.......
|
||||
|
||||
- Removed ``reset()`` function from ``SensirionI2CTxFrame`` since the
|
||||
functionality is not needed.
|
||||
|
||||
|
||||
`0.3.0`_ 2021-01-13
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Core implementation for I2C communication. This includes a RX and TX frame
|
||||
and a I2C communication class.
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- SHDLC and I2C RX frame inherit from a RX frame base class.
|
||||
- ESP8266 test board from esp8266:esp8266:arduino to esp8266:esp8266:generic.
|
||||
- Sorted errors into general, SHDLC and I2C errors.
|
||||
- Replace C style casts with ``static_cast``.
|
||||
|
||||
|
||||
`0.2.0`_ 2021-01-11
|
||||
-------------------
|
||||
|
||||
Added
|
||||
.....
|
||||
|
||||
- Explanation what SHDLC is in README.
|
||||
- ``SensirionErrors.h`` to ``SensirionCoreArduinoLibrary.h``.
|
||||
- ``sendAndReceiveFrame()`` function to ``SensirionShdlcCommunication``. This
|
||||
function combines ``sendFrame()`` and ``receiveFrame()`` into one function and
|
||||
adds additional error checking.
|
||||
|
||||
Changed
|
||||
.......
|
||||
|
||||
- Rename DeviceError to ExecutionError.
|
||||
- Move check for execution error after the whole frame is read and checksum is
|
||||
checked. This prevents that a wrong checksum can't be displayed as an
|
||||
execution error.
|
||||
|
||||
Removed
|
||||
.......
|
||||
|
||||
- ``reset()`` function from ``SensirionShdlcTxFrame`` and ``SensirionShdlcRxFrame``,
|
||||
since one can just create a new frame object which has the same effect.
|
||||
|
||||
`0.1.0`_ 2021-01-07
|
||||
-------------------
|
||||
|
||||
- Initial release
|
||||
|
||||
|
||||
.. _Unreleased: https://github.com/Sensirion/arduino-core/compare/0.6.0...main
|
||||
.. _0.6.0: https://github.com/Sensirion/arduino-core/compare/0.6.0...0.5.3
|
||||
.. _0.5.3: https://github.com/Sensirion/arduino-core/compare/0.5.2...0.5.3
|
||||
.. _0.5.2: https://github.com/Sensirion/arduino-core/compare/0.5.1...0.5.2
|
||||
.. _0.5.1: https://github.com/Sensirion/arduino-core/compare/0.5.0...0.5.1
|
||||
.. _0.5.0: https://github.com/Sensirion/arduino-core/compare/0.4.3...0.5.0
|
||||
.. _0.4.3: https://github.com/Sensirion/arduino-core/compare/0.4.2...0.4.3
|
||||
.. _0.4.2: https://github.com/Sensirion/arduino-core/compare/0.4.1...0.4.2
|
||||
.. _0.4.1: https://github.com/Sensirion/arduino-core/compare/0.4.0...0.4.1
|
||||
.. _0.4.0: https://github.com/Sensirion/arduino-core/compare/0.3.0...0.4.0
|
||||
.. _0.3.0: https://github.com/Sensirion/arduino-core/compare/0.2.0...0.3.0
|
||||
.. _0.2.0: https://github.com/Sensirion/arduino-core/compare/0.1.0...0.2.0
|
||||
.. _0.1.0: https://github.com/Sensirion/arduino-core/releases/tag/0.1.0
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Sensirion AG
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,139 @@
|
|||
<!-- Downloaded from https://github.com/Sensirion/arduino-core
|
||||
on 10/01/2023 at commit bd2d3ce9355a3a1997beeb820e59072ef9430d5e -->
|
||||
# Sensirion Arduino Core Library
|
||||
|
||||
This library provides SHDLC and I2C protocol implementations for Sensirion
|
||||
sensors. There shouldn't be a reason to use it directly, but is required by the
|
||||
sensor driver libraries provided here:
|
||||
|
||||
- [SCD4x](https://github.com/Sensirion/arduino-i2c-scd4x)
|
||||
- [SVM40-I2C](https://github.com/Sensirion/arduino-i2c-svm40)
|
||||
- [SVM40-UART](https://github.com/Sensirion/arduino-uart-svm40)
|
||||
- [SFA3x-I2C](https://github.com/Sensirion/arduino-i2c-sfa3x)
|
||||
- [SFA3x-UART](https://github.com/Sensirion/arduino-uart-sfa3x)
|
||||
|
||||
# More Drivers
|
||||
|
||||
Not looking for Arduino drivers? Check out our other drivers here:
|
||||
|
||||
- [Embedded](https://github.com/Sensirion/info#repositories)
|
||||
- [Python](https://github.com/Sensirion/info#python-drivers)
|
||||
|
||||
# Usage
|
||||
|
||||
## SHDLC
|
||||
|
||||
SHDLC (Sensirion High-Level Data Link Control) is a byte-oriented master-slave
|
||||
communication protocol based on [ISO
|
||||
HDLC](https://en.wikipedia.org/wiki/High-Level_Data_Link_Control). It is used
|
||||
to control some of Sensirion’s devices (for example mass flow controllers). The
|
||||
detailed protocol documentation is not publicly available (yet). If you need
|
||||
it, please contact our [customer
|
||||
support](https://www.sensirion.com/en/about-us/contact/).
|
||||
|
||||
This library provides the following classes for communication with Sensirion
|
||||
Sensors using the SHDLC protocol.
|
||||
- `SensirionShdlcTxFrame`
|
||||
- `SensirionShdlcRxFrame`
|
||||
- `SensirionShdlcCommunication`
|
||||
|
||||
### Example Usage
|
||||
First initialize an instance of `SensirionShdlcTxFrame` and
|
||||
`SensirionShdlcRxFrame` with a properly sized buffer. A good worst case
|
||||
estimation for the buffer size is `2 * (n+6)` where `n` is the number of bytes
|
||||
you want to send. After that you can build your frame by first calling
|
||||
`begin()`. Information about the correct COMMAND and ADDRESS can be found on
|
||||
the data sheet of your sensor. Then you can add data to the frame by using
|
||||
different add member functions. See the code below for examples. After adding
|
||||
your data finish the frame by calling `finish()`.
|
||||
|
||||
To send this frame to the sensor you first need to initialize the correct
|
||||
Stream object (Serial,UART,...) to talk to your sensor. Don't forget to also
|
||||
call the `.begin()` function with the right configuration. Then call the static
|
||||
function `sendAndReceiveFrame()` from `SensirionShdlcCommunication` as shown
|
||||
below. You need to replace `STREAMOBJECT` with the initialized Stream object of
|
||||
your choice. Additionally you need to provide a timeout for to receive data
|
||||
back, consult the data sheet of your sensor for information on the best timeout
|
||||
value.
|
||||
|
||||
You can decode the frame by using the different get members to convert the
|
||||
received data to desired data types.
|
||||
|
||||
All functions return a error code if an error occurs during execution and zero
|
||||
otherwise.
|
||||
|
||||
```cpp
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
txFrame.begin(COMMAND, ADDRESS, DATALENGTH);
|
||||
|
||||
txFrame.addUInt8(UINT8);
|
||||
txFrame.addUInt32(UINT32);
|
||||
|
||||
txFrame.finish();
|
||||
|
||||
SensirionShdlcCommunication::sendAndReceiveFrame(STREAMOBJECT, txFrame, rxFrame, TIMEOUT);
|
||||
|
||||
rxFrame.getUInt16(UINT16);
|
||||
rxFrame.getFloat(FLOAT);
|
||||
|
||||
```
|
||||
|
||||
## I2C
|
||||
|
||||
This library provides the following classes for communication with Sensirion
|
||||
Sensors using the I2C protocol.
|
||||
- `SensirionI2cTxFrame`
|
||||
- `SensirionI2cRxFrame`
|
||||
- `SensirionI2cCommunication`
|
||||
|
||||
### Example Usage
|
||||
|
||||
First initialize an instance of `SensirionI2CTxFrame` and `SensirionI2CRxFrame`
|
||||
with a buffer sized the amount of data to read times 1.5. This is needed to
|
||||
account for the CRC which is added after every second byte. After that you can
|
||||
build your frame by first calling `addCommand()` to add the command at the
|
||||
beginning of the frame. Information about the different COMMANDs can be found
|
||||
on the data sheet of your sensor. Then you can add data to the frame by using
|
||||
different add member functions. See the code below for examples.
|
||||
|
||||
To send this frame to the sensor you first need to initialize a Wire object.
|
||||
Don't forget to also call the `.begin()` function with the right configuration.
|
||||
Then call the static function `sendFrame()` form `SensirionI2CCommunication` as
|
||||
shown below. You can find the ADDRESS on the data sheet of the sensor. You also
|
||||
need to replace `WIREOBJECT` with the initialized Wire object. Then wait the in
|
||||
the data sheet documented `READ_DELAY` before receiving the reply from the
|
||||
sensor by calling `receiveFrame()` with the same Wire object.
|
||||
|
||||
You then can decode the frame by using the different get members to convert the
|
||||
received data to desired data types.
|
||||
|
||||
All functions return a error code if an error occurs during execution and zero
|
||||
otherwise.
|
||||
|
||||
```cpp
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
txFrame.addCommand(COMMAND);
|
||||
|
||||
txFrame.addUInt8(UINT8);
|
||||
txFrame.addUInt32(UINT32);
|
||||
|
||||
SensirionShdlcCommunication::sendFrame(ADDRESS, txFrame, WIREOBJECT);
|
||||
|
||||
delay(READ_DELAY);
|
||||
|
||||
SensirionShdlcCommunication::receiveFrame(ADDRESS, rxFrame, WIREOBJECT);
|
||||
|
||||
rxFrame.getUInt16(UINT16);
|
||||
rxFrame.getFloat(FLOAT);
|
||||
|
||||
```
|
|
@ -0,0 +1,62 @@
|
|||
#include <SensirionCore.h>
|
||||
#include <Wire.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionI2CTxFrame txFrame(txBuffer, 256);
|
||||
SensirionI2CRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
void setup() {
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint16_t mockCommand = 42;
|
||||
uint16_t error = txFrame.addCommand(mockCommand);
|
||||
|
||||
uint32_t mockUInt32 = 42;
|
||||
error |= txFrame.addUInt32(mockUInt32);
|
||||
|
||||
int32_t mockInt32 = 42;
|
||||
error |= txFrame.addInt32(mockInt32);
|
||||
|
||||
uint16_t mockUInt16 = 42;
|
||||
error |= txFrame.addUInt16(mockUInt16);
|
||||
|
||||
int16_t mockInt16 = 42;
|
||||
error |= txFrame.addInt16(mockInt16);
|
||||
|
||||
uint8_t mockUInt8 = 42;
|
||||
error |= txFrame.addUInt8(mockUInt8);
|
||||
|
||||
int8_t mockInt8 = 42;
|
||||
error |= txFrame.addInt8(mockInt8);
|
||||
|
||||
float mockFloat = 42.0f;
|
||||
error |= txFrame.addFloat(mockFloat);
|
||||
|
||||
bool mockBool = true;
|
||||
error |= txFrame.addBool(mockBool);
|
||||
|
||||
uint8_t mockBytes[] = {42, 42, 42, 42};
|
||||
error |= txFrame.addBytes(mockBytes, 4);
|
||||
|
||||
uint8_t mockAddress = 42;
|
||||
|
||||
error |= SensirionI2CCommunication::sendFrame(mockAddress, txFrame, Wire);
|
||||
|
||||
size_t mockNumBytes = 42;
|
||||
error |= SensirionI2CCommunication::receiveFrame(mockAddress, mockNumBytes,
|
||||
rxFrame, Wire);
|
||||
|
||||
error |= rxFrame.getUInt32(mockUInt32);
|
||||
error |= rxFrame.getInt32(mockInt32);
|
||||
error |= rxFrame.getUInt16(mockUInt16);
|
||||
error |= rxFrame.getInt16(mockInt16);
|
||||
error |= rxFrame.getUInt8(mockUInt8);
|
||||
error |= rxFrame.getInt8(mockInt8);
|
||||
error |= rxFrame.getFloat(mockFloat);
|
||||
error |= rxFrame.getBytes(mockBytes, 4);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include <SensirionCore.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t txBuffer[256];
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
SensirionShdlcTxFrame txFrame(txBuffer, 256);
|
||||
SensirionShdlcRxFrame rxFrame(rxBuffer, 256);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint8_t mockCommand = 42;
|
||||
uint8_t mockAddress = 42;
|
||||
uint8_t mockDataLength = 42;
|
||||
uint16_t error = txFrame.begin(mockCommand, mockAddress, mockDataLength);
|
||||
|
||||
uint32_t mockUInt32 = 42;
|
||||
error |= txFrame.addUInt32(mockUInt32);
|
||||
|
||||
int32_t mockInt32 = 42;
|
||||
error |= txFrame.addInt32(mockInt32);
|
||||
|
||||
uint16_t mockUInt16 = 42;
|
||||
error |= txFrame.addUInt16(mockUInt16);
|
||||
|
||||
int16_t mockInt16 = 42;
|
||||
error |= txFrame.addInt16(mockInt16);
|
||||
|
||||
uint8_t mockUInt8 = 42;
|
||||
error |= txFrame.addUInt8(mockUInt8);
|
||||
|
||||
int8_t mockInt8 = 42;
|
||||
error |= txFrame.addInt8(mockInt8);
|
||||
|
||||
float mockFloat = 42.0f;
|
||||
error |= txFrame.addFloat(mockFloat);
|
||||
|
||||
bool mockBool = true;
|
||||
error |= txFrame.addBool(mockBool);
|
||||
|
||||
uint8_t mockBytes[] = {42, 42, 42, 42};
|
||||
error |= txFrame.addBytes(mockBytes, 4);
|
||||
|
||||
error |= txFrame.finish();
|
||||
|
||||
error |= SensirionShdlcCommunication::sendFrame(txFrame, Serial);
|
||||
|
||||
error |= SensirionShdlcCommunication::sendAndReceiveFrame(
|
||||
Serial, txFrame, rxFrame, 10000000);
|
||||
|
||||
error |=
|
||||
SensirionShdlcCommunication::receiveFrame(rxFrame, Serial, 1000000);
|
||||
|
||||
error |= rxFrame.getUInt32(mockUInt32);
|
||||
error |= rxFrame.getInt32(mockInt32);
|
||||
error |= rxFrame.getUInt16(mockUInt16);
|
||||
error |= rxFrame.getInt16(mockInt16);
|
||||
error |= rxFrame.getUInt8(mockUInt8);
|
||||
error |= rxFrame.getInt8(mockInt8);
|
||||
error |= rxFrame.getFloat(mockFloat);
|
||||
error |= rxFrame.getBytes(mockBytes, 4);
|
||||
|
||||
mockCommand = rxFrame.getCommand();
|
||||
mockAddress = rxFrame.getAddress();
|
||||
mockDataLength = rxFrame.getDataLength();
|
||||
uint8_t mockState = rxFrame.getState();
|
||||
if (mockState) {
|
||||
// There is an error in the device.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
SensirionShdlcCommunication KEYWORD1
|
||||
SensirionShdlcRxFrame KEYWORD1
|
||||
SensirionShdlcTxFrame KEYWORD1
|
||||
SensirionI2CTxFrame KEYWORD1
|
||||
SensirionI2CRxFrame KEYWORD1
|
||||
SensirionI2CCommunication KEYWORD1
|
||||
|
||||
# SensirionErrors.h
|
||||
HighLevelError KEYWORD1
|
||||
LowLevelError KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
sendFrame KEYWORD2
|
||||
receiveFrame KEYWORD2
|
||||
sendAndReceiveFrame KEYWORD2
|
||||
addUInt32 KEYWORD2
|
||||
addInt32 KEYWORD2
|
||||
addUInt16 KEYWORD2
|
||||
addInt16 KEYWORD2
|
||||
addUInt8 KEYWORD2
|
||||
addInt8 KEYWORD2
|
||||
addFloat KEYWORD2
|
||||
addBytes KEYWORD2
|
||||
addBool KEYWORD2
|
||||
addCommand KEYWORD2
|
||||
begin KEYWORD2
|
||||
finish KEYWORD2
|
||||
reset KEYWORD2
|
||||
getUInt32 KEYWORD2
|
||||
getInt32 KEYWORD2
|
||||
getUInt16 KEYWORD2
|
||||
getInt16 KEYWORD2
|
||||
getUInt8 KEYWORD2
|
||||
getInt8 KEYWORD2
|
||||
getFloat KEYWORD2
|
||||
getBytes KEYWORD2
|
||||
getCommand KEYWORD2
|
||||
getAddress KEYWORD2
|
||||
getDataLength KEYWORD2
|
||||
getState KEYWORD2
|
||||
|
||||
# SensirionErrors.h
|
||||
errorToString KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
|
@ -0,0 +1,9 @@
|
|||
name=Sensirion Core
|
||||
version=0.6.0
|
||||
author=Sensirion
|
||||
maintainer=Sensirion
|
||||
sentence=Library containing code base for Sensirion Sensor Libraries.
|
||||
paragraph=All Libraries for Sensirion Sensors use this library as a code base. In this library the Sensirion specific parts for I2C and UART communication are implemented. It provides dynamic frame construction, checksum calculation and buffer handling.
|
||||
category=Communication
|
||||
url=https://github.com/Sensirion/arduino-core/
|
||||
includes=SensirionCore.h
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_CORE_H_
|
||||
#define _SENSIRION_CORE_H_
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#endif /* _SENSIRION_CORE_H_ */
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*
|
||||
* THIS IS A LEGACY FILE AND WILL BE REMOVED SOON.
|
||||
*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_CORE_ARDUINO_LIBRARY_H_
|
||||
#define _SENSIRION_CORE_ARDUINO_LIBRARY_H_
|
||||
|
||||
#pragma GCC warning \
|
||||
"Legacy file SensirionCoreArdunioLibrary.h included. Please include SensirionCore.h instead."
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#endif /* _SENSIRION_CORE_ARDUION_LIBRARY_H_ */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
|
||||
uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init,
|
||||
uint8_t polynomial) {
|
||||
uint8_t crc = init;
|
||||
|
||||
/* calculates 8-Bit checksum with given polynomial */
|
||||
for (size_t current_byte = 0; current_byte < count; ++current_byte) {
|
||||
crc ^= (data[current_byte]);
|
||||
for (uint8_t crc_bit = 8; crc_bit > 0; --crc_bit) {
|
||||
if (crc & 0x80)
|
||||
crc = (crc << 1) ^ polynomial;
|
||||
else
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint8_t generateCRC31_ff(const uint8_t* data, size_t count) {
|
||||
return generateCRCGeneric(data, count, 0xff, 0x31);
|
||||
}
|
||||
|
||||
uint8_t generateCRC31_00(const uint8_t* data, size_t count) {
|
||||
return generateCRCGeneric(data, count, 0x00, 0x31);
|
||||
}
|
||||
|
||||
uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type) {
|
||||
if (CRC31_00 == type) {
|
||||
return generateCRC31_00(data, count);
|
||||
}
|
||||
return generateCRC31_ff(data, count);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SENSIRION_CRC_H_
|
||||
#define _SENSIRION_CRC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum CrcPolynomial : uint8_t {
|
||||
CRC31_00 = 0x0,
|
||||
CRC31_ff = 0x1,
|
||||
};
|
||||
|
||||
uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init,
|
||||
uint8_t polynomial);
|
||||
|
||||
uint8_t generateCRC31_ff(const uint8_t* data, size_t count);
|
||||
|
||||
uint8_t generateCRC31_00(const uint8_t* data, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Generate a crc for data given a polynomial type
|
||||
*
|
||||
* @param data data to calculate CRC for
|
||||
* @param count the array size of data
|
||||
* @param poly CRC polynomal to use
|
||||
*/
|
||||
uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type);
|
||||
|
||||
#endif /* _SENSIRION_CRC_H_ */
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void errorToString(uint16_t error, char errorMessage[],
|
||||
size_t errorMessageSize) {
|
||||
|
||||
uint16_t highLevelError = error & 0xFF00;
|
||||
uint16_t lowLevelError = error & 0x00FF;
|
||||
|
||||
if (error & HighLevelError::SensorSpecificError) {
|
||||
snprintf(errorMessage, errorMessageSize, "Sensor specific error: 0x%2x",
|
||||
lowLevelError);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (highLevelError) {
|
||||
case HighLevelError::NoError:
|
||||
if (!error) {
|
||||
strncpy(errorMessage, "No error", errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::WriteError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::SerialWriteError:
|
||||
strncpy(errorMessage, "Error writing to serial",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::InternalBufferSizeError:
|
||||
strncpy(errorMessage,
|
||||
"Data too long to fit in transmit buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cAddressNack:
|
||||
strncpy(errorMessage,
|
||||
"Received NACK on transmit of address",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cDataNack:
|
||||
strncpy(errorMessage, "Received NACK on transmit of data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::I2cOtherError:
|
||||
strncpy(errorMessage, "Error writing to I2C bus",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::ReadError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::NonemptyFrameError:
|
||||
strncpy(errorMessage, "Frame already contains data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::TimeoutError:
|
||||
strncpy(errorMessage, "Timeout while reading data",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::ChecksumError:
|
||||
strncpy(errorMessage, "Checksum is wrong",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::CRCError:
|
||||
strncpy(errorMessage, "Wrong CRC found", errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::WrongNumberBytesError:
|
||||
strncpy(errorMessage, "Number of bytes not a multiple of 3",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::NotEnoughDataError:
|
||||
strncpy(errorMessage, "Not enough data received",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::InternalBufferSizeError:
|
||||
strncpy(errorMessage, "Internal I2C buffer too small",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::ExecutionError: {
|
||||
char format[] = "Execution error, status register: 0x%x";
|
||||
snprintf(errorMessage, errorMessageSize, format, lowLevelError);
|
||||
return;
|
||||
}
|
||||
case HighLevelError::TxFrameError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::BufferSizeError:
|
||||
strncpy(errorMessage, "Not enough space in buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case HighLevelError::RxFrameError:
|
||||
switch (lowLevelError) {
|
||||
case LowLevelError::BufferSizeError:
|
||||
strncpy(errorMessage, "Not enough space in buffer",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::NoDataError:
|
||||
strncpy(errorMessage, "No more data in frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::RxAddressError:
|
||||
strncpy(errorMessage, "Wrong address in return frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
case LowLevelError::RxCommandError:
|
||||
strncpy(errorMessage, "Wrong command in return frame",
|
||||
errorMessageSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
strncpy(errorMessage, "Error processing error", errorMessageSize);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _SENSIRION_ERRORS_H_
|
||||
#define _SENSIRION_ERRORS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum HighLevelError : uint16_t {
|
||||
// general errors
|
||||
NoError = 0,
|
||||
WriteError = 0x0100,
|
||||
ReadError = 0x0200,
|
||||
TxFrameError = 0x0300,
|
||||
RxFrameError = 0x0400,
|
||||
// shdlc errors
|
||||
ExecutionError = 0x0500,
|
||||
// i2c errors
|
||||
|
||||
// Sensor specific errors. All errors higher than that are depending on the
|
||||
// sensor used.
|
||||
SensorSpecificError = 0x8000,
|
||||
};
|
||||
|
||||
enum LowLevelError : uint16_t {
|
||||
// general errors
|
||||
NonemptyFrameError,
|
||||
NoDataError,
|
||||
BufferSizeError,
|
||||
// shdlc errors
|
||||
StopByteError,
|
||||
ChecksumError,
|
||||
TimeoutError,
|
||||
RxCommandError,
|
||||
RxAddressError,
|
||||
SerialWriteError,
|
||||
// i2c errors
|
||||
WrongNumberBytesError,
|
||||
CRCError,
|
||||
I2cAddressNack,
|
||||
I2cDataNack,
|
||||
I2cOtherError,
|
||||
NotEnoughDataError,
|
||||
InternalBufferSizeError,
|
||||
};
|
||||
|
||||
/**
|
||||
* errorToString() - Convert error code to a human readable error message
|
||||
*
|
||||
* @param error Error code to be converted.
|
||||
* @param errorMessage String where the error text can be
|
||||
* stored.
|
||||
* @param errorMessageSize Size in bytes of the string buffer for the error
|
||||
* message.
|
||||
*/
|
||||
void errorToString(uint16_t error, char errorMessage[],
|
||||
size_t errorMessageSize);
|
||||
|
||||
#endif /* _SENSIRION_ERRORS_H_ */
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionI2CCommunication.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
static void clearRxBuffer(TwoWire& i2cBus) {
|
||||
while (i2cBus.available()) {
|
||||
(void)i2cBus.read();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CCommunication::sendFrame(uint8_t address,
|
||||
SensirionI2CTxFrame& frame,
|
||||
TwoWire& i2cBus) {
|
||||
i2cBus.beginTransmission(address);
|
||||
size_t writtenBytes = i2cBus.write(frame._buffer, frame._index);
|
||||
uint8_t i2c_error = i2cBus.endTransmission();
|
||||
if (writtenBytes != frame._index) {
|
||||
return WriteError | I2cOtherError;
|
||||
}
|
||||
// translate Arduino errors, see
|
||||
// https://www.arduino.cc/en/Reference/WireEndTransmission
|
||||
switch (i2c_error) {
|
||||
case 0:
|
||||
return NoError;
|
||||
case 1:
|
||||
return WriteError | InternalBufferSizeError;
|
||||
case 2:
|
||||
return WriteError | I2cAddressNack;
|
||||
case 3:
|
||||
return WriteError | I2cDataNack;
|
||||
default:
|
||||
return WriteError | I2cOtherError;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address,
|
||||
size_t numBytes,
|
||||
SensirionI2CRxFrame& frame,
|
||||
TwoWire& i2cBus,
|
||||
CrcPolynomial poly) {
|
||||
size_t readAmount;
|
||||
size_t i = 0;
|
||||
|
||||
#ifdef I2C_BUFFER_LENGTH
|
||||
const uint8_t sizeBuffer =
|
||||
(static_cast<uint8_t>(I2C_BUFFER_LENGTH) / static_cast<uint8_t>(3)) * 3;
|
||||
#elif defined(BUFFER_LENGTH)
|
||||
const uint8_t sizeBuffer =
|
||||
(static_cast<uint8_t>(BUFFER_LENGTH) / static_cast<uint8_t>(3)) * 3;
|
||||
#else
|
||||
const uint8_t sizeBuffer = 30;
|
||||
#endif
|
||||
|
||||
if (numBytes % 3) {
|
||||
return ReadError | WrongNumberBytesError;
|
||||
}
|
||||
if ((numBytes / 3) * 2 > frame._bufferSize) {
|
||||
return ReadError | BufferSizeError;
|
||||
}
|
||||
if (numBytes > sizeBuffer) {
|
||||
return ReadError | InternalBufferSizeError;
|
||||
}
|
||||
|
||||
readAmount = i2cBus.requestFrom(address, static_cast<uint8_t>(numBytes),
|
||||
static_cast<uint8_t>(true));
|
||||
if (numBytes != readAmount) {
|
||||
return ReadError | NotEnoughDataError;
|
||||
}
|
||||
do {
|
||||
frame._buffer[i++] = i2cBus.read();
|
||||
frame._buffer[i++] = i2cBus.read();
|
||||
uint8_t actualCRC = i2cBus.read();
|
||||
uint8_t expectedCRC = generateCRC(&frame._buffer[i - 2], 2, poly);
|
||||
if (actualCRC != expectedCRC) {
|
||||
clearRxBuffer(i2cBus);
|
||||
return ReadError | CRCError;
|
||||
}
|
||||
readAmount -= 3;
|
||||
} while (readAmount > 0);
|
||||
frame._numBytes = i;
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_COMMUNICATION_H_
|
||||
#define SENSIRION_I2C_COMMUNICATION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#include "SensirionI2CRxFrame.h"
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
class SensirionI2CTxFrame;
|
||||
class SensirionI2CRxFrame;
|
||||
|
||||
/*
|
||||
* SensirionI2CCommunication - Class which is responsible for the communication
|
||||
* via a I2C bus. It provides functionality to send and receive frames from a
|
||||
* Sensirion sensor. The data is sent and received in a SensirionI2cTxFrame or
|
||||
* SensirionI2cRxFrame respectively.
|
||||
*/
|
||||
class SensirionI2CCommunication {
|
||||
public:
|
||||
/**
|
||||
* sendFrame() - Sends frame to sensor
|
||||
*
|
||||
* @param address I2C address of the sensor.
|
||||
* @param frame Tx frame object containing a finished frame to send to
|
||||
* the sensor.
|
||||
* @param i2cBus TwoWire object to communicate with the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendFrame(uint8_t address, SensirionI2CTxFrame& frame,
|
||||
TwoWire& i2cBus);
|
||||
|
||||
/**
|
||||
* receiveFrame() - Receive Frame from sensor
|
||||
*
|
||||
* @param address I2C address of the sensor.
|
||||
* @param numBytes Number of bytes to receive.
|
||||
* @param frame Rx frame to store the received data in.
|
||||
* @param i2cBus TwoWire object to communicate with the sensor.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t receiveFrame(uint8_t address, size_t numBytes,
|
||||
SensirionI2CRxFrame& frame, TwoWire& i2cBus,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_COMMUNICATION_H_ */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_RX_FRAME_H_
|
||||
#define SENSIRION_I2C_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionI2CCommunication.h"
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
/**
|
||||
* SenirionI2CRxFrame - Class which decodes the through I2C received data into
|
||||
* common data types. It contains a buffer which is filled by the
|
||||
* SensirionI2CCommunication class. By calling the different decode function
|
||||
* inherited from the SensirionRxFrame base class the raw data can be decoded
|
||||
* into different data types.
|
||||
*/
|
||||
class SensirionI2CRxFrame : public SensirionRxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be
|
||||
* stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*
|
||||
*/
|
||||
SensirionI2CRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: SensirionRxFrame(buffer, bufferSize){};
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_RX_FRAME_H_ */
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionI2CTxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
size_t numCommandBytes,
|
||||
CrcPolynomial poly)
|
||||
: _buffer(buffer), _bufferSize(bufferSize), _index(numCommandBytes),
|
||||
_numCommandBytes(numCommandBytes), _polynomial_type(poly) {
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly)
|
||||
: SensirionI2CTxFrame(buffer, bufferSize, 2, poly) {
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt8Command(
|
||||
uint8_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) {
|
||||
SensirionI2CTxFrame instance =
|
||||
SensirionI2CTxFrame(buffer, bufferSize, 1, poly);
|
||||
instance._buffer[0] = command;
|
||||
return instance;
|
||||
}
|
||||
|
||||
SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt16Command(
|
||||
uint16_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) {
|
||||
SensirionI2CTxFrame instance =
|
||||
SensirionI2CTxFrame(buffer, bufferSize, 2, poly);
|
||||
instance._buffer[0] = static_cast<uint8_t>((command & 0xFF00) >> 8);
|
||||
instance._buffer[1] = static_cast<uint8_t>((command & 0x00FF) >> 0);
|
||||
return instance;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addCommand(uint16_t command) {
|
||||
if (_bufferSize < 2) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[0] = static_cast<uint8_t>((command & 0xFF00) >> 8);
|
||||
_buffer[1] = static_cast<uint8_t>((command & 0x00FF) >> 0);
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt32(uint32_t data) {
|
||||
uint16_t error = _addByte(static_cast<uint8_t>((data & 0xFF000000) >> 24));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x00FF0000) >> 16));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x0000FF00) >> 8));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x000000FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt32(int32_t data) {
|
||||
return addUInt32(static_cast<uint32_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt16(uint16_t data) {
|
||||
uint16_t error = _addByte(static_cast<uint8_t>((data & 0xFF00) >> 8));
|
||||
error |= _addByte(static_cast<uint8_t>((data & 0x00FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt16(int16_t data) {
|
||||
return addUInt16(static_cast<uint16_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addUInt8(uint8_t data) {
|
||||
return _addByte(data);
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addInt8(int8_t data) {
|
||||
return _addByte(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addBool(bool data) {
|
||||
return _addByte(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addFloat(float data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
|
||||
convert.floatData = data;
|
||||
return addUInt32(convert.uInt32Data);
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::addBytes(const uint8_t data[],
|
||||
size_t dataLength) {
|
||||
uint16_t error = 0;
|
||||
for (size_t i = 0; i < dataLength; i++) {
|
||||
error |= _addByte(data[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CTxFrame::_addByte(uint8_t data) {
|
||||
if (_bufferSize <= _index) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[_index++] = data;
|
||||
if ((_index - _numCommandBytes) % 3 == 2) {
|
||||
if (_bufferSize <= _index) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
uint8_t crc = generateCRC(&_buffer[_index - 2], 2, _polynomial_type);
|
||||
_buffer[_index++] = crc;
|
||||
}
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_I2C_TX_FRAME_H_
|
||||
#define SENSIRION_I2C_TX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionCrc.h"
|
||||
#include "SensirionI2CCommunication.h"
|
||||
|
||||
/*
|
||||
* SensirionI2CTxFrame - Class which helps to build a correct I2C frame for
|
||||
* Sensirion Sensors. The different addDatatype() functions add the frame data
|
||||
* and the addCommand() function writes the command at the beginning. Using
|
||||
* these functions one can easily construct a I2C frame for Sensirion sensors.
|
||||
*/
|
||||
class SensirionI2CTxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Factory to create a SensirionI2CTxFrame using a UInt8 command.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return the constructed SensirionI2CTxFrame.
|
||||
*/
|
||||
static SensirionI2CTxFrame
|
||||
createWithUInt8Command(uint8_t command, uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* Factory to create a SensirionI2CTxFrame using a UInt16 command.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @return the constructed SensirionI2CTxFrame.
|
||||
*/
|
||||
static SensirionI2CTxFrame
|
||||
createWithUInt16Command(uint16_t command, uint8_t buffer[],
|
||||
size_t bufferSize, CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
* @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF
|
||||
*
|
||||
* @deprecated Use createWithUInt16Command() instead
|
||||
*/
|
||||
SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
/**
|
||||
* addCommand() - Add command to the send frame.
|
||||
*
|
||||
* @param command Command to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*
|
||||
* @deprecated Use createWithUInt16Command() instead
|
||||
*/
|
||||
uint16_t addCommand(uint16_t command);
|
||||
|
||||
/**
|
||||
* addUInt32() - Add unsigned 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt32(uint32_t data);
|
||||
|
||||
/**
|
||||
* addInt32() - Add signed 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt32(int32_t data);
|
||||
|
||||
/**
|
||||
* addUInt16() - Add unsigned 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt16(uint16_t data);
|
||||
|
||||
/**
|
||||
* addInt16() - Add signed 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt16(int16_t data);
|
||||
|
||||
/**
|
||||
* addUInt8() - Add unsigned 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt8(uint8_t data);
|
||||
|
||||
/**
|
||||
* addInt8() - Add signed 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt8(int8_t data);
|
||||
|
||||
/**
|
||||
* addBool() - Add boolean to the send frame.
|
||||
*
|
||||
* @param data Boolean to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBool(bool data);
|
||||
|
||||
/**
|
||||
* addFloat() - Add float to the send frame.
|
||||
*
|
||||
* @param data Float to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addFloat(float data);
|
||||
|
||||
/**
|
||||
* addBytes() - Add byte array to the send frame.
|
||||
*
|
||||
* @param data Byte array to add to the send frame.
|
||||
* @param dataLength Number of bytes to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBytes(const uint8_t data[], size_t dataLength);
|
||||
|
||||
private:
|
||||
SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize,
|
||||
size_t numCommandBytes, CrcPolynomial poly = CRC31_ff);
|
||||
|
||||
uint16_t _addByte(uint8_t data);
|
||||
|
||||
uint8_t* _buffer;
|
||||
size_t _bufferSize;
|
||||
size_t _index;
|
||||
size_t _numCommandBytes;
|
||||
CrcPolynomial _polynomial_type;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_I2C_TX_FRAME_H_ */
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionRxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
SensirionRxFrame::SensirionRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: _buffer(buffer), _bufferSize(bufferSize), _index(0), _numBytes(0) {
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt32(uint32_t& data) {
|
||||
if (_numBytes < 4) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<uint32_t>(_buffer[_index++]) << 24;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]) << 16;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]) << 8;
|
||||
data |= static_cast<uint32_t>(_buffer[_index++]);
|
||||
_numBytes -= 4;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt32(int32_t& data) {
|
||||
uint32_t ret;
|
||||
uint16_t error = getUInt32(ret);
|
||||
data = static_cast<int32_t>(ret);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt16(uint16_t& data) {
|
||||
if (_numBytes < 2) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<uint16_t>(_buffer[_index++]) << 8;
|
||||
data |= static_cast<uint16_t>(_buffer[_index++]);
|
||||
_numBytes -= 2;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt16(int16_t& data) {
|
||||
uint16_t ret;
|
||||
uint16_t error = getUInt16(ret);
|
||||
data = static_cast<int16_t>(ret);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getUInt8(uint8_t& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = _buffer[_index++];
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getInt8(int8_t& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<int8_t>(_buffer[_index++]);
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getBool(bool& data) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
data = static_cast<bool>(_buffer[_index++]);
|
||||
_numBytes -= 1;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getFloat(float& data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
uint16_t error = getUInt32(convert.uInt32Data);
|
||||
data = convert.floatData;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionRxFrame::getBytes(uint8_t data[], size_t maxBytes) {
|
||||
if (_numBytes < 1) {
|
||||
return RxFrameError | NoDataError;
|
||||
}
|
||||
size_t readAmount = maxBytes;
|
||||
if (_numBytes < maxBytes) {
|
||||
readAmount = _numBytes;
|
||||
}
|
||||
for (size_t i = 0; i < readAmount; i++) {
|
||||
data[i] = _buffer[_index++];
|
||||
}
|
||||
_numBytes -= readAmount;
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_RX_FRAME_H_
|
||||
#define SENSIRION_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* SenirionRxFrame - Base class for SensirionShdlcRxFrame and
|
||||
* SensirionI2cRxFrame. It decodes received data into common data types. The
|
||||
* data is contained in a buffer which is filled by the one of the two
|
||||
* communication classes. By calling the different decode function the raw data
|
||||
* can be decoded into different data types.
|
||||
*/
|
||||
class SensirionRxFrame {
|
||||
|
||||
friend class SensirionI2CCommunication;
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*/
|
||||
SensirionRxFrame(uint8_t buffer[], size_t bufferSize);
|
||||
|
||||
/**
|
||||
* getUInt32() - Get unsigned 32bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 32bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt32(uint32_t& data);
|
||||
|
||||
/**
|
||||
* getInt32() - Get signed 32bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 32bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt32(int32_t& data);
|
||||
|
||||
/**
|
||||
* getUInt16() - Get unsigned 16bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 16bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt16(uint16_t& data);
|
||||
|
||||
/**
|
||||
* getInt16() - Get signed 16bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 16bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt16(int16_t& data);
|
||||
|
||||
/**
|
||||
* getUInt8() - Get unsigned 8bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store unsigned 8bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getUInt8(uint8_t& data);
|
||||
|
||||
/**
|
||||
* getInt8() - Get signed 8bit integer from the received data.
|
||||
*
|
||||
* @param data Memory to store signed 8bit integer in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getInt8(int8_t& data);
|
||||
|
||||
/**
|
||||
* getBool() - Get Boolean from the received data.
|
||||
*
|
||||
* @param data Memory to store boolean in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getBool(bool& data);
|
||||
|
||||
/**
|
||||
* getFloat() - Get float from the received data.
|
||||
*
|
||||
* @param data Memory to store float in.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getFloat(float& data);
|
||||
|
||||
/**
|
||||
* getBytes() - Get an array of bytes from the received data.
|
||||
*
|
||||
* @param data Buffer to store the bytes in.
|
||||
* @param maxBytes Maximal amount of bytes to read from the received data.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getBytes(uint8_t data[], size_t maxBytes);
|
||||
|
||||
private:
|
||||
uint8_t* _buffer = 0;
|
||||
size_t _bufferSize = 0;
|
||||
size_t _index = 0;
|
||||
size_t _numBytes = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_RX_FRAME_H_ */
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensirionErrors.h"
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
static uint16_t readByte(uint8_t& data, Stream& serial, unsigned long startTime,
|
||||
unsigned long timeoutMicros) {
|
||||
do {
|
||||
if (micros() - startTime > timeoutMicros) {
|
||||
return ReadError | TimeoutError;
|
||||
}
|
||||
} while (!serial.available());
|
||||
data = serial.read();
|
||||
return NoError;
|
||||
}
|
||||
|
||||
static uint16_t unstuffByte(uint8_t& data, Stream& serial,
|
||||
unsigned long startTime,
|
||||
unsigned long timeoutMicros) {
|
||||
uint16_t error = readByte(data, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (data == 0x7d) {
|
||||
error = readByte(data, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
data = data ^ (1 << 5);
|
||||
}
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::sendFrame(SensirionShdlcTxFrame& frame,
|
||||
Stream& serial) {
|
||||
size_t writtenBytes = serial.write(&frame._buffer[0], frame._index);
|
||||
if (writtenBytes != frame._index) {
|
||||
return WriteError | SerialWriteError;
|
||||
}
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::receiveFrame(
|
||||
SensirionShdlcRxFrame& frame, Stream& serial, unsigned long timeoutMicros) {
|
||||
unsigned long startTime = micros();
|
||||
uint16_t error;
|
||||
uint8_t dataLength;
|
||||
uint8_t current = 0;
|
||||
|
||||
if (frame._numBytes) {
|
||||
return ReadError | NonemptyFrameError;
|
||||
}
|
||||
|
||||
// Wait for start byte and ignore all other bytes in case a partial frame
|
||||
// is still in the receive buffer due to a previous error.
|
||||
do {
|
||||
error = readByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} while (current != 0x7e);
|
||||
|
||||
// Handle a repeated start byte which may happen
|
||||
do {
|
||||
error = unstuffByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} while (current == 0x7e);
|
||||
|
||||
frame._address = current;
|
||||
error = unstuffByte(frame._command, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = unstuffByte(frame._state, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = unstuffByte(dataLength, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t checksum =
|
||||
frame._address + frame._command + frame._state + dataLength;
|
||||
|
||||
if (dataLength > frame._bufferSize) {
|
||||
return RxFrameError | BufferSizeError;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (i < dataLength) {
|
||||
error = unstuffByte(current, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
frame._buffer[i] = current;
|
||||
checksum += current;
|
||||
i++;
|
||||
}
|
||||
|
||||
uint8_t expectedChecksum = ~checksum;
|
||||
uint8_t actualChecksum;
|
||||
error = unstuffByte(actualChecksum, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (expectedChecksum != actualChecksum) {
|
||||
return ReadError | ChecksumError;
|
||||
}
|
||||
|
||||
uint8_t stop;
|
||||
error = readByte(stop, serial, startTime, timeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (stop != 0x7e) {
|
||||
return ReadError | StopByteError;
|
||||
}
|
||||
if (frame._state & 0x7F) {
|
||||
return ExecutionError | frame._state;
|
||||
}
|
||||
frame._dataLength = dataLength;
|
||||
frame._numBytes = dataLength;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcCommunication::sendAndReceiveFrame(
|
||||
Stream& serial, SensirionShdlcTxFrame& txFrame,
|
||||
SensirionShdlcRxFrame& rxFrame, unsigned long rxTimeoutMicros) {
|
||||
uint16_t error;
|
||||
error = SensirionShdlcCommunication::sendFrame(txFrame, serial);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
error = SensirionShdlcCommunication::receiveFrame(rxFrame, serial,
|
||||
rxTimeoutMicros);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (rxFrame.getCommand() != txFrame.getCommand()) {
|
||||
return RxFrameError | RxCommandError;
|
||||
}
|
||||
if (rxFrame.getAddress() != txFrame.getAddress()) {
|
||||
return RxFrameError | RxAddressError;
|
||||
}
|
||||
return NoError;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_COMMUNICATION_H_
|
||||
#define SENSIRION_SHDLC_COMMUNICATION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "SensirionShdlcRxFrame.h"
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
class SensirionShdlcTxFrame;
|
||||
class SensirionShdlcRxFrame;
|
||||
|
||||
/*
|
||||
* SensirionShdlcCommunication - Class which is responsible for the
|
||||
* communication via a UART (Serial) interface. It provides functionality to
|
||||
* send and receive frames from a Sensirion sensor. The data is sent and
|
||||
* received in a SensirionShdlcTxFrame or SensirionShdlcRxFrame respectively.
|
||||
*/
|
||||
class SensirionShdlcCommunication {
|
||||
|
||||
public:
|
||||
/**
|
||||
* sendFrame() - Sends frame to sensor
|
||||
*
|
||||
* @param frame Tx frame object containing a finished frame to send to the
|
||||
* sensor.
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendFrame(SensirionShdlcTxFrame& frame, Stream& serial);
|
||||
|
||||
/**
|
||||
* receiveFrame() - Receive Frame from sensor
|
||||
*
|
||||
* @param frame Rx frame to store the received data in.
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
* @param timeoutMicros Timeout in micro seconds for the receive operation.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t receiveFrame(SensirionShdlcRxFrame& frame, Stream& serial,
|
||||
unsigned long timeoutMicros);
|
||||
|
||||
/**
|
||||
* sendAndReceiveFrame() - Send and receive a frame from sensor.
|
||||
*
|
||||
* @param serial Stream object to communicate with the sensor.
|
||||
* @param txFrame Tx frame object containing a finished frame to
|
||||
* send to the sensor.
|
||||
* @param rxFrame Rx frame to store the received data in.
|
||||
* @param rxTimeoutMicros Timeout in micro seconds for the receive
|
||||
* operation.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
static uint16_t sendAndReceiveFrame(Stream& serial,
|
||||
SensirionShdlcTxFrame& txFrame,
|
||||
SensirionShdlcRxFrame& rxFrame,
|
||||
unsigned long rxTimeoutMicros);
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_COMMUNICATION_H_ */
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_RX_FRAME_H_
|
||||
#define SENSIRION_SHDLC_RX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionRxFrame.h"
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
/**
|
||||
* SenirionShdlcRxFrame - Class which decodes the through UART received data
|
||||
* into common data types. It contains a buffer which is filled by the
|
||||
* SensirionShdlcCommunication class. By calling the different decode function
|
||||
* inherited from the SensirionRxFrame base class the raw data can be decoded
|
||||
* into different data types. In addition to that it also stores the four
|
||||
* header bytes defined by the SHDLC protocol state, command, address,
|
||||
* datalength. These bytes can be read out by the corresponding getter method.
|
||||
*/
|
||||
class SensirionShdlcRxFrame : public SensirionRxFrame {
|
||||
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the receive frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the receive frame.
|
||||
*/
|
||||
SensirionShdlcRxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: SensirionRxFrame(buffer, bufferSize){};
|
||||
|
||||
uint8_t getAddress(void) const {
|
||||
return _address;
|
||||
};
|
||||
|
||||
uint8_t getCommand(void) const {
|
||||
return _command;
|
||||
};
|
||||
|
||||
uint8_t getState(void) const {
|
||||
return _state;
|
||||
};
|
||||
|
||||
uint8_t getDataLength(void) const {
|
||||
return _dataLength;
|
||||
};
|
||||
|
||||
private:
|
||||
uint8_t _address = 0;
|
||||
uint8_t _command = 0;
|
||||
uint8_t _state = 0;
|
||||
uint8_t _dataLength = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_RX_FRAME_H_ */
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionShdlcTxFrame.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionErrors.h"
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::begin(uint8_t command, uint8_t address,
|
||||
uint8_t dataLength) {
|
||||
_buffer[_index++] = 0x7e;
|
||||
uint16_t error = addUInt8(address);
|
||||
error |= addUInt8(command);
|
||||
error |= addUInt8(dataLength);
|
||||
_command = command;
|
||||
_address = address;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::finish(void) {
|
||||
uint16_t error = addUInt8(~_checksum);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (_index + 1 > _bufferSize) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
_buffer[_index++] = 0x7e;
|
||||
_isFinished = true;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt32(uint32_t data) {
|
||||
uint16_t error = addUInt8(static_cast<uint8_t>((data & 0xFF000000) >> 24));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x00FF0000) >> 16));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x0000FF00) >> 8));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x000000FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt32(int32_t data) {
|
||||
return addUInt32(static_cast<uint32_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt16(uint16_t data) {
|
||||
uint16_t error = addUInt8(static_cast<uint8_t>((data & 0xFF00) >> 8));
|
||||
error |= addUInt8(static_cast<uint8_t>((data & 0x00FF) >> 0));
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt16(int16_t data) {
|
||||
return addUInt16(static_cast<uint16_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addUInt8(uint8_t data) {
|
||||
if (_index + 2 > _bufferSize) {
|
||||
return TxFrameError | BufferSizeError;
|
||||
}
|
||||
switch (data) {
|
||||
case 0x11:
|
||||
case 0x13:
|
||||
case 0x7d:
|
||||
case 0x7e:
|
||||
// byte stuffing is done by inserting 0x7d and inverting bit 5
|
||||
_buffer[_index++] = 0x7d;
|
||||
_buffer[_index++] = data ^ (1 << 5);
|
||||
break;
|
||||
default:
|
||||
_buffer[_index++] = data;
|
||||
}
|
||||
_checksum += data;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addInt8(int8_t data) {
|
||||
return addUInt8(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addBool(bool data) {
|
||||
return addUInt8(static_cast<uint8_t>(data));
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addFloat(float data) {
|
||||
union {
|
||||
uint32_t uInt32Data;
|
||||
float floatData;
|
||||
} convert;
|
||||
|
||||
convert.floatData = data;
|
||||
return addUInt32(convert.uInt32Data);
|
||||
}
|
||||
|
||||
uint16_t SensirionShdlcTxFrame::addBytes(const uint8_t data[],
|
||||
size_t dataLength) {
|
||||
uint16_t error = 0;
|
||||
for (size_t i = 0; i < dataLength; i++) {
|
||||
error |= addUInt8(data[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SENSIRION_SHDLC_TX_FRAME_H_
|
||||
#define SENSIRION_SHDLC_TX_FRAME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SensirionShdlcCommunication.h"
|
||||
|
||||
/*
|
||||
* SensirionShdlcTxFrame - Class which helps to build a correct SHDLC frame.
|
||||
* The begin() functions writes the header. The different addDatatype()
|
||||
* functions add the frame data and the finish() function writes the tail.
|
||||
* Using these functions one can easily construct a SHDLC frame.
|
||||
*/
|
||||
class SensirionShdlcTxFrame {
|
||||
|
||||
friend class SensirionShdlcCommunication;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer Buffer in which the send frame will be stored.
|
||||
* @param bufferSize Number of bytes in the buffer for the send frame.
|
||||
*/
|
||||
SensirionShdlcTxFrame(uint8_t buffer[], size_t bufferSize)
|
||||
: _buffer(buffer), _bufferSize(bufferSize) {
|
||||
}
|
||||
|
||||
/**
|
||||
* begin() - Begin frame and write header.
|
||||
*
|
||||
* @note This function needs to be called before calling other
|
||||
* data add functions to write the header at the beginning.
|
||||
*
|
||||
* @param command Command byte to add to the send frame.
|
||||
* @param address Address byte to add to the send frame.
|
||||
* @param dataLength Data length byte to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t begin(uint8_t command, uint8_t address, uint8_t dataLength);
|
||||
|
||||
/**
|
||||
* finish() - Finish frame and write tail.
|
||||
*
|
||||
* @note This function needs to be called last, after adding all
|
||||
* data to frame and before sending the frame to the sensor.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t finish(void);
|
||||
|
||||
/**
|
||||
* addUInt32() - Add unsigned 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt32(uint32_t data);
|
||||
|
||||
/**
|
||||
* addInt32() - Add signed 32bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 32bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt32(int32_t data);
|
||||
|
||||
/**
|
||||
* addUInt16() - Add unsigned 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt16(uint16_t data);
|
||||
|
||||
/**
|
||||
* addInt16() - Add signed 16bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 16bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt16(int16_t data);
|
||||
|
||||
/**
|
||||
* addUInt8() - Add unsigned 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Unsigned 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addUInt8(uint8_t data);
|
||||
|
||||
/**
|
||||
* addInt8() - Add signed 8bit integer to the send frame.
|
||||
*
|
||||
* @param data Signed 8bit integer to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addInt8(int8_t data);
|
||||
|
||||
/**
|
||||
* addBool() - Add boolean to the send frame.
|
||||
*
|
||||
* @param data Boolean to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBool(bool data);
|
||||
|
||||
/**
|
||||
* addFloat() - Add float to the send frame.
|
||||
*
|
||||
* @param data Float to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addFloat(float data);
|
||||
|
||||
/**
|
||||
* addBytes() - Add byte array to the send frame.
|
||||
*
|
||||
* @param data Byte array to add to the send frame.
|
||||
* @param dataLength Number of bytes to add to the send frame.
|
||||
*
|
||||
* @return NoError on success, an error code otherwise
|
||||
*/
|
||||
uint16_t addBytes(const uint8_t data[], size_t dataLength);
|
||||
|
||||
uint8_t getCommand(void) const {
|
||||
return _command;
|
||||
};
|
||||
|
||||
uint8_t getAddress(void) const {
|
||||
return _address;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* _buffer;
|
||||
size_t _bufferSize;
|
||||
size_t _index = 0;
|
||||
uint8_t _checksum = 0;
|
||||
bool _isFinished = false;
|
||||
uint8_t _command = 0;
|
||||
uint8_t _address = 0;
|
||||
};
|
||||
|
||||
#endif /* SENSIRION_SHDLC_TX_FRAME_H_ */
|
|
@ -0,0 +1,45 @@
|
|||
#! /usr/bin/env python3
|
||||
import subprocess
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import logging
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.description = u'Compile test a sketch for all available boards'
|
||||
parser.add_argument(u'-s', u'--sketch', dest=u'sketch',
|
||||
required=True, help=u'Path to sketch')
|
||||
args = parser.parse_args()
|
||||
test_all_boards(args.sketch)
|
||||
|
||||
|
||||
def test_all_boards(sketch):
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s')
|
||||
log = logging.getLogger('arduino-compile-test')
|
||||
process = subprocess.run("arduino-cli board listall --format json".split(),
|
||||
stdout=subprocess.PIPE)
|
||||
board_list_json = process.stdout.decode('utf-8')
|
||||
board_list = json.loads(board_list_json)
|
||||
test_list = ["arduino:samd:mkrzero", "arduino:avr:mega",
|
||||
"arduino:avr:nano", "arduino:avr:uno",
|
||||
"esp32:esp32:esp32", "esp8266:esp8266:generic"]
|
||||
for board in test_list:
|
||||
if board in (b['fqbn'] for b in board_list['boards']):
|
||||
log.info('Test compilation for board {}'.format(board))
|
||||
command = 'arduino-cli compile --libraries="." --warnings all'\
|
||||
' --fqbn {board} {sketch}'.format(board=board,
|
||||
sketch=sketch)
|
||||
process = subprocess.run(command.split(), stdout=subprocess.PIPE)
|
||||
if process.returncode:
|
||||
log.error(process.stdout.decode('utf-8'))
|
||||
sys.exit(process.returncode)
|
||||
else:
|
||||
log.error('Board not installed: {}'.format(board))
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
cppcheck --std=c++11 --language=c++ --error-exitcode=1 --enable=warning,style,performance,portability src/*
|
|
@ -0,0 +1,5 @@
|
|||
#! /bin/bash
|
||||
set -euxo pipefail
|
||||
editorconfig-checker
|
||||
flake8
|
||||
find . -type f -iregex ".*\.\(c\|h\|cpp\|ino\)" -exec clang-format-6.0 -i -style=file {} \; && git diff --exit-code
|
|
@ -0,0 +1,20 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
## [0.2.0] - 2022-03-30
|
||||
|
||||
Add support for SEN50
|
||||
|
||||
## [0.1.0] - 2022-01-05
|
||||
|
||||
Initial release
|
||||
|
||||
[0.2.0]: https://github.com/Sensirion/embedded-i2c-sen5x/compare/0.1.0...0.2.0
|
||||
[0.1.0]: https://github.com/Sensirion/arduino-i2c-sen5x/releases/tag/0.1.0
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, Sensirion AG
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,97 @@
|
|||
<!-- Downloaded from https://github.com/Sensirion/arduino-i2c-sen5x
|
||||
on 10/01/2023 at commit d7a73c86073cca34b84cde83814f5c17b87aad6d -->
|
||||
# Sensirion I2C SEN5X Arduino Library
|
||||
|
||||
This is the Sensirion SEN5X library for Arduino using the
|
||||
modules I2C interface.
|
||||
|
||||
<center><img src="images/SEN5x.png" width="500px"></center>
|
||||
|
||||
## Supported sensors
|
||||
|
||||
- SEN50 (only particulate matter signals available)
|
||||
- SEN54 (no NOx signal available)
|
||||
- SEN55 (full feature set)
|
||||
|
||||
# Installation
|
||||
|
||||
To install, download the latest release as .zip file and add it to your
|
||||
[Arduino IDE](http://www.arduino.cc/en/main/software) via
|
||||
|
||||
Sketch => Include Library => Add .ZIP Library...
|
||||
|
||||
Don't forget to **install the dependencies** listed below the same way via `Add
|
||||
.ZIP Library`
|
||||
|
||||
Note: Installation via the Arduino Library Manager is coming soon.
|
||||
|
||||
# Dependencies
|
||||
|
||||
* [Sensirion Core](https://github.com/Sensirion/arduino-core)
|
||||
|
||||
|
||||
# Quick Start
|
||||
|
||||
1. Connect the SEN5X Sensor to your Arduino board's standard
|
||||
I2C bus. Check the pinout of your Arduino board to find the correct pins.
|
||||
The pinout of the SEN5X Sensor board can be found in the
|
||||
data sheet.
|
||||
|
||||
| *SEN5X* | *Arduino* | *Jumper Wire* |
|
||||
| ------- | ----------- | ------------- |
|
||||
| VCC | 5V | Red |
|
||||
| GND | GND | Black |
|
||||
| SDA | SDA | Green |
|
||||
| SCL | SCL | Yellow |
|
||||
| SEL | GND for I2C | Blue |
|
||||
|
||||
<center><img src="images/SEN5X_pinout.png" width="300px"></center>
|
||||
|
||||
| *Pin* | *Name* | *Description* | *Comments* |
|
||||
| ----- | ------ | ------------------------------- | -------------------------------- |
|
||||
| 1 | VCC | Supply Voltage | 5V ±10% |
|
||||
| 2 | GND | Ground |
|
||||
| 3 | SDA | I2C: Serial data input / output | TTL 5V and LVTTL 3.3V compatible |
|
||||
| 4 | SCL | I2C: Serial clock input | TTL 5V and LVTTL 3.3V compatible |
|
||||
| 5 | SEL | Interface select | Pull to GND to select I2C |
|
||||
| 6 | NC | Do not connect |
|
||||
|
||||
2. Open the `exampleUsage` sample project within the Arduino IDE
|
||||
|
||||
File => Examples => Sensirion I2C SEN5X => exampleUsage
|
||||
|
||||
3. Click the `Upload` button in the Arduino IDE or
|
||||
|
||||
Sketch => Upload
|
||||
|
||||
4. When the upload process has finished, open the `Serial Monitor` or `Serial
|
||||
Plotter` via the `Tools` menu to observe the measurement values. Note that
|
||||
the `Baud Rate` in the corresponding window has to be set to `115200 baud`.
|
||||
|
||||
# Contributing
|
||||
|
||||
**Contributions are welcome!**
|
||||
|
||||
We develop and test this driver using our company internal tools (version
|
||||
control, continuous integration, code review etc.) and automatically
|
||||
synchronize the master branch with GitHub. But this doesn't mean that we don't
|
||||
respond to issues or don't accept pull requests on GitHub. In fact, you're very
|
||||
welcome to open issues or create pull requests :)
|
||||
|
||||
This Sensirion library uses
|
||||
[`clang-format`](https://releases.llvm.org/download.html) to standardize the
|
||||
formatting of all our `.cpp` and `.h` files. Make sure your contributions are
|
||||
formatted accordingly:
|
||||
|
||||
The `-i` flag will apply the format changes to the files listed.
|
||||
|
||||
```bash
|
||||
clang-format -i src/*.cpp src/*.h
|
||||
```
|
||||
|
||||
Note that differences from this formatting will result in a failed build until
|
||||
they are fixed.
|
||||
|
||||
# License
|
||||
|
||||
See [LICENSE](LICENSE).
|
|
@ -0,0 +1,249 @@
|
|||
|
||||
/*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-112-g190ecaa
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SensirionI2CSen5x.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// The used commands use up to 48 bytes. On some Arduino's the default buffer
|
||||
// space is not large enough
|
||||
#define MAXBUF_REQUIREMENT 48
|
||||
|
||||
#if (defined(I2C_BUFFER_LENGTH) && \
|
||||
(I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || \
|
||||
(defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT)
|
||||
#define USE_PRODUCT_INFO
|
||||
#endif
|
||||
|
||||
SensirionI2CSen5x sen5x;
|
||||
|
||||
void printModuleVersions() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
|
||||
unsigned char productName[32];
|
||||
uint8_t productNameSize = 32;
|
||||
|
||||
error = sen5x.getProductName(productName, productNameSize);
|
||||
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getProductName(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("ProductName:");
|
||||
Serial.println((char*)productName);
|
||||
}
|
||||
|
||||
uint8_t firmwareMajor;
|
||||
uint8_t firmwareMinor;
|
||||
bool firmwareDebug;
|
||||
uint8_t hardwareMajor;
|
||||
uint8_t hardwareMinor;
|
||||
uint8_t protocolMajor;
|
||||
uint8_t protocolMinor;
|
||||
|
||||
error = sen5x.getVersion(firmwareMajor, firmwareMinor, firmwareDebug,
|
||||
hardwareMajor, hardwareMinor, protocolMajor,
|
||||
protocolMinor);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getVersion(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("Firmware: ");
|
||||
Serial.print(firmwareMajor);
|
||||
Serial.print(".");
|
||||
Serial.print(firmwareMinor);
|
||||
Serial.print(", ");
|
||||
|
||||
Serial.print("Hardware: ");
|
||||
Serial.print(hardwareMajor);
|
||||
Serial.print(".");
|
||||
Serial.println(hardwareMinor);
|
||||
}
|
||||
}
|
||||
|
||||
void printSerialNumber() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
unsigned char serialNumber[32];
|
||||
uint8_t serialNumberSize = 32;
|
||||
|
||||
error = sen5x.getSerialNumber(serialNumber, serialNumberSize);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute getSerialNumber(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("SerialNumber:");
|
||||
Serial.println((char*)serialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Wire.begin();
|
||||
|
||||
sen5x.begin(Wire);
|
||||
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
error = sen5x.deviceReset();
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute deviceReset(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
}
|
||||
|
||||
// Print SEN55 module information if i2c buffers are large enough
|
||||
#ifdef USE_PRODUCT_INFO
|
||||
printSerialNumber();
|
||||
printModuleVersions();
|
||||
#endif
|
||||
|
||||
// set a temperature offset in degrees celsius
|
||||
// Note: supported by SEN54 and SEN55 sensors
|
||||
// By default, the temperature and humidity outputs from the sensor
|
||||
// are compensated for the modules self-heating. If the module is
|
||||
// designed into a device, the temperature compensation might need
|
||||
// to be adapted to incorporate the change in thermal coupling and
|
||||
// self-heating of other device components.
|
||||
//
|
||||
// A guide to achieve optimal performance, including references
|
||||
// to mechanical design-in examples can be found in the app note
|
||||
// “SEN5x – Temperature Compensation Instruction” at www.sensirion.com.
|
||||
// Please refer to those application notes for further information
|
||||
// on the advanced compensation settings used
|
||||
// in `setTemperatureOffsetParameters`, `setWarmStartParameter` and
|
||||
// `setRhtAccelerationMode`.
|
||||
//
|
||||
// Adjust tempOffset to account for additional temperature offsets
|
||||
// exceeding the SEN module's self heating.
|
||||
float tempOffset = 0.0;
|
||||
error = sen5x.setTemperatureOffsetSimple(tempOffset);
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute setTemperatureOffsetSimple(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("Temperature Offset set to ");
|
||||
Serial.print(tempOffset);
|
||||
Serial.println(" deg. Celsius (SEN54/SEN55 only");
|
||||
}
|
||||
|
||||
// Start Measurement
|
||||
error = sen5x.startMeasurement();
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute startMeasurement(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
|
||||
delay(1000);
|
||||
|
||||
// Read Measurement
|
||||
float massConcentrationPm1p0;
|
||||
float massConcentrationPm2p5;
|
||||
float massConcentrationPm4p0;
|
||||
float massConcentrationPm10p0;
|
||||
float ambientHumidity;
|
||||
float ambientTemperature;
|
||||
float vocIndex;
|
||||
float noxIndex;
|
||||
|
||||
error = sen5x.readMeasuredValues(
|
||||
massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0,
|
||||
massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex,
|
||||
noxIndex);
|
||||
|
||||
if (error) {
|
||||
Serial.print("Error trying to execute readMeasuredValues(): ");
|
||||
errorToString(error, errorMessage, 256);
|
||||
Serial.println(errorMessage);
|
||||
} else {
|
||||
Serial.print("MassConcentrationPm1p0:");
|
||||
Serial.print(massConcentrationPm1p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm2p5:");
|
||||
Serial.print(massConcentrationPm2p5);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm4p0:");
|
||||
Serial.print(massConcentrationPm4p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("MassConcentrationPm10p0:");
|
||||
Serial.print(massConcentrationPm10p0);
|
||||
Serial.print("\t");
|
||||
Serial.print("AmbientHumidity:");
|
||||
if (isnan(ambientHumidity)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(ambientHumidity);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("AmbientTemperature:");
|
||||
if (isnan(ambientTemperature)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(ambientTemperature);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("VocIndex:");
|
||||
if (isnan(vocIndex)) {
|
||||
Serial.print("n/a");
|
||||
} else {
|
||||
Serial.print(vocIndex);
|
||||
}
|
||||
Serial.print("\t");
|
||||
Serial.print("NoxIndex:");
|
||||
if (isnan(noxIndex)) {
|
||||
Serial.println("n/a");
|
||||
} else {
|
||||
Serial.println(noxIndex);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
After Width: | Height: | Size: 440 KiB |
|
@ -0,0 +1,55 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SensirionI2CSen5x KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
startMeasurement KEYWORD2
|
||||
startMeasurementWithoutPm KEYWORD2
|
||||
stopMeasurement KEYWORD2
|
||||
readDataReady KEYWORD2
|
||||
readMeasuredValues KEYWORD2
|
||||
readMeasuredValuesAsIntegers KEYWORD2
|
||||
readMeasuredValuesSen50 KEYWORD2
|
||||
readMeasuredRawValues KEYWORD2
|
||||
readMeasuredPmValues KEYWORD2
|
||||
readMeasuredPmValuesAsIntegers KEYWORD2
|
||||
startFanCleaning KEYWORD2
|
||||
setTemperatureOffsetSimple KEYWORD2
|
||||
getTemperatureOffsetSimple KEYWORD2
|
||||
setTemperatureOffsetParameters KEYWORD2
|
||||
getTemperatureOffsetParameters KEYWORD2
|
||||
setWarmStartParameter KEYWORD2
|
||||
getWarmStartParameter KEYWORD2
|
||||
setVocAlgorithmTuningParameters KEYWORD2
|
||||
getVocAlgorithmTuningParameters KEYWORD2
|
||||
setNoxAlgorithmTuningParameters KEYWORD2
|
||||
getNoxAlgorithmTuningParameters KEYWORD2
|
||||
setRhtAccelerationMode KEYWORD2
|
||||
getRhtAccelerationMode KEYWORD2
|
||||
setVocAlgorithmState KEYWORD2
|
||||
getVocAlgorithmState KEYWORD2
|
||||
setFanAutoCleaningInterval KEYWORD2
|
||||
getFanAutoCleaningInterval KEYWORD2
|
||||
getProductName KEYWORD2
|
||||
getSerialNumber KEYWORD2
|
||||
getVersion KEYWORD2
|
||||
readDeviceStatus KEYWORD2
|
||||
readAndClearDeviceStatus KEYWORD2
|
||||
deviceReset KEYWORD2
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
sen5x KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
|
@ -0,0 +1,10 @@
|
|||
name=Sensirion I2C SEN5X
|
||||
version=0.2.0
|
||||
author=Sensirion
|
||||
maintainer=Sensirion
|
||||
sentence=Library for the SEN5X sensor family by Sensirion
|
||||
paragraph=Enables you to use the SEN50, SEN54 and SEN55 via I2C.
|
||||
url=https://github.com/Sensirion/arduino-i2c-sen5x
|
||||
category=Sensors
|
||||
depends=Sensirion Core
|
||||
includes=SensirionI2CSen5x.h
|
|
@ -0,0 +1,880 @@
|
|||
/*
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED
|
||||
*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-112-g190ecaa
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SensirionI2CSen5x.h"
|
||||
#include "Arduino.h"
|
||||
#include "SensirionCore.h"
|
||||
#include <Wire.h>
|
||||
#include <math.h>
|
||||
|
||||
#define SEN5X_I2C_ADDRESS 0x69
|
||||
#define UINT_INVALID 0xFFFF
|
||||
#define INT_INVALID 0x7FFF
|
||||
|
||||
SensirionI2CSen5x::SensirionI2CSen5x() {
|
||||
}
|
||||
|
||||
void SensirionI2CSen5x::begin(TwoWire& i2cBus) {
|
||||
_i2cBus = &i2cBus;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::startMeasurement() {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[2];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x21, buffer, 2);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(50);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::startMeasurementWithoutPm() {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[2];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x37, buffer, 2);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(50);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::stopMeasurement() {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[2];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x104, buffer, 2);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(200);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readDataReady(bool& dataReady) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[3];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x202, buffer, 3);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 3);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t padding;
|
||||
error |= rxFrame.getUInt8(padding); // remove padding
|
||||
error |= rxFrame.getBool(dataReady);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredValues(
|
||||
float& massConcentrationPm1p0, float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0, float& massConcentrationPm10p0,
|
||||
float& ambientHumidity, float& ambientTemperature, float& vocIndex,
|
||||
float& noxIndex) {
|
||||
|
||||
uint16_t error = 0;
|
||||
uint16_t massConcentrationPm1p0Int;
|
||||
uint16_t massConcentrationPm2p5Int;
|
||||
uint16_t massConcentrationPm4p0Int;
|
||||
uint16_t massConcentrationPm10p0Int;
|
||||
int16_t ambientHumidityInt;
|
||||
int16_t ambientTemperatureInt;
|
||||
int16_t vocIndexInt;
|
||||
int16_t noxIndexInt;
|
||||
|
||||
error = readMeasuredValuesAsIntegers(
|
||||
massConcentrationPm1p0Int, massConcentrationPm2p5Int,
|
||||
massConcentrationPm4p0Int, massConcentrationPm10p0Int,
|
||||
ambientHumidityInt, ambientTemperatureInt, vocIndexInt, noxIndexInt);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm1p0Int / 10.0f;
|
||||
massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm2p5Int / 10.0f;
|
||||
massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm4p0Int / 10.0f;
|
||||
massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm10p0Int / 10.0f;
|
||||
ambientHumidity =
|
||||
ambientHumidityInt == INT_INVALID ? NAN : ambientHumidityInt / 100.0f;
|
||||
ambientTemperature = ambientTemperatureInt == INT_INVALID
|
||||
? NAN
|
||||
: ambientTemperatureInt / 200.0f;
|
||||
vocIndex = vocIndexInt == INT_INVALID ? NAN : vocIndexInt / 10.0f;
|
||||
noxIndex = noxIndexInt == INT_INVALID ? NAN : noxIndexInt / 10.0f;
|
||||
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredValuesAsIntegers(
|
||||
uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5,
|
||||
uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0,
|
||||
int16_t& ambientHumidity, int16_t& ambientTemperature, int16_t& vocIndex,
|
||||
int16_t& noxIndex) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[24];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x3C4, buffer, 24);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 24);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 24,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt16(massConcentrationPm1p0);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm2p5);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm4p0);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm10p0);
|
||||
error |= rxFrame.getInt16(ambientHumidity);
|
||||
error |= rxFrame.getInt16(ambientTemperature);
|
||||
error |= rxFrame.getInt16(vocIndex);
|
||||
error |= rxFrame.getInt16(noxIndex);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredRawValues(int16_t& rawHumidity,
|
||||
int16_t& rawTemperature,
|
||||
uint16_t& rawVoc,
|
||||
uint16_t& rawNox) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[12];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x3D2, buffer, 12);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 12);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getInt16(rawHumidity);
|
||||
error |= rxFrame.getInt16(rawTemperature);
|
||||
error |= rxFrame.getUInt16(rawVoc);
|
||||
error |= rxFrame.getUInt16(rawNox);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredValuesSen50(
|
||||
float& massConcentrationPm1p0, float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0, float& massConcentrationPm10p0) {
|
||||
|
||||
uint16_t error = 0;
|
||||
float ambientHumidityDummy;
|
||||
float ambientTemperatureDummy;
|
||||
float vocIndexDummy;
|
||||
float noxIndexDummy;
|
||||
error = readMeasuredValues(massConcentrationPm1p0, massConcentrationPm2p5,
|
||||
massConcentrationPm4p0, massConcentrationPm10p0,
|
||||
ambientHumidityDummy, ambientTemperatureDummy,
|
||||
vocIndexDummy, noxIndexDummy);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredPmValues(
|
||||
float& massConcentrationPm1p0, float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0, float& massConcentrationPm10p0,
|
||||
float& numberConcentrationPm0p5, float& numberConcentrationPm1p0,
|
||||
float& numberConcentrationPm2p5, float& numberConcentrationPm4p0,
|
||||
float& numberConcentrationPm10p0, float& typicalParticleSize) {
|
||||
|
||||
uint16_t error = 0;
|
||||
uint16_t massConcentrationPm1p0Int;
|
||||
uint16_t massConcentrationPm2p5Int;
|
||||
uint16_t massConcentrationPm4p0Int;
|
||||
uint16_t massConcentrationPm10p0Int;
|
||||
uint16_t numberConcentrationPm0p5Int;
|
||||
uint16_t numberConcentrationPm1p0Int;
|
||||
uint16_t numberConcentrationPm2p5Int;
|
||||
uint16_t numberConcentrationPm4p0Int;
|
||||
uint16_t numberConcentrationPm10p0Int;
|
||||
uint16_t typicalParticleSizeInt;
|
||||
|
||||
error = readMeasuredPmValuesAsIntegers(
|
||||
massConcentrationPm1p0Int, massConcentrationPm2p5Int,
|
||||
massConcentrationPm4p0Int, massConcentrationPm10p0Int,
|
||||
numberConcentrationPm0p5Int, numberConcentrationPm1p0Int,
|
||||
numberConcentrationPm2p5Int, numberConcentrationPm4p0Int,
|
||||
numberConcentrationPm10p0Int, typicalParticleSizeInt);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm1p0Int / 10.0f;
|
||||
massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm2p5Int / 10.0f;
|
||||
massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm4p0Int / 10.0f;
|
||||
massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: massConcentrationPm10p0Int / 10.0f;
|
||||
numberConcentrationPm0p5 = numberConcentrationPm0p5Int == UINT_INVALID
|
||||
? NAN
|
||||
: numberConcentrationPm0p5Int / 10.0f;
|
||||
numberConcentrationPm1p0 = numberConcentrationPm1p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: numberConcentrationPm1p0Int / 10.0f;
|
||||
numberConcentrationPm2p5 = numberConcentrationPm2p5Int == UINT_INVALID
|
||||
? NAN
|
||||
: numberConcentrationPm2p5Int / 10.0f;
|
||||
numberConcentrationPm4p0 = numberConcentrationPm4p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: numberConcentrationPm4p0Int / 10.0f;
|
||||
numberConcentrationPm10p0 = numberConcentrationPm10p0Int == UINT_INVALID
|
||||
? NAN
|
||||
: numberConcentrationPm10p0Int / 10.0f;
|
||||
typicalParticleSize = typicalParticleSizeInt == UINT_INVALID
|
||||
? NAN
|
||||
: typicalParticleSizeInt / 1000.0f;
|
||||
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readMeasuredPmValuesAsIntegers(
|
||||
uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5,
|
||||
uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0,
|
||||
uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0,
|
||||
uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0,
|
||||
uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[30];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x413, buffer, 30);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 30);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 30,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt16(massConcentrationPm1p0);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm2p5);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm4p0);
|
||||
error |= rxFrame.getUInt16(massConcentrationPm10p0);
|
||||
error |= rxFrame.getUInt16(numberConcentrationPm0p5);
|
||||
error |= rxFrame.getUInt16(numberConcentrationPm1p0);
|
||||
error |= rxFrame.getUInt16(numberConcentrationPm2p5);
|
||||
error |= rxFrame.getUInt16(numberConcentrationPm4p0);
|
||||
error |= rxFrame.getUInt16(numberConcentrationPm10p0);
|
||||
error |= rxFrame.getUInt16(typicalParticleSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::startFanCleaning() {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[2];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x5607, buffer, 2);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setTemperatureOffsetSimple(float tempOffset) {
|
||||
int16_t defaultSlope = 0;
|
||||
uint16_t defaultTimeConstant = 0;
|
||||
int16_t tempOffsetTicks = static_cast<int16_t>(tempOffset * 200);
|
||||
return setTemperatureOffsetParameters(tempOffsetTicks, defaultSlope,
|
||||
defaultTimeConstant);
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getTemperatureOffsetSimple(float& tempOffset) {
|
||||
int16_t tempOffsetTicks;
|
||||
int16_t slope;
|
||||
uint16_t timeConstant;
|
||||
uint16_t error = 0;
|
||||
|
||||
error =
|
||||
getTemperatureOffsetParameters(tempOffsetTicks, slope, timeConstant);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
tempOffset = static_cast<float>(tempOffsetTicks) / 200.0f;
|
||||
|
||||
return NoError;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setTemperatureOffsetParameters(
|
||||
int16_t tempOffset, int16_t slope, uint16_t timeConstant) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[11];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 11);
|
||||
|
||||
error |= txFrame.addInt16(tempOffset);
|
||||
error |= txFrame.addInt16(slope);
|
||||
error |= txFrame.addUInt16(timeConstant);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getTemperatureOffsetParameters(
|
||||
int16_t& tempOffset, int16_t& slope, uint16_t& timeConstant) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[9];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 9);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 9);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 9,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getInt16(tempOffset);
|
||||
error |= rxFrame.getInt16(slope);
|
||||
error |= rxFrame.getUInt16(timeConstant);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setWarmStartParameter(uint16_t warmStart) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[5];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 5);
|
||||
|
||||
error |= txFrame.addUInt16(warmStart);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getWarmStartParameter(uint16_t& warmStart) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[3];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 3);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 3);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt16(warmStart);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setVocAlgorithmTuningParameters(
|
||||
int16_t indexOffset, int16_t learningTimeOffsetHours,
|
||||
int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes,
|
||||
int16_t stdInitial, int16_t gainFactor) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[20];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 20);
|
||||
|
||||
error |= txFrame.addInt16(indexOffset);
|
||||
error |= txFrame.addInt16(learningTimeOffsetHours);
|
||||
error |= txFrame.addInt16(learningTimeGainHours);
|
||||
error |= txFrame.addInt16(gatingMaxDurationMinutes);
|
||||
error |= txFrame.addInt16(stdInitial);
|
||||
error |= txFrame.addInt16(gainFactor);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getVocAlgorithmTuningParameters(
|
||||
int16_t& indexOffset, int16_t& learningTimeOffsetHours,
|
||||
int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes,
|
||||
int16_t& stdInitial, int16_t& gainFactor) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[18];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 18);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 18);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getInt16(indexOffset);
|
||||
error |= rxFrame.getInt16(learningTimeOffsetHours);
|
||||
error |= rxFrame.getInt16(learningTimeGainHours);
|
||||
error |= rxFrame.getInt16(gatingMaxDurationMinutes);
|
||||
error |= rxFrame.getInt16(stdInitial);
|
||||
error |= rxFrame.getInt16(gainFactor);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setNoxAlgorithmTuningParameters(
|
||||
int16_t indexOffset, int16_t learningTimeOffsetHours,
|
||||
int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes,
|
||||
int16_t stdInitial, int16_t gainFactor) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[20];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 20);
|
||||
|
||||
error |= txFrame.addInt16(indexOffset);
|
||||
error |= txFrame.addInt16(learningTimeOffsetHours);
|
||||
error |= txFrame.addInt16(learningTimeGainHours);
|
||||
error |= txFrame.addInt16(gatingMaxDurationMinutes);
|
||||
error |= txFrame.addInt16(stdInitial);
|
||||
error |= txFrame.addInt16(gainFactor);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getNoxAlgorithmTuningParameters(
|
||||
int16_t& indexOffset, int16_t& learningTimeOffsetHours,
|
||||
int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes,
|
||||
int16_t& stdInitial, int16_t& gainFactor) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[18];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 18);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 18);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getInt16(indexOffset);
|
||||
error |= rxFrame.getInt16(learningTimeOffsetHours);
|
||||
error |= rxFrame.getInt16(learningTimeGainHours);
|
||||
error |= rxFrame.getInt16(gatingMaxDurationMinutes);
|
||||
error |= rxFrame.getInt16(stdInitial);
|
||||
error |= rxFrame.getInt16(gainFactor);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setRhtAccelerationMode(uint16_t mode) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[5];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 5);
|
||||
|
||||
error |= txFrame.addUInt16(mode);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getRhtAccelerationMode(uint16_t& mode) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[3];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 3);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 3);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt16(mode);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setVocAlgorithmState(const uint8_t state[],
|
||||
uint8_t stateSize) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[14];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 14);
|
||||
|
||||
error |= txFrame.addBytes(state, stateSize);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getVocAlgorithmState(uint8_t state[],
|
||||
uint8_t stateSize) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[12];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 12);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 12);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getBytes(state, stateSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::setFanAutoCleaningInterval(uint32_t interval) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[8];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 8);
|
||||
|
||||
error |= txFrame.addUInt32(interval);
|
||||
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(20);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getFanAutoCleaningInterval(uint32_t& interval) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[6];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 6);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 6);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt32(interval);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getProductName(unsigned char productName[],
|
||||
uint8_t productNameSize) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[48];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD014, buffer, 48);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 48);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getBytes(productName, productNameSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::getSerialNumber(unsigned char serialNumber[],
|
||||
uint8_t serialNumberSize) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[48];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD033, buffer, 48);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 48);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getBytes(serialNumber, serialNumberSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
SensirionI2CSen5x::getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor,
|
||||
bool& firmwareDebug, uint8_t& hardwareMajor,
|
||||
uint8_t& hardwareMinor, uint8_t& protocolMajor,
|
||||
uint8_t& protocolMinor) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[12];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD100, buffer, 12);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 12);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt8(firmwareMajor);
|
||||
error |= rxFrame.getUInt8(firmwareMinor);
|
||||
error |= rxFrame.getBool(firmwareDebug);
|
||||
error |= rxFrame.getUInt8(hardwareMajor);
|
||||
error |= rxFrame.getUInt8(hardwareMinor);
|
||||
error |= rxFrame.getUInt8(protocolMajor);
|
||||
error |= rxFrame.getUInt8(protocolMinor);
|
||||
uint8_t padding;
|
||||
error |= rxFrame.getUInt8(padding); // remove padding
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readDeviceStatus(uint32_t& deviceStatus) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[6];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD206, buffer, 6);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 6);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt32(deviceStatus);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::readAndClearDeviceStatus(uint32_t& deviceStatus) {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[6];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD210, buffer, 6);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
SensirionI2CRxFrame rxFrame(buffer, 6);
|
||||
error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6,
|
||||
rxFrame, *_i2cBus);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error |= rxFrame.getUInt32(deviceStatus);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t SensirionI2CSen5x::deviceReset() {
|
||||
uint16_t error = 0;
|
||||
uint8_t buffer[2];
|
||||
SensirionI2CTxFrame txFrame =
|
||||
SensirionI2CTxFrame::createWithUInt16Command(0xD304, buffer, 2);
|
||||
|
||||
error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame,
|
||||
*_i2cBus);
|
||||
delay(200);
|
||||
return error;
|
||||
}
|
|
@ -0,0 +1,857 @@
|
|||
/*
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED
|
||||
*
|
||||
* I2C-Generator: 0.3.0
|
||||
* Yaml Version: 2.1.3
|
||||
* Template Version: 0.7.0-112-g190ecaa
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021, Sensirion AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Sensirion AG nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SENSIRIONI2CSEN5X_H
|
||||
#define SENSIRIONI2CSEN5X_H
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include <SensirionCore.h>
|
||||
|
||||
class SensirionI2CSen5x {
|
||||
|
||||
public:
|
||||
SensirionI2CSen5x();
|
||||
/**
|
||||
* begin() - Initializes the SensirionI2CSen5x class.
|
||||
*
|
||||
* @param serial Arduino stream object to be communicated with.
|
||||
*
|
||||
*/
|
||||
void begin(TwoWire& i2cBus);
|
||||
|
||||
/**
|
||||
* startMeasurement() - Starts a continuous measurement.
|
||||
|
||||
* After starting the measurement, it takes some time (~1s) until the first
|
||||
* measurement results are available. You could poll with the command
|
||||
* 0x0202 \"Read Data Ready\" to check when the results are ready to read.
|
||||
*
|
||||
* This command is only available in idle mode. If the device is already
|
||||
* in any measure mode, this command has no effect.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t startMeasurement(void);
|
||||
|
||||
/**
|
||||
* startMeasurementWithoutPm() - Starts a continuous measurement without PM.
|
||||
* Only humidity, temperature, VOC and NOx are available in this mode. Laser
|
||||
* and fan are switched off to keep power consumption low.
|
||||
*
|
||||
* After starting the measurement, it takes some time (~1s) until the first
|
||||
* measurement results are available. You could poll with the command
|
||||
* 0x0202 \"Read Data Ready\" to check when the results are ready to read.
|
||||
*
|
||||
* This command is only available in idle mode. If the device is already
|
||||
* in any measure mode, this command has no effect.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t startMeasurementWithoutPm(void);
|
||||
|
||||
/**
|
||||
* stopMeasurement() - Stops the measurement and returns to idle mode.
|
||||
*
|
||||
* If the device is already in idle mode, this command has no effect.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t stopMeasurement(void);
|
||||
|
||||
/**
|
||||
* readDataReady() - This command can be used to check if new measurement
|
||||
* results are ready to read. The data ready flag is automatically reset
|
||||
* after reading the measurement values with the 0x03.. \"Read Measured
|
||||
* Values\" commands.
|
||||
*
|
||||
* @note During fan (auto-)cleaning, no measurement data is available for
|
||||
* several seconds and thus this flag will not be set until cleaning has
|
||||
* finished. So please expect gaps of several seconds at any time if fan
|
||||
* auto-cleaning is enabled.
|
||||
*
|
||||
* @param padding Padding byte, always 0x00.
|
||||
*
|
||||
* @param dataReady True (0x01) if data is ready, False (0x00) if not. When
|
||||
* no measurement is running, False will be returned.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readDataReady(bool& dataReady);
|
||||
|
||||
/**
|
||||
* readMeasuredValues() - Returns the measured values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data is
|
||||
* available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be NAN.
|
||||
*
|
||||
* @param massConcentrationPm1p0 PM1.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm2p5 PM2.5 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm4p0 PM4.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm10p0 PM10.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param ambientHumidity RH [%]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param ambientTemperature T [°C]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param vocIndex VOC Index
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param noxIndex NOx Index
|
||||
* Note: If this value is unknown, which is true for SEN54,
|
||||
* NAN is returned. During the first 10..11 seconds after
|
||||
* power-on or device reset, this value will be NAN as well.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredValues(float& massConcentrationPm1p0,
|
||||
float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0,
|
||||
float& massConcentrationPm10p0,
|
||||
float& ambientHumidity,
|
||||
float& ambientTemperature, float& vocIndex,
|
||||
float& noxIndex);
|
||||
|
||||
/**
|
||||
* readMeasuredValuesAsIntegers() - Returns the measured values
|
||||
* without scaling factors applied.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data is
|
||||
* available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be at their upper limit (0xFFFF for `uint16`,
|
||||
* 0x7FFF for `int16`).
|
||||
*
|
||||
* @param massConcentrationPm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [µg/m³] = value / 10
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [µg/m³] = value / 10
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [µg/m³] = value / 10
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [µg/m³] = value / 10
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param ambientHumidity Value is scaled with factor 100:
|
||||
* RH [%] = value /100
|
||||
* Note: If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param ambientTemperature Value is scaled with factor 200:
|
||||
* T [°C] = value / 200
|
||||
* Note: If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param vocIndex Value is scaled with factor 10: VOC Index = value / 10
|
||||
* Note: If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param noxIndex Value is scaled with factor 10: NOx Index = value / 10
|
||||
* Note: If this value is unknown, which is the case for SEN54,
|
||||
* 0x7FFF is returned. During the first 10..11 seconds after power-on
|
||||
* or device reset, this value will be 0x7FFF as well.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredValuesAsIntegers(uint16_t& massConcentrationPm1p0,
|
||||
uint16_t& massConcentrationPm2p5,
|
||||
uint16_t& massConcentrationPm4p0,
|
||||
uint16_t& massConcentrationPm10p0,
|
||||
int16_t& ambientHumidity,
|
||||
int16_t& ambientTemperature,
|
||||
int16_t& vocIndex, int16_t& noxIndex);
|
||||
|
||||
/**
|
||||
* readMeasuredRawValues() - Returns the measured raw values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data
|
||||
* is available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be at their upper limit (0xFFFF for `uint16`,
|
||||
* 0x7FFF for `int16`).
|
||||
*
|
||||
* Supported sensors: SEN54 (no NOx), SEN55
|
||||
*
|
||||
* @param rawHumidity Value is scaled with factor 100: RH [%] = value / 100
|
||||
* Note: If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param rawTemperature Value is scaled with factor 200:
|
||||
* T [°C] = value / 200
|
||||
* Note: If this value is unknown, 0x7FFF is returned.*
|
||||
*
|
||||
* @param rawVoc Raw measured VOC ticks without scale factor.
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param rawNox Raw measured NOx ticks without scale factor.
|
||||
* Note: If this value is unknown, which is the case for SEN54,
|
||||
* 0x7FFF is returned. During the first 10..11 seconds after power-on
|
||||
* or device reset, this value will be 0x7FFF as well.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredRawValues(int16_t& rawHumidity,
|
||||
int16_t& rawTemperature, uint16_t& rawVoc,
|
||||
uint16_t& rawNox);
|
||||
|
||||
/**
|
||||
* readMeasuredValuesSen50() - Returns the measured values for SEN50.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data is
|
||||
* available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be NAN.
|
||||
*
|
||||
* @param massConcentrationPm1p0 PM1.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm2p5 PM2.5 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm4p0 PM4.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm10p0 PM10.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredValuesSen50(float& massConcentrationPm1p0,
|
||||
float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0,
|
||||
float& massConcentrationPm10p0);
|
||||
|
||||
/**
|
||||
* readMeasuredPmValues() - Returns the measured particulate matter values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data
|
||||
* is available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be NAN.
|
||||
*
|
||||
* @param massConcentrationPm1p0 PM1.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm2p5 PM2.5 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm4p0 PM4.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param massConcentrationPm10p0 PM10.0 [µg/m³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm0p5 PM0.5 [#/cm³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm1p0 PM1.0 [#/cm³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm2p5 PM2.5 [#/cm³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm4p0 PM4.0 [#/cm³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm10p0 PM10.0 [#/cm³]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @param typicalParticleSize Size [µm]
|
||||
* Note: If this value is unknown, NAN is returned.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredPmValues(
|
||||
float& massConcentrationPm1p0, float& massConcentrationPm2p5,
|
||||
float& massConcentrationPm4p0, float& massConcentrationPm10p0,
|
||||
float& numberConcentrationPm0p5, float& numberConcentrationPm1p0,
|
||||
float& numberConcentrationPm2p5, float& numberConcentrationPm4p0,
|
||||
float& numberConcentrationPm10p0, float& typicalParticleSize);
|
||||
|
||||
/**
|
||||
* readMeasuredPmValuesAsIntegers() - Returns the measured particulate
|
||||
* matter values.
|
||||
*
|
||||
* The command 0x0202 \"Read Data Ready\" can be used to check if new
|
||||
* data is available since the last read operation. If no new data is
|
||||
* available, the previous values will be returned again. If no data
|
||||
* is available at all (e.g. measurement not running for at least one
|
||||
* second), all values will be 0xFFFF.
|
||||
*
|
||||
* @param massConcentrationPm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [µg/m³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [µg/m³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [µg/m³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param massConcentrationPm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [µg/m³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm0p5 Value is scaled with factor 10:
|
||||
* PM0.5 [#/cm³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm1p0 Value is scaled with factor 10:
|
||||
* PM1.0 [#/cm³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm2p5 Value is scaled with factor 10:
|
||||
* PM2.5 [#/cm³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm4p0 Value is scaled with factor 10:
|
||||
* PM4.0 [#/cm³] = value / 1
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param numberConcentrationPm10p0 Value is scaled with factor 10:
|
||||
* PM10.0 [#/cm³] = value / 10
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @param typicalParticleSize Value is scaled with factor 1000:
|
||||
* Size [µm] = value / 1000
|
||||
* Note: If this value is unknown, 0xFFFF is returned.*
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readMeasuredPmValuesAsIntegers(
|
||||
uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5,
|
||||
uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0,
|
||||
uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0,
|
||||
uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0,
|
||||
uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize);
|
||||
|
||||
/**
|
||||
* startFanCleaning() - Starts the fan cleaning manually. The \"data
|
||||
* ready\"-flag will be cleared immediately and during the next few seconds,
|
||||
* no new measurement results will be available (old values will be
|
||||
* returned). Once the cleaning is finished, the \"data ready\"-flag will be
|
||||
* set and new measurement results will be available.
|
||||
*
|
||||
* When executing this command while cleaning is already active, the
|
||||
* command does nothing.
|
||||
*
|
||||
* If you stop the measurement while fan cleaning is active, the cleaning
|
||||
* will be aborted immediately.
|
||||
*
|
||||
* @note This command is only available in measure mode with PM measurement
|
||||
* enabled, i.e. only if the fan is already running. In any other state,
|
||||
* this command does nothing.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t startFanCleaning(void);
|
||||
|
||||
/**
|
||||
* setTemperatureOffsetSimple() - Sets the temperature offset parameter
|
||||
* in degrees celsius for the device, while leaving the other parameters at
|
||||
* their default setting.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param tempOffset Constant temperature offset in degrees celsius.
|
||||
* The default value is 0.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setTemperatureOffsetSimple(float tempOffset);
|
||||
|
||||
/**
|
||||
* getTemperatureOffsetSimple() - Gets the temperature offset parameter
|
||||
* in degrees celsius from the device.
|
||||
* @note The other parameters, such as slope and time constant may differ
|
||||
* from the default values, if they were previously set using
|
||||
* `setTemperatureOffsetParameters`.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param tempOffset Constant temperature offset in degrees celsius.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getTemperatureOffsetSimple(float& tempOffset);
|
||||
|
||||
/**
|
||||
* setTemperatureOffsetParameters() - Sets the temperature offset parameters
|
||||
* for the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param tempOffset Constant temperature offset scaled with factor 200 (T
|
||||
* [°C] = value / 200). The default value is 0.
|
||||
*
|
||||
* @param slope Normalized temperature offset slope scaled with factor 10000
|
||||
* (applied factor = value / 10000). The default value is 0.
|
||||
*
|
||||
* @param timeConstant Time constant [s] how fast the new slope and offset
|
||||
* will be applied. After the specified value in seconds, 63% of the new
|
||||
* slope and offset are applied. A time constant of zero means the new
|
||||
* values will be applied immediately (within the next measure interval of 1
|
||||
* second).
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setTemperatureOffsetParameters(int16_t tempOffset, int16_t slope,
|
||||
uint16_t timeConstant);
|
||||
|
||||
/**
|
||||
* getTemperatureOffsetParameters() - Gets the temperature offset parameters
|
||||
* from the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param tempOffset Constant temperature offset scaled with factor 200 (T
|
||||
* [°C] = value / 200).
|
||||
*
|
||||
* @param slope Normalized temperature offset slope scaled with factor 10000
|
||||
* (applied factor = value / 10000).
|
||||
*
|
||||
* @param timeConstant Time constant [s] how fast the slope and offset are
|
||||
* applied. After the specified value in seconds, 63% of the new slope and
|
||||
* offset are applied.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getTemperatureOffsetParameters(int16_t& tempOffset, int16_t& slope,
|
||||
uint16_t& timeConstant);
|
||||
|
||||
/**
|
||||
* setWarmStartParameter() - Sets the warm start parameter for the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This parameter can be changed in any state of the device (and the
|
||||
* getter immediately returns the new value), but it is applied only the
|
||||
* next time starting a measurement, i.e. when sending a \"Start
|
||||
* Measurement\" command! So the parameter needs to be set *before* a
|
||||
* warm-start measurement is started.
|
||||
*
|
||||
* @param warmStart Warm start behavior as a value in the range from 0 (cold
|
||||
* start) to 65535 (warm start). The default value is 0.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setWarmStartParameter(uint16_t warmStart);
|
||||
|
||||
/**
|
||||
* getWarmStartParameter() - Gets the warm start parameter from the device.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param warmStart Warm start behavior as a value in the range from 0 (cold
|
||||
* start) to 65535 (warm start).
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getWarmStartParameter(uint16_t& warmStart);
|
||||
|
||||
/**
|
||||
* setVocAlgorithmTuningParameters() - Sets the tuning parameters of the VOC
|
||||
* algorithm.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This command is available only in idle mode. In measure mode, this
|
||||
* command has no effect. In addition, it has no effect if at least one
|
||||
* parameter is outside the specified range.
|
||||
*
|
||||
* @param indexOffset VOC index representing typical (average) conditions.
|
||||
* Allowed values are in range 1..250. The default value is 100.
|
||||
*
|
||||
* @param learningTimeOffsetHours Time constant to estimate the VOC
|
||||
* algorithm offset from the history in hours. Past events will be forgotten
|
||||
* after about twice the learning time. Allowed values are in range 1..1000.
|
||||
* The default value is 12 hours.
|
||||
*
|
||||
* @param learningTimeGainHours Time constant to estimate the VOC algorithm
|
||||
* gain from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time. Allowed values are in range 1..1000. The default
|
||||
* value is 12 hours.
|
||||
*
|
||||
* @param gatingMaxDurationMinutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high VOC index signal). Set to zero to
|
||||
* disable the gating. Allowed values are in range 0..3000. The default
|
||||
* value is 180 minutes.
|
||||
*
|
||||
* @param stdInitial Initial estimate for standard deviation. Lower value
|
||||
* boosts events during initial learning period, but may result in larger
|
||||
* device-to-device variations. Allowed values are in range 10..5000. The
|
||||
* default value is 50.
|
||||
*
|
||||
* @param gainFactor Gain factor to amplify or to attenuate the VOC index
|
||||
* output. Allowed values are in range 1..1000. The default value is 230.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setVocAlgorithmTuningParameters(int16_t indexOffset,
|
||||
int16_t learningTimeOffsetHours,
|
||||
int16_t learningTimeGainHours,
|
||||
int16_t gatingMaxDurationMinutes,
|
||||
int16_t stdInitial,
|
||||
int16_t gainFactor);
|
||||
|
||||
/**
|
||||
* getVocAlgorithmTuningParameters() - Gets the currently set tuning
|
||||
* parameters of the VOC algorithm.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param indexOffset VOC index representing typical (average) conditions.
|
||||
*
|
||||
* @param learningTimeOffsetHours Time constant to estimate the VOC
|
||||
* algorithm offset from the history in hours. Past events will be forgotten
|
||||
* after about twice the learning time.
|
||||
*
|
||||
* @param learningTimeGainHours Time constant to estimate the VOC algorithm
|
||||
* gain from the history in hours. Past events will be forgotten after about
|
||||
* twice the learning time.
|
||||
*
|
||||
* @param gatingMaxDurationMinutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high VOC index signal). Zero disables the
|
||||
* gating.
|
||||
*
|
||||
* @param stdInitial Initial estimate for standard deviation. Lower value
|
||||
* boosts events during initial learning period, but may result in larger
|
||||
* device-to-device variations.
|
||||
*
|
||||
* @param gainFactor Gain factor to amplify or to attenuate the VOC index
|
||||
* output.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getVocAlgorithmTuningParameters(int16_t& indexOffset,
|
||||
int16_t& learningTimeOffsetHours,
|
||||
int16_t& learningTimeGainHours,
|
||||
int16_t& gatingMaxDurationMinutes,
|
||||
int16_t& stdInitial,
|
||||
int16_t& gainFactor);
|
||||
|
||||
/**
|
||||
* setNoxAlgorithmTuningParameters() - Sets the tuning parameters of the NOx
|
||||
* algorithm.
|
||||
*
|
||||
* Supported sensors: SEN55
|
||||
*
|
||||
* @note This command is available only in idle mode. In measure mode, this
|
||||
* command has no effect. In addition, it has no effect if at least one
|
||||
* parameter is outside the specified range.
|
||||
*
|
||||
* @param indexOffset NOx index representing typical (average) conditions.
|
||||
* Allowed values are in range 1..250. The default value is 1.
|
||||
*
|
||||
* @param learningTimeOffsetHours Time constant to estimate the NOx
|
||||
* algorithm offset from the history in hours. Past events will be forgotten
|
||||
* after about twice the learning time. Allowed values are in range 1..1000.
|
||||
* The default value is 12 hours.
|
||||
*
|
||||
* @param learningTimeGainHours The time constant to estimate the NOx
|
||||
* algorithm gain from the history has no impact for NOx. This parameter is
|
||||
* still in place for consistency reasons with the VOC tuning parameters
|
||||
* command. This parameter must always be set to 12 hours.
|
||||
*
|
||||
* @param gatingMaxDurationMinutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high NOx index signal). Set to zero to
|
||||
* disable the gating. Allowed values are in range 0..3000. The default
|
||||
* value is 720 minutes.
|
||||
*
|
||||
* @param stdInitial The initial estimate for standard deviation parameter
|
||||
* has no impact for NOx. This parameter is still in place for consistency
|
||||
* reasons with the VOC tuning parameters command. This parameter must
|
||||
* always be set to 50.
|
||||
*
|
||||
* @param gainFactor Gain factor to amplify or to attenuate the NOx index
|
||||
* output. Allowed values are in range 1..1000. The default value is 230.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setNoxAlgorithmTuningParameters(int16_t indexOffset,
|
||||
int16_t learningTimeOffsetHours,
|
||||
int16_t learningTimeGainHours,
|
||||
int16_t gatingMaxDurationMinutes,
|
||||
int16_t stdInitial,
|
||||
int16_t gainFactor);
|
||||
|
||||
/**
|
||||
* getNoxAlgorithmTuningParameters() - Gets the currently set tuning
|
||||
* parameters of the NOx algorithm.
|
||||
*
|
||||
* Supported sensors: SEN55
|
||||
*
|
||||
* @param indexOffset NOx index representing typical (average) conditions.
|
||||
*
|
||||
* @param learningTimeOffsetHours Time constant to estimate the NOx
|
||||
* algorithm offset from the history in hours. Past events will be forgotten
|
||||
* after about twice the learning time.
|
||||
*
|
||||
* @param learningTimeGainHours The time constant to estimate the NOx
|
||||
* algorithm gain from the history has no impact for NOx. This parameter is
|
||||
* still in place for consistency reasons with the VOC tuning parameters
|
||||
* command.
|
||||
*
|
||||
* @param gatingMaxDurationMinutes Maximum duration of gating in minutes
|
||||
* (freeze of estimator during high NOx index signal). Zero disables the
|
||||
* gating.
|
||||
*
|
||||
* @param stdInitial The initial estimate for standard deviation has no
|
||||
* impact for NOx. This parameter is still in place for consistency reasons
|
||||
* with the VOC tuning parameters command.
|
||||
*
|
||||
* @param gainFactor Gain factor to amplify or to attenuate the NOx index
|
||||
* output.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getNoxAlgorithmTuningParameters(int16_t& indexOffset,
|
||||
int16_t& learningTimeOffsetHours,
|
||||
int16_t& learningTimeGainHours,
|
||||
int16_t& gatingMaxDurationMinutes,
|
||||
int16_t& stdInitial,
|
||||
int16_t& gainFactor);
|
||||
|
||||
/**
|
||||
* setRhtAccelerationMode() - Sets the RH/T acceleration mode.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This parameter can be changed in any state of the device (and the
|
||||
* getter immediately returns the new value), but it is applied only the
|
||||
* next time starting a measurement, i.e. when sending a \"Start
|
||||
* Measurement\" command. So the parameter needs to be set *before* a new
|
||||
* measurement is started.
|
||||
*
|
||||
* @param mode The new RH/T acceleration mode.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setRhtAccelerationMode(uint16_t mode);
|
||||
|
||||
/**
|
||||
* getRhtAccelerationMode() - Gets the RH/T acceleration mode.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param mode The current RH/T acceleration mode.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getRhtAccelerationMode(uint16_t& mode);
|
||||
|
||||
/**
|
||||
* setVocAlgorithmState() - Sets the VOC algorithm state previously received
|
||||
* with the \"Get VOC Algorithm State\" command.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @note This command is only available in idle mode and the state will be
|
||||
* applied only once when starting the next measurement. Any further
|
||||
* measurements (i.e. when stopping and restarting the measure mode) will
|
||||
* reset the state to initial values. In measure mode, this command has no
|
||||
* effect.
|
||||
*
|
||||
* @param state VOC algorithm state to restore.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setVocAlgorithmState(const uint8_t state[], uint8_t stateSize);
|
||||
|
||||
/**
|
||||
* getVocAlgorithmState() - Gets the current VOC algorithm state. This data
|
||||
* can be used to restore the state with the \"Set VOC Algorithm State\"
|
||||
* command after a short power cycle or device reset.
|
||||
*
|
||||
* This command can be used either in measure mode or in idle mode
|
||||
* (which will then return the state at the time when the measurement
|
||||
* was stopped). In measure mode, the state can be read each measure
|
||||
* interval to always have the latest state available, even in case of
|
||||
* a sudden power loss.
|
||||
*
|
||||
* Supported sensors: SEN54, SEN55
|
||||
*
|
||||
* @param state Current VOC algorithm state.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getVocAlgorithmState(uint8_t state[], uint8_t stateSize);
|
||||
|
||||
/**
|
||||
* setFanAutoCleaningInterval() - Sets the fan auto cleaning interval for
|
||||
* the device.
|
||||
*
|
||||
* @param interval Fan auto cleaning interval [s]. Set to zero to disable
|
||||
* auto cleaning.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t setFanAutoCleaningInterval(uint32_t interval);
|
||||
|
||||
/**
|
||||
* getFanAutoCleaningInterval() - Gets the fan auto cleaning interval from
|
||||
* the device.
|
||||
*
|
||||
* @param interval Fan auto cleaning interval [s]. Zero means auto cleaning
|
||||
* is disabled.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getFanAutoCleaningInterval(uint32_t& interval);
|
||||
|
||||
/**
|
||||
* getProductName() - Gets the product name from the device.
|
||||
*
|
||||
* @param productName Null-terminated ASCII string containing the product
|
||||
* name. Up to 32 characters can be read from the device.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getProductName(unsigned char productName[],
|
||||
uint8_t productNameSize);
|
||||
|
||||
/**
|
||||
* getSerialNumber() - Gets the serial number from the device.
|
||||
*
|
||||
* @param serialNumber Null-terminated ASCII string containing the serial
|
||||
* number. Up to 32 characters can be read from the device.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getSerialNumber(unsigned char serialNumber[],
|
||||
uint8_t serialNumberSize);
|
||||
|
||||
/**
|
||||
* getVersion() - Gets the version information for the hardware, firmware
|
||||
* and communication protocol.
|
||||
*
|
||||
* @param firmwareMajor Firmware major version number.
|
||||
*
|
||||
* @param firmwareMinor Firmware minor version number.
|
||||
*
|
||||
* @param firmwareDebug Firmware debug state. If the debug state is set, the
|
||||
* firmware is in development.
|
||||
*
|
||||
* @param hardwareMajor Hardware major version number.
|
||||
*
|
||||
* @param hardwareMinor Hardware minor version number.
|
||||
*
|
||||
* @param protocolMajor Protocol major version number.
|
||||
*
|
||||
* @param protocolMinor Protocol minor version number.
|
||||
*
|
||||
* @param padding Padding byte, ignore this.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor,
|
||||
bool& firmwareDebug, uint8_t& hardwareMajor,
|
||||
uint8_t& hardwareMinor, uint8_t& protocolMajor,
|
||||
uint8_t& protocolMinor);
|
||||
|
||||
/**
|
||||
* readDeviceStatus() - Reads the current device status.
|
||||
*
|
||||
* Use this command to get detailed information about the device status.
|
||||
* The device status is encoded in flags. Each device status flag
|
||||
* represents a single bit in a 32-bit integer value. If more than one
|
||||
* error is present, the device status register value is the sum of the
|
||||
* corresponding flag values. For details about the available flags,
|
||||
* refer to the device status flags documentation.
|
||||
*
|
||||
* @note The status flags of type \"Error\" are sticky, i.e. they are not
|
||||
* cleared automatically even if the error condition no longer exists. So
|
||||
* they can only be cleared manually with the command 0xD210 \"Read And
|
||||
* Clear Device Status\" or with a device reset. All other flags are not
|
||||
* sticky, i.e. they are cleared automatically if the trigger condition
|
||||
* disappears.
|
||||
*
|
||||
* @param deviceStatus Device status (32 flags as an integer value). For
|
||||
* details, please refer to the device status flags documentation.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readDeviceStatus(uint32_t& deviceStatus);
|
||||
|
||||
/**
|
||||
* readAndClearDeviceStatus() - Reads the current device status (like
|
||||
* command 0xD206 \"Read Device Status\") and afterwards clears all flags.
|
||||
*
|
||||
* @param deviceStatus Device status (32 flags as an integer value)
|
||||
* **before** clearing it. For details, please refer to the device status
|
||||
* flags documentation.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t readAndClearDeviceStatus(uint32_t& deviceStatus);
|
||||
|
||||
/**
|
||||
* deviceReset() - Executes a reset on the device. This has the same effect
|
||||
* as a power cycle.
|
||||
*
|
||||
* @return 0 on success, an error code otherwise
|
||||
*/
|
||||
uint16_t deviceReset(void);
|
||||
|
||||
private:
|
||||
TwoWire* _i2cBus = nullptr;
|
||||
};
|
||||
|
||||
#endif /* SENSIRIONI2CSEN5X_H */
|
|
@ -98,6 +98,7 @@
|
|||
#define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
|
||||
#define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code)
|
||||
#define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code)
|
||||
#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code)
|
||||
//#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code)
|
||||
#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code)
|
||||
//#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code)
|
||||
|
|
|
@ -369,6 +369,7 @@
|
|||
//#define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
|
||||
//#define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code)
|
||||
//#define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code)
|
||||
//#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code)
|
||||
//#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code)
|
||||
//#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code)
|
||||
//#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code)
|
||||
|
@ -586,6 +587,7 @@
|
|||
#define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code)
|
||||
#define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code)
|
||||
#define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code)
|
||||
#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code)
|
||||
//#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code)
|
||||
#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code)
|
||||
//#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code)
|
||||
|
|
|
@ -619,6 +619,7 @@
|
|||
#define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address
|
||||
// #define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code)
|
||||
// #define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code)
|
||||
// #define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code)
|
||||
// #define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code)
|
||||
// #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code)
|
||||
// #define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code)
|
||||
|
|
|
@ -870,8 +870,9 @@ void ResponseAppendFeatures(void)
|
|||
#ifdef USE_TUYAMCUBR
|
||||
feature9 |= 0x00004000; // xdrv_65_tuyamcubr.ino
|
||||
#endif
|
||||
|
||||
// feature9 |= 0x00008000;
|
||||
#if defined(USE_I2C) && defined(USE_SEN5X)
|
||||
feature9 |= 0x00008000; // xsns_103_sen5x.ino
|
||||
#endif
|
||||
|
||||
// feature9 |= 0x00010000;
|
||||
// feature9 |= 0x00020000;
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
xsns_103_sen5x.ino - SEN5X gas and air quality sensor support for Tasmota
|
||||
|
||||
Copyright (C) 2022 Tyeth Gundry
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_SEN5X
|
||||
/*********************************************************************************************\
|
||||
* SEN5X - Gas (VOC - Volatile Organic Compounds / NOx - Nitrous Oxides) and Particulates (PPM)
|
||||
*
|
||||
* Source: Sensirion SEN5X Driver + Example, and Tasmota Driver 98 by Jean-Pierre Deschamps
|
||||
* Adaption for TASMOTA: Tyeth Gundry
|
||||
*
|
||||
* I2C Address: 0x59
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XSNS_103 103
|
||||
#define XI2C_76 76 // See I2CDEVICES.md
|
||||
|
||||
#define SEN5X_ADDRESS 0x69
|
||||
|
||||
#include <SensirionI2CSen5x.h>
|
||||
#include <Wire.h>
|
||||
SensirionI2CSen5x *sen5x = nullptr;
|
||||
|
||||
struct SEN5XDATA_s {
|
||||
bool sen5x_ready;
|
||||
float abshum;
|
||||
float massConcentrationPm1p0;
|
||||
float massConcentrationPm2p5;
|
||||
float massConcentrationPm4p0;
|
||||
float massConcentrationPm10p0;
|
||||
float ambientHumidity;
|
||||
float ambientTemperature;
|
||||
float vocIndex;
|
||||
float noxIndex;
|
||||
} *SEN5XDATA = nullptr;
|
||||
/********************************************************************************************/
|
||||
|
||||
void sen5x_Init(void)
|
||||
{
|
||||
if(!TasmotaGlobal.i2c_enabled){
|
||||
DEBUG_SENSOR_LOG(PSTR("I2C Not enabled, so not loading SEN5X driver."));
|
||||
return;
|
||||
}
|
||||
int usingI2cBus = 0;
|
||||
#ifdef ESP32
|
||||
if (!I2cSetDevice(SEN5X_ADDRESS, 0))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0"));
|
||||
if (TasmotaGlobal.i2c_enabled_2 ){
|
||||
|
||||
if(!I2cSetDevice(SEN5X_ADDRESS, 1)){
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 1"));
|
||||
return;
|
||||
}
|
||||
usingI2cBus = 1;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!I2cSetDevice(SEN5X_ADDRESS))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (SEN5XDATA == nullptr)
|
||||
SEN5XDATA = (SEN5XDATA_s *)calloc(1, sizeof(struct SEN5XDATA_s));
|
||||
SEN5XDATA->sen5x_ready = false;
|
||||
if(sen5x == nullptr) sen5x = new SensirionI2CSen5x();
|
||||
if(usingI2cBus==1){
|
||||
#ifdef ESP32
|
||||
sen5x->begin(Wire1);
|
||||
#else
|
||||
sen5x->begin(Wire);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
sen5x->begin(Wire);
|
||||
}
|
||||
int error_stop = sen5x->deviceReset();
|
||||
if (error_stop != 0)
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to reset device (I2C Bus %d)"), usingI2cBus);
|
||||
return;
|
||||
}
|
||||
// Wait 1 second for sensors to start recording + 100ms for reset command
|
||||
delay(1100);
|
||||
int error_start = sen5x->startMeasurement();
|
||||
if (error_start != 0)
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to start measurement (I2C Bus %d)"), usingI2cBus);
|
||||
return;
|
||||
}
|
||||
SEN5XDATA->sen5x_ready = true;
|
||||
I2cSetActiveFound(SEN5X_ADDRESS, "SEN5X", usingI2cBus);
|
||||
DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X found, i2c bus %d"), usingI2cBus);
|
||||
}
|
||||
|
||||
// #define POW_FUNC pow
|
||||
#define POW_FUNC FastPrecisePow
|
||||
|
||||
float sen5x_AbsoluteHumidity(float temperature, float humidity)
|
||||
{
|
||||
// taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
|
||||
// precision is about 0.1°C in range -30 to 35°C
|
||||
// August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
|
||||
// Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
|
||||
// reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html
|
||||
float temp = NAN;
|
||||
const float mw = 18.01534f; // molar mass of water g/mol
|
||||
const float r = 8.31447215f; // Universal gas constant J/mol/K
|
||||
|
||||
if (isnan(temperature) || isnan(humidity))
|
||||
{
|
||||
return NAN;
|
||||
}
|
||||
|
||||
temp = POW_FUNC(2.718281828f, (17.67f * temperature) / (temperature + 243.5f));
|
||||
|
||||
// return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version
|
||||
return (6.112f * temp * humidity * mw) / ((273.15f + temperature) * r); // long version
|
||||
}
|
||||
|
||||
#define SAVE_PERIOD 30
|
||||
|
||||
void SEN5XUpdate(void) // Perform every second to ensure proper operation of the baseline compensation algorithm
|
||||
{
|
||||
uint16_t error;
|
||||
char errorMessage[256];
|
||||
DEBUG_SENSOR_LOG(PSTR("Running readMeasuredValues for SEN5X..."));
|
||||
|
||||
error = sen5x->readMeasuredValues(
|
||||
SEN5XDATA->massConcentrationPm1p0, SEN5XDATA->massConcentrationPm2p5, SEN5XDATA->massConcentrationPm4p0,
|
||||
SEN5XDATA->massConcentrationPm10p0, SEN5XDATA->ambientHumidity, SEN5XDATA->ambientTemperature, SEN5XDATA->vocIndex,
|
||||
SEN5XDATA->noxIndex);
|
||||
|
||||
if (error)
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to retrieve SEN5X readings."));
|
||||
#ifdef DEBUG_TASMOTA_SENSOR
|
||||
DEBUG_SENSOR_LOG(PSTR("Error trying to execute readMeasuredValues(): \n"));
|
||||
errorToString(error, errorMessage, 256);
|
||||
DEBUG_SENSOR_LOG(errorMessage);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_TASMOTA_SENSOR
|
||||
DEBUG_SENSOR_LOG(PSTR("SEN5x readings:-"));
|
||||
DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm1p0: %f\n"), SEN5XDATA->massConcentrationPm1p0);
|
||||
DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm2p5: %f\n"), SEN5XDATA->massConcentrationPm2p5);
|
||||
DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm4p0: %f\n"), SEN5XDATA->massConcentrationPm4p0);
|
||||
DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm10p0: %f\n"), SEN5XDATA->massConcentrationPm10p0);
|
||||
if (isnan(SEN5XDATA->ambientHumidity))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: n/a\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: %f\n"), SEN5XDATA->ambientHumidity);
|
||||
}
|
||||
|
||||
if (isnan(SEN5XDATA->ambientTemperature))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: n/a\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: %f\n"), SEN5XDATA->ambientTemperature);
|
||||
}
|
||||
|
||||
if (isnan(SEN5XDATA->vocIndex))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("VocIndex: n/a\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("VocIndex: %f\n"), SEN5XDATA->vocIndex);
|
||||
}
|
||||
|
||||
if (isnan(SEN5XDATA->noxIndex))
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("NoxIndex: n/a\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SENSOR_LOG(PSTR("NoxIndex: %f\n"), SEN5XDATA->noxIndex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (!isnan(SEN5XDATA->ambientTemperature) && SEN5XDATA->ambientHumidity > 0) {
|
||||
SEN5XDATA->abshum = sen5x_AbsoluteHumidity(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity);
|
||||
DEBUG_SENSOR_LOG(PSTR("AbsoluteHumidity: %f\n"), SEN5XDATA->abshum);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_SNS_SEN5X_UNITS[] PROGMEM = "{s}SEN5X %s{m}%.*f %s{e}";
|
||||
const char HTTP_SNS_SEN5X_UNITLESS[] PROGMEM = "{s}SEN5X %s{m}%.*f{e}";
|
||||
// {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
const char HTTP_SNS_AHUMSEN5X[] PROGMEM = "{s}SEN5X Abs Humidity{m}%s g/m³{e}";
|
||||
#endif
|
||||
|
||||
#define D_JSON_AHUM "aHumidity"
|
||||
|
||||
void SEN5XShow(bool json)
|
||||
{
|
||||
if (SEN5XDATA->sen5x_ready)
|
||||
{
|
||||
char sen5x_abs_hum[33];
|
||||
bool ahum_available = !isnan(SEN5XDATA->ambientTemperature) && (SEN5XDATA->ambientHumidity > 0);
|
||||
if (ahum_available)
|
||||
{
|
||||
// has humidity + temperature
|
||||
dtostrfd(SEN5XDATA->abshum, 4, sen5x_abs_hum);
|
||||
}
|
||||
if (json)
|
||||
{
|
||||
ResponseAppend_P(PSTR(",\"SEN5X\":{"));
|
||||
ResponseAppend_P(PSTR("\"PM1\":%.1f,"), SEN5XDATA->massConcentrationPm1p0);
|
||||
ResponseAppend_P(PSTR("\"PM2.5\":%.1f,"), SEN5XDATA->massConcentrationPm2p5);
|
||||
ResponseAppend_P(PSTR("\"PM4\":%.1f,"), SEN5XDATA->massConcentrationPm4p0);
|
||||
ResponseAppend_P(PSTR("\"PM10\":%.1f,"), SEN5XDATA->massConcentrationPm10p0);
|
||||
if (!isnan(SEN5XDATA->noxIndex))
|
||||
ResponseAppend_P(PSTR("\"NOx\":%.0f,"), SEN5XDATA->noxIndex);
|
||||
if (!isnan(SEN5XDATA->vocIndex))
|
||||
ResponseAppend_P(PSTR("\"VOC\":%.0f,"), SEN5XDATA->vocIndex);
|
||||
if (!isnan(SEN5XDATA->ambientTemperature))
|
||||
ResponseAppendTHD(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity);
|
||||
if (ahum_available)
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"), sen5x_abs_hum);
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM1", 1, SEN5XDATA->massConcentrationPm1p0, "μg/m³");
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM2.5", 1, SEN5XDATA->massConcentrationPm2p5, "μg/m³");
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM4", 1, SEN5XDATA->massConcentrationPm4p0, "μg/m³");
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM10", 1, SEN5XDATA->massConcentrationPm10p0, "μg/m³");
|
||||
if (!isnan(SEN5XDATA->noxIndex))
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "NOx", 0, SEN5XDATA->noxIndex);
|
||||
if (!isnan(SEN5XDATA->vocIndex))
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "VOC", 0, SEN5XDATA->vocIndex);
|
||||
if (!isnan(SEN5XDATA->ambientTemperature))
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Temperature", 2, SEN5XDATA->ambientTemperature, "°C");
|
||||
if (!isnan(SEN5XDATA->ambientHumidity))
|
||||
WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Humidity", 2, SEN5XDATA->ambientHumidity, "%RH");
|
||||
if (ahum_available)
|
||||
WSContentSend_PD(HTTP_SNS_AHUMSEN5X, sen5x_abs_hum);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xsns103(uint32_t function)
|
||||
{
|
||||
if (!I2cEnabled(XI2C_76))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (FUNC_INIT == function)
|
||||
{
|
||||
sen5x_Init();
|
||||
}
|
||||
else if (SEN5XDATA != nullptr)
|
||||
{
|
||||
switch (function)
|
||||
{
|
||||
case FUNC_EVERY_SECOND:
|
||||
SEN5XUpdate();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
SEN5XShow(1);
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
SEN5XShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_SEN5X
|
||||
#endif // USE_I2C
|
|
@ -290,7 +290,7 @@ a_features = [[
|
|||
"USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L",
|
||||
"USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ",
|
||||
"USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007",
|
||||
"USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","",
|
||||
"USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X",
|
||||
"","","","",
|
||||
"","","","",
|
||||
"","","","",
|
||||
|
|
Loading…
Reference in New Issue