diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..047f2ad --- /dev/null +++ b/.clang-format @@ -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'] +... diff --git a/.github/workflows/arduino_quality_check.yml b/.github/workflows/arduino_quality_check.yml new file mode 100644 index 0000000..a2dc17c --- /dev/null +++ b/.github/workflows/arduino_quality_check.yml @@ -0,0 +1,24 @@ +name: Quality check + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + arduino-quality: + uses: sensirion/.github/.github/workflows/driver.arduino.check.yml@main + with: + expect-arduino-examples: true + lint-lib-manager-check: update + + todo-check: + if: github.event_name == 'push' && github.ref != 'refs/head/main' + uses: sensirion/.github/.github/workflows/driver.common.todo_check.yml@main + + code-generation-check: + if: github.event_name == 'push' && github.ref != 'refs/head/main' + uses: sensirion/.github/.github/workflows/driver.generated.metadata_check.yml@main diff --git a/.github/workflows/github_release.yml b/.github/workflows/github_release.yml new file mode 100644 index 0000000..d98ee0e --- /dev/null +++ b/.github/workflows/github_release.yml @@ -0,0 +1,10 @@ +name: Github Release + +on: + push: + tags: + - '*' + +jobs: + github-release: + uses: sensirion/.github/.github/workflows/driver.common.github_release.yml@main diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..1610d88 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,103 @@ +stages: + - validate + - test + +variables: + YQ_URL: https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_amd64 + +compile_test: + stage: test + image: + name: registry.gitlab.sensirion.lokal/sensirion/docker/docker-arduino:0.4.0 + tags: [docker, linux] + before_script: + - rm -rf ../sensirion-core-arduino-library + script: + - git clone --depth 1 --branch 0.7.0 https://github.com/Sensirion/arduino-core.git ../sensirion-core-arduino-library + - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:samd:mkrzero ./examples/exampleUsage/exampleUsage.ino + - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:mega ./examples/exampleUsage/exampleUsage.ino + - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:nano ./examples/exampleUsage/exampleUsage.ino + - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:uno ./examples/exampleUsage/exampleUsage.ino + - arduino-cli compile --libraries=".." --warnings all --fqbn esp32:esp32:esp32 ./examples/exampleUsage/exampleUsage.ino + - arduino-cli compile --libraries=".." --warnings all --fqbn esp8266:esp8266:generic ./examples/exampleUsage/exampleUsage.ino + +arduino_lint: + stage: validate + image: + name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0 + tags: [linux, docker] + script: + - mkdir ~/arlint + - PATH=~/arlint:$PATH + - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/install.sh | BINDIR=~/arlint sh + - arduino-lint --library-manager false + +syntax_check: + stage: validate + image: + name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0 + tags: [linux, docker] + script: + - find . -type f -iregex ".*\.\(c\|h\|cpp\|ino\)" -exec clang-format-6.0 -i -style=file {} \; && git diff --exit-code + + +cppcheck: + stage: validate + image: + name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0 + tags: [linux, docker] + script: + - cppcheck --std=c++11 --language=c++ --error-exitcode=1 --enable=warning,style,performance,portability --suppress=unreadVariable --suppress=unusedStructMember src/* + +TODO_check: + stage: validate + image: + name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0 + tags: [linux, docker] + script: + - '! grep -rnw --exclude=.gitlab-ci.yml --exclude-dir=.git . -e "TODO"' + +metadata_check: + stage: validate + image: + name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0 + tags: [linux, docker] + before_script: + - apt-get -qq update && apt-get -qq install -y wget + - if ! [ -d downloads/ ]; then mkdir downloads; fi + - if ! [ -e downloads/yq ]; then wget --no-verbose $YQ_URL -O downloads/yq; fi + - cp downloads/yq /usr/local/bin/yq && chmod +x /usr/local/bin/yq + script: + # check if metadata.yml exists + - > + if ! [ -f "metadata.yml" ]; then + echo "metadata.yml file not found" + exit 1 + fi + # check that dg_status is 'released' + - export DG_STATUS=$(yq ".dg_status.[]" ./metadata.yml) + - > + if [ $DG_STATUS != "released" ]; then + echo "dg_status in metadata.yml has to be 'released', not '$DG_STATUS'" + exit 1 + fi + # check that last_generated is not older than timestamp of last non-merge commit (+ 3 minutes) + - export IS_MANUALLY_MODIFIED=$(yq ".is_manually_modified" ./metadata.yml) + - > + if [ $IS_MANUALLY_MODIFIED = false ]; then + export LAST_GENERATED_TS=$(yq ".last_generated" ./metadata.yml) + export LAST_GENERATED_TS_EPOCH=$(date -d "$LAST_GENERATED_TS" +%s) + export LAST_NON_MERGE_COMMIT_TS=$(git log --format=%ad --date=iso-strict --no-merges -1) + export COMMIT_TS_EPOCH=$(date -d "$LAST_NON_MERGE_COMMIT_TS" +%s) + if [ $(($LAST_GENERATED_TS_EPOCH + 180)) -lt $COMMIT_TS_EPOCH ]; then + echo "'last_generated' timestamp in metadata.yml is older than commit timestamp ($LAST_GENERATED_TS vs $LAST_NON_MERGE_COMMIT_TS)" + exit 1 + fi + fi + # check that 'is_manually_modified' is set to true if commit is not from driver generator + - export LAST_NON_MERGE_COMMIT_AUTHOR=$(git log --format=%an --no-merges -1) + - > + if ! [ "$LAST_NON_MERGE_COMMIT_AUTHOR" = "Driver Generator 2" ] && [ "$IS_MANUALLY_MODIFIED" = false ]; then + echo "Last commit is not from Driver Generator. Please update 'is_manually_modified' in metadata.yml" + exit 1 + fi \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..792adcb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# CHANGELOG + +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.1.0] - 2024-10-31 + +### Added + +- Add product picture +- Add interfaces to start, stop and read measurements. +- Add interfaces to read product name, serial number and version + +[Unreleased]: https://github.com/Sensirion/arduino-i2c-sen66/compare/0.1.0...HEAD +[0.1.0]: https://github.com/Sensirion/arduino-i2c-sen66/releases/tag/0.1.0 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1daaf92 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2024, 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9b87187 --- /dev/null +++ b/README.md @@ -0,0 +1,198 @@ +# Sensirion I²C SEN66 Arduino Library + +This is the Sensirion SEN66 library for Arduino allowing you to +communicate with a SEN66 sensor over I²C. + + + +Click [here](https://sensirion.com/sen6x-air-quality-sensor-platform) to learn more about the Sensirion SEN66 sensor. + + +unknown + + +The default I²C address of [SEN66](https://www.sensirion.com/products/catalog/SEN6x) is **0x6B**. + + + +## Installation of the library + +This library can be installed using the Arduino Library manager: +Start the [Arduino IDE](http://www.arduino.cc/en/main/software) and open +the Library Manager via + +`Sketch` ➔ `Include Library` ➔ `Manage Libraries...` + +Search for the `Sensirion I2C SEN66` library in the `Filter +your search...` field and install it by clicking the `install` button. + +If you cannot find it in the library manager, 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 library +manager or `Add .ZIP Library` + +#### Dependencies +* [Sensirion Core](https://github.com/Sensirion/arduino-core) + +## Sensor wiring + +Use the following pin description to connect your SEN66 to the standard I²C bus of your Arduino board: + + + +| *Pin* | *Cable Color* | *Name* | *Description* | *Comments* | +|-------|---------------|:------:|----------------|------------| +| 1 | red | VDD | Supply Voltage | 3.3V ±10% +| 2 | black | GND | Ground | +| 3 | green | SDA | I2C: Serial data input / output | TTL 5V compatible +| 4 | yellow | SCL | I2C: Serial clock input | TTL 5V compatible +| 5 | | NC | Do not connect | +| 6 | | NC | Do not connect | + + + + +The recommended voltage is 3.3V. + +### Board specific wiring +You will find pinout schematics for recommended board models below: + + + +
Arduino Uno +

+ +| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* | +| :---: | --- | --- | --- | +| VDD | 1 | red | 3.3V | +| GND | 2 | black | GND | +| SDA | 3 | green | D18/SDA | +| SCL | 4 | yellow | D19/SCL | + + + + +

+
+ + + + +
Arduino Nano +

+ +| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* | +| :---: | --- | --- | --- | +| VDD | 1 | red | 3.3V | +| GND | 2 | black | GND | +| SDA | 3 | green | A4 | +| SCL | 4 | yellow | A5 | + + + + +

+
+ + + + +
Arduino Micro +

+ +| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* | +| :---: | --- | --- | --- | +| VDD | 1 | red | 3.3V | +| GND | 2 | black | GND | +| SDA | 3 | green | D2/SDA | +| SCL | 4 | yellow | ~D3/SCL | + + + + +

+
+ + + + +
Arduino Mega 2560 +

+ +| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* | +| :---: | --- | --- | --- | +| VDD | 1 | red | 3.3V | +| GND | 2 | black | GND | +| SDA | 3 | green | D20/SDA | +| SCL | 4 | yellow | D21/SCL | + + + + +

+
+ + + + +
ESP32 DevKitC +

+ +| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* | +| :---: | --- | --- | --- | +| VDD | 1 | red | 3V3 | +| GND | 2 | black | GND | +| SDA | 3 | green | GPIO 21 | +| SCL | 4 | yellow | GPIO 22 | + + + + +

+
+ + + +## Quick Start + +1. Install the libraries and dependencies according to [Installation of the library](#installation-of-the-library) + +2. Connect the SEN66 sensor to your Arduino as explained in [Sensor wiring](#sensor-wiring) + +3. Open the `exampleUsage` sample project within the Arduino IDE: + + `File` ➔ `Examples` ➔ `Sensirion I2C SEN66` ➔ `exampleUsage` + + + +5. 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 used tool has to be set to `115200 baud`. + +## Contributing + +**Contributions are welcome!** + +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). \ No newline at end of file diff --git a/examples/exampleUsage/exampleUsage.ino b/examples/exampleUsage/exampleUsage.ino new file mode 100644 index 0000000..f5949b9 --- /dev/null +++ b/examples/exampleUsage/exampleUsage.ino @@ -0,0 +1,148 @@ +/* + * THIS FILE IS AUTOMATICALLY GENERATED + * + * Generator: sensirion-driver-generator 1.0.1 + * Product: sen66 + * Model-Version: 1.2.0 + */ +/* + * Copyright (c) 2024, 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 +#include +#include + +// macro definitions +// make sure that we use the proper definition of NO_ERROR +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#define NO_ERROR 0 + +SensirionI2cSen66 sensor; + +static char errorMessage[64]; +static int16_t error; + +void print_byte_array(uint8_t* array, uint16_t len) { + uint16_t i = 0; + Serial.print("0x"); + for (; i < len; i++) { + Serial.print(array[i], HEX); + } +} + +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(100); + } + Wire.begin(); + sensor.begin(Wire, SEN66_I2C_ADDR_6B); + + error = sensor.deviceReset(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute deviceReset(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + delay(1200); + uint8_t serialNumber[32] = {0}; + error = sensor.getSerialNumber(serialNumber, 32); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getSerialNumber(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + Serial.print("serialNumber: "); + print_byte_array(serialNumber, 32); + Serial.println(); + error = sensor.startContinuousMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute startContinuousMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } +} + +void loop() { + + float massConcentrationPm1p0 = 0.0; + float massConcentrationPm2p5 = 0.0; + float massConcentrationPm4p0 = 0.0; + float massConcentrationPm10p0 = 0.0; + float humidity = 0.0; + float temperature = 0.0; + float vocIndex = 0.0; + float noxIndex = 0.0; + float co2 = 0.0; + delay(1000); + error = sensor.readMeasuredValues( + massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0, + massConcentrationPm10p0, humidity, temperature, vocIndex, noxIndex, + co2); + if (error != NO_ERROR) { + Serial.print("Error trying to execute readMeasuredValues(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + 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("humidity: "); + Serial.print(humidity); + Serial.print("\t"); + Serial.print("temperature: "); + Serial.print(temperature); + Serial.print("\t"); + Serial.print("vocIndex: "); + Serial.print(vocIndex); + Serial.print("\t"); + Serial.print("noxIndex: "); + Serial.print(noxIndex); + Serial.print("\t"); + Serial.print("co2: "); + Serial.print(co2); + Serial.println(); +} diff --git a/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png b/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png new file mode 100644 index 0000000..942173d Binary files /dev/null and b/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png differ diff --git a/images/Arduino-Micro-i2c-pinout-3.3V.png b/images/Arduino-Micro-i2c-pinout-3.3V.png new file mode 100644 index 0000000..ca9ba6c Binary files /dev/null and b/images/Arduino-Micro-i2c-pinout-3.3V.png differ diff --git a/images/Arduino-Nano-i2c-pinout-3.3V.png b/images/Arduino-Nano-i2c-pinout-3.3V.png new file mode 100644 index 0000000..55fd2ff Binary files /dev/null and b/images/Arduino-Nano-i2c-pinout-3.3V.png differ diff --git a/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png b/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png new file mode 100644 index 0000000..a6daad7 Binary files /dev/null and b/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png differ diff --git a/images/esp32-devkitc-i2c-pinout-3.3V.png b/images/esp32-devkitc-i2c-pinout-3.3V.png new file mode 100644 index 0000000..319b021 Binary files /dev/null and b/images/esp32-devkitc-i2c-pinout-3.3V.png differ diff --git a/images/sen6x-pinout.png b/images/sen6x-pinout.png new file mode 100644 index 0000000..42b5f0a Binary files /dev/null and b/images/sen6x-pinout.png differ diff --git a/images/sen6x.png b/images/sen6x.png new file mode 100644 index 0000000..b97bde3 Binary files /dev/null and b/images/sen6x.png differ diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..9636ea9 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,43 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SensirionI2cSen66 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +readMeasuredValues KEYWORD2 +deviceReset KEYWORD2 +startContinuousMeasurement KEYWORD2 +stopMeasurement KEYWORD2 +getDataReady KEYWORD2 +readMeasuredValuesAsIntegers KEYWORD2 +performForcedCo2Recalibration KEYWORD2 +getProductName KEYWORD2 +getSerialNumber KEYWORD2 +getVersion KEYWORD2 +signalMassConcentrationPm1p0 KEYWORD2 +signalMassConcentrationPm2p5 KEYWORD2 +signalMassConcentrationPm4p0 KEYWORD2 +signalMassConcentrationPm10p0 KEYWORD2 +signalTemperature KEYWORD2 +signalHumidity KEYWORD2 +signalVocIndex KEYWORD2 +signalNoxIndex KEYWORD2 +signalCo2 KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +sensor KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..b609c4c --- /dev/null +++ b/library.properties @@ -0,0 +1,11 @@ +name=Sensirion I2C SEN66 +version=0.1.0 +author=Sensirion +maintainer=Sensirion +sentence=Library for the SEN66 sensor by Sensirion +paragraph=Enables you to use the SEN66 sensor via I2C. +url=https://github.com/Sensirion/arduino-i2c-sen66 +category=Sensors +architectures=* +depends=Sensirion Core +includes=SensirionI2cSen66.h diff --git a/metadata.yml b/metadata.yml new file mode 100644 index 0000000..5a15951 --- /dev/null +++ b/metadata.yml @@ -0,0 +1,7 @@ +# driver generation metadata +generator_version: 1.0.1 +model_version: 1.2.0 +dg_status: released +is_manually_modified: false +first_generated: '2024-10-30 08:14' +last_generated: '2024-10-30 08:14' diff --git a/src/SensirionI2cSen66.cpp b/src/SensirionI2cSen66.cpp new file mode 100644 index 0000000..5575358 --- /dev/null +++ b/src/SensirionI2cSen66.cpp @@ -0,0 +1,351 @@ +/* + * THIS FILE IS AUTOMATICALLY GENERATED + * + * Generator: sensirion-driver-generator 1.0.1 + * Product: sen66 + * Model-Version: 1.2.0 + */ +/* + * Copyright (c) 2024, 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 "SensirionI2cSen66.h" +#include + +// make sure that we use the proper definition of NO_ERROR +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#define NO_ERROR 0 + +static uint8_t communication_buffer[48] = {0}; + +SensirionI2cSen66::SensirionI2cSen66() { +} + +float SensirionI2cSen66::signalMassConcentrationPm1p0( + uint16_t massConcentrationPm1p0Raw) { + float massConcentrationPm1p0 = 0.0; + massConcentrationPm1p0 = massConcentrationPm1p0Raw / 10.0; + return massConcentrationPm1p0; +} + +float SensirionI2cSen66::signalMassConcentrationPm2p5( + uint16_t massConcentrationPm2p5Raw) { + float massConcentrationPm2p5 = 0.0; + massConcentrationPm2p5 = massConcentrationPm2p5Raw / 10.0; + return massConcentrationPm2p5; +} + +float SensirionI2cSen66::signalMassConcentrationPm4p0( + uint16_t massConcentrationPm4p0Raw) { + float massConcentrationPm4p0 = 0.0; + massConcentrationPm4p0 = massConcentrationPm4p0Raw / 10.0; + return massConcentrationPm4p0; +} + +float SensirionI2cSen66::signalMassConcentrationPm10p0( + uint16_t massConcentrationPm10p0Raw) { + float massConcentrationPm10p0 = 0.0; + massConcentrationPm10p0 = massConcentrationPm10p0Raw / 10.0; + return massConcentrationPm10p0; +} + +float SensirionI2cSen66::signalTemperature(int16_t temperatureRaw) { + float temperature = 0.0; + temperature = temperatureRaw / 200.0; + return temperature; +} + +float SensirionI2cSen66::signalHumidity(int16_t humidityRaw) { + float humidity = 0.0; + humidity = humidityRaw / 100.0; + return humidity; +} + +float SensirionI2cSen66::signalVocIndex(int16_t vocIndexRaw) { + float vocIndex = 0.0; + vocIndex = vocIndexRaw / 10.0; + return vocIndex; +} + +float SensirionI2cSen66::signalNoxIndex(int16_t noxIndexRaw) { + float noxIndex = 0.0; + noxIndex = noxIndexRaw / 10.0; + return noxIndex; +} + +float SensirionI2cSen66::signalCo2(uint16_t co2Raw) { + float co2 = 0.0; + co2 = co2Raw / 1.0; + return co2; +} + +int16_t SensirionI2cSen66::readMeasuredValues( + float& massConcentrationPm1p0, float& massConcentrationPm2p5, + float& massConcentrationPm4p0, float& massConcentrationPm10p0, + float& humidity, float& temperature, float& vocIndex, float& noxIndex, + float& co2) { + uint16_t massConcentrationPm1p0Raw = 0; + uint16_t massConcentrationPm2p5Raw = 0; + uint16_t massConcentrationPm4p0Raw = 0; + uint16_t massConcentrationPm10p0Raw = 0; + int16_t humidityRaw = 0; + int16_t temperatureRaw = 0; + int16_t vocIndexRaw = 0; + int16_t noxIndexRaw = 0; + uint16_t co2Raw = 0; + int16_t localError = 0; + localError = readMeasuredValuesAsIntegers( + massConcentrationPm1p0Raw, massConcentrationPm2p5Raw, + massConcentrationPm4p0Raw, massConcentrationPm10p0Raw, humidityRaw, + temperatureRaw, vocIndexRaw, noxIndexRaw, co2Raw); + if (localError != NO_ERROR) { + return localError; + } + massConcentrationPm1p0 = SensirionI2cSen66::signalMassConcentrationPm1p0( + massConcentrationPm1p0Raw); + massConcentrationPm2p5 = SensirionI2cSen66::signalMassConcentrationPm2p5( + massConcentrationPm2p5Raw); + massConcentrationPm4p0 = SensirionI2cSen66::signalMassConcentrationPm4p0( + massConcentrationPm4p0Raw); + massConcentrationPm10p0 = SensirionI2cSen66::signalMassConcentrationPm10p0( + massConcentrationPm10p0Raw); + humidity = SensirionI2cSen66::signalHumidity(humidityRaw); + temperature = SensirionI2cSen66::signalTemperature(temperatureRaw); + vocIndex = SensirionI2cSen66::signalVocIndex(vocIndexRaw); + noxIndex = SensirionI2cSen66::signalNoxIndex(noxIndexRaw); + co2 = SensirionI2cSen66::signalCo2(co2Raw); + return localError; +} + +int16_t SensirionI2cSen66::deviceReset() { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xd304, buffer_ptr, 2); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(1200); + return localError; +} + +int16_t SensirionI2cSen66::startContinuousMeasurement() { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x21, buffer_ptr, 2); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(50); + return localError; +} + +int16_t SensirionI2cSen66::stopMeasurement() { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x104, buffer_ptr, 2); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(160); + return localError; +} + +int16_t SensirionI2cSen66::getDataReady(uint8_t& padding, bool& dataReady) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x202, buffer_ptr, 3); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(20); + SensirionI2CRxFrame rxFrame(buffer_ptr, 3); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 3, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getUInt8(padding); + localError |= rxFrame.getBool(dataReady); + return localError; +} + +int16_t SensirionI2cSen66::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& cO2) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x300, buffer_ptr, 27); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(20); + SensirionI2CRxFrame rxFrame(buffer_ptr, 27); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 27, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getUInt16(massConcentrationPm1p0); + localError |= rxFrame.getUInt16(massConcentrationPm2p5); + localError |= rxFrame.getUInt16(massConcentrationPm4p0); + localError |= rxFrame.getUInt16(massConcentrationPm10p0); + localError |= rxFrame.getInt16(ambientHumidity); + localError |= rxFrame.getInt16(ambientTemperature); + localError |= rxFrame.getInt16(vOCIndex); + localError |= rxFrame.getInt16(nOxIndex); + localError |= rxFrame.getUInt16(cO2); + return localError; +} + +int16_t SensirionI2cSen66::performForcedCo2Recalibration( + uint16_t targetCo2Concentration, uint16_t& correction) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x6707, buffer_ptr, 5); + localError |= txFrame.addUInt16(targetCo2Concentration); + if (localError != NO_ERROR) { + return localError; + } + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(500); + SensirionI2CRxFrame rxFrame(buffer_ptr, 5); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 3, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getUInt16(correction); + return localError; +} + +int16_t SensirionI2cSen66::getProductName(uint8_t productName[], + uint16_t productNameSize) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xd014, buffer_ptr, 48); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(20); + SensirionI2CRxFrame rxFrame(buffer_ptr, 48); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 48, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getBytes((uint8_t*)productName, productNameSize); + return localError; +} + +int16_t SensirionI2cSen66::getSerialNumber(uint8_t serialNumber[], + uint16_t serialNumberSize) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xd033, buffer_ptr, 48); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(20); + SensirionI2CRxFrame rxFrame(buffer_ptr, 48); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 48, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getBytes((uint8_t*)serialNumber, serialNumberSize); + return localError; +} + +int16_t +SensirionI2cSen66::getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor, + bool& firmwareDebug, uint8_t& hardwareMajor, + uint8_t& hardwareMinor, uint8_t& protocolMajor, + uint8_t& protocolMinor, uint8_t& padding) { + int16_t localError = NO_ERROR; + uint8_t* buffer_ptr = communication_buffer; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xd000, buffer_ptr, 12); + localError = + SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + delay(20); + SensirionI2CRxFrame rxFrame(buffer_ptr, 12); + localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 12, + rxFrame, *_i2cBus); + if (localError != NO_ERROR) { + return localError; + } + localError |= rxFrame.getUInt8(firmwareMajor); + localError |= rxFrame.getUInt8(firmwareMinor); + localError |= rxFrame.getBool(firmwareDebug); + localError |= rxFrame.getUInt8(hardwareMajor); + localError |= rxFrame.getUInt8(hardwareMinor); + localError |= rxFrame.getUInt8(protocolMajor); + localError |= rxFrame.getUInt8(protocolMinor); + localError |= rxFrame.getUInt8(padding); + return localError; +} + +void SensirionI2cSen66::begin(TwoWire& i2cBus, uint8_t i2cAddress) { + _i2cBus = &i2cBus; + _i2cAddress = i2cAddress; +} diff --git a/src/SensirionI2cSen66.h b/src/SensirionI2cSen66.h new file mode 100644 index 0000000..c80d850 Binary files /dev/null and b/src/SensirionI2cSen66.h differ