diff --git a/.github/workflows/embedded_quality_check.yml b/.github/workflows/embedded_quality_check.yml
index b229e50..495b778 100644
--- a/.github/workflows/embedded_quality_check.yml
+++ b/.github/workflows/embedded_quality_check.yml
@@ -1,16 +1,10 @@
name: Quality check
on:
- pull_request:
- branches:
- - master
push:
+ pull_request:
branches:
- master
-
jobs:
driver-quality:
uses: sensirion/.github/.github/workflows/driver.c.check.yml@main
- with:
- examples: '["."]'
- run-environment: "ubuntu-20.04"
diff --git a/.gitignore b/.gitignore
index 051cadf..781a364 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
-/scd4x_i2c_example_usage
-.idea
+/example-usage/scd4x_i2c_example_usage
+/tests/scd4x_test_hw_i2c
+/tests/scd4x_test_sw_i2c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 860b34e..cffad92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,32 +1,22 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
+# 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.2.1] - 2021-04-30
-
-### Changed
-
-* Increase timing for single shot from 1350ms to 5000ms
-* Increase timing for self test from 5500ms to 10000ms
-
-
-## [0.2.0] - 2021-03-01
+## [1.0.0] - 2025-1-30
### Added
-- Convenience interfaces taking care of unit conversion to and from ticks.
-
-### Fixed
-- wake-up interface handles missing ACK from sensor on wake up.
+- All commands according to data sheet
+## [0.1.0] - 2021-2-1
-## [0.1.0] - 2021-01-28
+### Added
-Initial release
+- Initial version
+- Check latest 0.x.x version for changelog prior to version 1.0.0
-[0.2.1]: https://github.com/Sensirion/embedded-i2c-scd4x/compare/0.2.0...0.2.1
-[0.2.0]: https://github.com/Sensirion/embedded-i2c-scd4x/compare/0.1.0...0.2.0
-[0.1.0]: https://github.com/Sensirion/embedded-i2c-scd4x/releases/tag/0.1.0
+[Unreleased]: https://github.com/Sensirion/embedded-i2c-scd4x/compare/1.0.0...HEAD
+[1.0.0]: https://github.com/Sensirion/embedded-i2c-scd4x/compare/0.1.0...1.0.0
+[0.1.0]: https://github.com/Sensirion/embedded-i2c-scd4x/releases/tag/0.1.0
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index ff20c41..2062766 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2021, Sensirion AG
+Copyright (c) 2025, Sensirion AG
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 7852ac8..0000000
--- a/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-common_sources = sensirion_config.h sensirion_common.h sensirion_common.c
-i2c_sources = sensirion_i2c_hal.h sensirion_i2c.h sensirion_i2c.c
-scd4x_sources = scd4x_i2c.h scd4x_i2c.c
-
-i2c_implementation ?= sensirion_i2c_hal.c
-
-CFLAGS = -Os -Wall -fstrict-aliasing -Wstrict-aliasing=1 -Wsign-conversion -fPIC -I.
-
-ifdef CI
- CFLAGS += -Werror
-endif
-
-.PHONY: all clean
-
-all: scd4x_i2c_example_usage
-
-scd4x_i2c_example_usage: clean
- $(CC) $(CFLAGS) -o $@ ${scd4x_sources} ${i2c_sources} \
- ${i2c_implementation} ${common_sources} scd4x_i2c_example_usage.c
-
-clean:
- $(RM) scd4x_i2c_example_usage
diff --git a/README.md b/README.md
index 6586695..8a94531 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,61 @@
-# Sensirion Embedded I2C SCD4x Driver
+# Sensirion I2C SCD4X embedded Library
-This is a generic embedded driver for the [Sensirion SCD4x Carbon Dioxide Sensor](https://www.sensirion.com/scd4x/).
-It enables developers to communicate with the SCD4x sensor on different hardware platforms by only adapting the I2C communication related source files.
+This document explains how to set up a sensor of the SCD4X family to run on an embedded device using the I²C interface.
-[
](https://sensirion.com/my-scd-ek)
+
-# Getting started
+Click [here](https://sensirion.com/products/catalog/SEK-SCD41) to learn more about the Sensirion SCD4X sensor family.
-## Implement the I2C Interface
-So we need to adjust two files according to your platform.
+Not all sensors of this driver family support all measurements.
+In case a measurement is not supported by all sensors, the products that
+support it are listed in the API description.
+
+
+
+## Supported sensor types
+
+| Sensor name | I²C Addresses |
+| ------------- | -------------- |
+|[SCD40](https://sensirion.com/products/catalog/SCD40)| **0x62**|
+|[SCD41](https://sensirion.com/products/catalog/SCD41)| **0x62**|
+
+The following instructions and examples use a *SCD41*.
+
+
+
+## Setup Guide
+
+### Connect the Sensor
+
+Your sensor has 4 pins that need to be connected to your board: SCL, GND, VDD, SDA.
+Use the following description to connect your SCD4X:
+
+
+
+| *Pin* | *Cable Color* | *Name* | *Description* | *Comments* |
+|-------|---------------|:------:|----------------|------------|
+| 1 | yellow | SCL | I2C: Serial clock input |
+| 2 | black | GND | Ground |
+| 3 | red | VDD | Supply Voltage | 2.4V to 5.5V
+| 4 | green | SDA | I2C: Serial data input / output |
+
+
+
+The recommended voltage is 3.3V.
+
+### Configure the code
+
+In order to use the provided code we need to adjust two files according to your platform.
### Edit `sensirion_i2c_hal.c`
-This file contains the implementation of the sensor communication
-(how to send requests to the sensor). Therefore, how this is done depends on your
-hardware platform. Therefore we can only provide function stubs in which you
-can implement the logic yourself.
-There are sample implementations available for some platforms: [`sample-implementations`](sample-implementations).
-If you are using a Linux based platform like Raspberry Pi
-you can just replace the unimplemented HAL template with the provided
+This file contains the implementation of the sensor communication, which
+depends on your hardware platform. We provide function stubs for your
+hardware's own implementation.
+Sample implementations are available for some platforms:
+[`sample-implementations`](sample-implementations). For Linux based platforms
+like Raspberry Pi you can just replace the unimplemented HAL template with the
implementation in `sample-implementations/linux_user_space/`:
```
@@ -28,17 +64,16 @@ cp sample-implementations/linux_user_space/sensirion_i2c_hal.c ./
### Edit `sensirion_config.h`
-If you are on a Linux based platform you can skip this part since
-everything is already correctly setup for you.
+Skip this part for Linux based platforms since everything is already setup for
+this case.
-Otherwise you need to check if the libraries `` and
-`` are provided by your toolchain, compiler or system.
-If you have no idea on how to do that you can skip this
-step for now and come back when you get errors related to these names when
-compiling the driver.
-The features we use out of those libraries are standard integer sizes
-from `` and `NULL` from ``. If they are not available
-you need to specify the following integer types yourself:
+Otherwise you need to check if the libraries `` and `` are
+provided by your toolchain, compiler or system. If you have no idea on how to
+do that you can skip this step for now and come back when you get errors
+related to these names when compiling the driver.
+The features we use from those libraries are type definitions for integer sizes
+from `` and `NULL` from ``. If they are not available you
+need to specify the following integer types yourself:
* `int64_t` = signed 64bit integer
* `uint64_t` = unsigned 64bit integer
@@ -49,26 +84,47 @@ you need to specify the following integer types yourself:
* `int8_t` = signed 8bit integer
* `uint8_t` = unsigned 8bit integer
-In addition to that you will need to specify `NULL`.
-For both we have a detailed template where you just need to fill in
-your system specific values.
+In addition to that you will need to specify `NULL`. For both we have a
+detailed template where you just need to fill in your system specific values.
+
+## Choose the i2c address to use with your product
+
+The provided example is working with a SCD41, I²C address 0x62.
+In order to use the code with another product or I²C address you need to change it in the call scd4x_init(ADDRESS) in
+`scd4x_i2c_example_usage.c`. The list of supported I²C-addresses is found in the header
+`scd4x_i2c.h`.
+
Now we are ready to compile and run the example usage for your sensor.
## Compile and Run
-Take the `.c` and `.h` files directly in this folder pass them to your
-favorite C compiler and run the resulting binary.
-This step may vary, depending on your platform. Here we demonstrate the
-procedure for Linux based platforms:
+Pass the source `.c` and header `.h` files in this folder into your C compiler
+and run the resulting binary. This step may vary, depending on your platform.
+Here we demonstrate the procedure for Linux based platforms:
1. Open up a terminal.
2. Navigate to the directory where this README is located.
-3. Run `make` (this compiles all the code here to one binary).
-4. Run `./scd4x_i2c_example_usage` (This will run your newly compiled binary).
-5. Now you should see the first measurement values appear in your terminal.
- As a next step you can adjust the example usage file or write your own
- main function to use the sensor.
+3. Navigate to the subdirectory example-usage.
+4. Run `make` (this compiles the example code into one executable binary).
+5. Run the compiled executable with `./scd4x_i2c_example_usage`
+6. Now you should see the first measurement values appear in your terminal. As
+ a next step you can adjust the example usage file or write your own main
+ function to use the sensor.
+
+## Compile and Run Tests
+
+The testframekwork used is CppUTest. Pass the source `.cpp`, `.c` and header `.h`
+files from the tests and top level folder into your CPP compiler and run the
+resulting binary. This step may vary, depending on your platform.
+Here we demonstrate the procedure for Linux based platforms:
+
+1. Open up a terminal.
+2. Install CppUTest framework `apt install cpputest`.
+3. Navigate to the directory `tests`.
+4. Run `make` (this compiles the test code into one executable binary).
+5. Run the compiled executable with `./scd4x_test_hw_i2c`.
+6. Now you should see the test output on your console.
# Background
@@ -76,29 +132,53 @@ procedure for Linux based platforms:
### sensirion\_i2c.[ch]
-In these files you can find the implementation of the I2C protocol used by Sensirion
-sensors. The functions in these files are used by the embedded driver to build the
-correct frame out of data to be sent to the sensor or receive a frame of data from
-the sensor and convert it back to data readable by your machine. The functions in
-here calculate and check CRCs, reorder bytes for different byte orders and build the
-correct formatted frame for your sensor.
+In these files you can find the implementation of the I2C protocol used by
+Sensirion sensors. The functions in these files are used by the embedded driver
+to build the correct frame out of data to be sent to the sensor or receive a
+frame of data from the sensor and convert it back to data readable by your
+machine. The functions in here calculate and check CRCs, reorder bytes for
+different byte orders and build the correct formatted frame for your sensor.
### sensirion\_i2c\_hal.[ch]
-In these files you can find the implementation of the hardware abstraction layer used
-by Sensirion's I2C embedded drivers. This part of the code is specific to the underlying
-hardware platform. This is an unimplemented template for the user to implement.
-In the `sample-implementations/` folder we provide implementations for the most common
-platforms.
+These files contain the implementation of the hardware abstraction layer used
+by Sensirion's I2C embedded drivers. This part of the code is specific to the
+underlying hardware platform. This is an unimplemented template for the user to
+implement. In the `sample-implementations/` folder we provide implementations
+for the most common platforms.
### sensirion\_config.h
-In this file we keep all the included libraries for our drivers and global defines.
-Next to `sensirion_i2c_hal.c` *it's the only file you should need to edit to get your
-driver working.*
+In this file we keep all the included libraries for our drivers and global
+defines. Next to `sensirion_i2c_hal.c` *it's the only file you should need to
+edit to get your driver working.*
### sensirion\_common.[ch]
-In these files you can find some helper functions used by Sensirion's embedded drivers.
-It mostly contains byte order conversions for different variable types. These functions
-are also used by the UART embedded drivers therefore they are kept in their own file.
+In these files you can find some helper functions used by Sensirion's embedded
+drivers. It mostly contains byte order conversions for different variable
+types. These functions are also used by the UART embedded drivers therefore
+they are kept in their own file.
+
+## Contributing
+
+**Contributions are welcome!**
+
+This Sensirion library uses
+[`clang-format`](https://releases.llvm.org/download.html) to standardize the
+formatting of all our `.c` 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 *.c *.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/example-usage/Makefile b/example-usage/Makefile
new file mode 100644
index 0000000..37ae2c2
--- /dev/null
+++ b/example-usage/Makefile
@@ -0,0 +1,23 @@
+src_dir = ..
+common_sources = ${src_dir}/sensirion_config.h ${src_dir}/sensirion_common.h ${src_dir}/sensirion_common.c
+i2c_sources = ${src_dir}/sensirion_i2c_hal.h ${src_dir}/sensirion_i2c.h ${src_dir}/sensirion_i2c.c
+driver_sources = ${src_dir}/scd4x_i2c.h ${src_dir}/scd4x_i2c.c
+
+i2c_implementation ?= ${src_dir}/sensirion_i2c_hal.c
+
+CFLAGS = -Os -Wall -fstrict-aliasing -Wstrict-aliasing=1 -Wsign-conversion -fPIC -I${src_dir} -I.
+
+ifdef CI
+ CFLAGS += -Werror
+endif
+
+.PHONY: all clean
+
+all: scd4x_i2c_example_usage
+
+scd4x_i2c_example_usage: clean
+ $(CC) $(CFLAGS) -o $@ ${driver_sources} ${i2c_sources} \
+ ${i2c_implementation} ${common_sources} scd4x_i2c_example_usage.c
+
+clean:
+ $(RM) scd4x_i2c_example_usage
\ No newline at end of file
diff --git a/example-usage/scd4x_i2c_example_usage.c b/example-usage/scd4x_i2c_example_usage.c
new file mode 100644
index 0000000..27f60f8
--- /dev/null
+++ b/example-usage/scd4x_i2c_example_usage.c
@@ -0,0 +1,141 @@
+/*
+ * THIS FILE IS AUTOMATICALLY GENERATED
+ *
+ * Generator: sensirion-driver-generator 1.1.2
+ * Product: scd4x
+ * Model-Version: 2.0
+ */
+/*
+ * Copyright (c) 2025, 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 "scd4x_i2c.h"
+#include "sensirion_common.h"
+#include "sensirion_i2c_hal.h"
+#include // PRIx64
+#include // printf
+
+#define sensirion_hal_sleep_us sensirion_i2c_hal_sleep_usec
+
+void convert_and_print_serial(uint16_t* serial_raw) {
+ uint64_t serial_as_int = 0;
+ sensirion_common_to_integer((uint8_t*)serial_raw, (uint8_t*)&serial_as_int,
+ LONG_INTEGER, 6);
+ printf("0x%" PRIx64, serial_as_int);
+}
+
+int main(void) {
+ int16_t error = NO_ERROR;
+ sensirion_i2c_hal_init();
+ scd4x_init(SCD41_I2C_ADDR_62);
+
+ uint16_t serial_number[3] = {0};
+ sensirion_hal_sleep_us(30000);
+ // Ensure sensor is in clean state
+ error = scd4x_wake_up();
+ if (error != NO_ERROR) {
+ printf("error executing wake_up(): %i\n", error);
+ }
+
+ error = scd4x_stop_periodic_measurement();
+ if (error != NO_ERROR) {
+ printf("error executing stop_periodic_measurement(): %i\n", error);
+ }
+
+ error = scd4x_reinit();
+ if (error != NO_ERROR) {
+ printf("error executing reinit(): %i\n", error);
+ }
+
+ // Read out information about the sensor
+ error = scd4x_get_serial_number(serial_number, 3);
+ if (error != NO_ERROR) {
+ printf("error executing get_serial_number(): %i\n", error);
+ return error;
+ }
+ printf("serial number: ");
+ convert_and_print_serial(serial_number);
+ printf("\n");
+ //
+ // If temperature offset and/or sensor altitude compensation
+ // is required, you should call the respective functions here.
+ // Check out the header file for the function definitions.
+ // Start periodic measurements (5sec interval)
+ error = scd4x_start_periodic_measurement();
+ if (error != NO_ERROR) {
+ printf("error executing start_periodic_measurement(): %i\n", error);
+ return error;
+ }
+ //
+ // If low-power mode is required, switch to the low power
+ // measurement function instead of the standard measurement
+ // function above. Check out the header file for the definition.
+ //
+ bool data_ready = false;
+ uint16_t co2_concentration = 0;
+ uint16_t temperature = 0;
+ uint16_t relative_humidity = 0;
+ uint16_t repetition = 0;
+ for (repetition = 0; repetition < 50; repetition++) {
+ //
+ // Slow down the sampling to 0.2Hz.
+ //
+ sensirion_hal_sleep_us(5000000);
+ //
+ // If ambient pressure compensation during measurement
+ // is required, you should call the respective functions here.
+ // Check out the header file for the function definition.
+ error = scd4x_get_data_ready_status(&data_ready);
+ if (error != NO_ERROR) {
+ printf("error executing get_data_ready_status(): %i\n", error);
+ continue;
+ }
+ while (!data_ready) {
+ sensirion_hal_sleep_us(100000);
+ error = scd4x_get_data_ready_status(&data_ready);
+ if (error != NO_ERROR) {
+ printf("error executing get_data_ready_status(): %i\n", error);
+ continue;
+ }
+ }
+ error = scd4x_read_measurement_raw(&co2_concentration, &temperature,
+ &relative_humidity);
+ if (error != NO_ERROR) {
+ printf("error executing read_measurement_raw(): %i\n", error);
+ continue;
+ }
+ //
+ // Print results in physical units.
+ printf("CO2 concentration [ppm]: %u\n", co2_concentration);
+ printf("Temperature ticks: %u\n", temperature);
+ printf("Humidity ticks: %u\n", relative_humidity);
+ }
+
+ return NO_ERROR;
+}
diff --git a/images/SCD41.png b/images/SCD41.png
new file mode 100644
index 0000000..d6f6c9c
Binary files /dev/null and b/images/SCD41.png differ
diff --git a/images/SCD41_pinout.png b/images/SCD41_pinout.png
new file mode 100644
index 0000000..bc33679
Binary files /dev/null and b/images/SCD41_pinout.png differ
diff --git a/images/SCD4x.png b/images/SCD4x.png
deleted file mode 100644
index b82a898..0000000
Binary files a/images/SCD4x.png and /dev/null differ
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..b53c9f0
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,7 @@
+# driver generation metadata
+generator_version: 1.1.2
+model_version: '2.0'
+dg_status: released
+is_manually_modified: false
+first_generated: '2021-01-15 10:54'
+last_generated: '2025-01-29 12:04'
diff --git a/sample-implementations/Atmel_SAMD2_series/sensirion_i2c_hal.c b/sample-implementations/Atmel_SAMD2_series/sensirion_i2c_hal.c
index 18e8863..30ea666 100644
--- a/sample-implementations/Atmel_SAMD2_series/sensirion_i2c_hal.c
+++ b/sample-implementations/Atmel_SAMD2_series/sensirion_i2c_hal.c
@@ -57,7 +57,7 @@ void sensirion_i2c_hal_init(void) {
void sensirion_i2c_hal_free(void) {
}
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
struct i2c_master_packet packet = {
.address = address,
.data_length = count,
@@ -69,7 +69,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
}
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
struct i2c_master_packet packet = {
.address = address,
.data_length = count,
diff --git a/sample-implementations/GPIO_bit_banging/sensirion_i2c_hal.c b/sample-implementations/GPIO_bit_banging/sensirion_i2c_hal.c
index a946e17..3d2f6d0 100644
--- a/sample-implementations/GPIO_bit_banging/sensirion_i2c_hal.c
+++ b/sample-implementations/GPIO_bit_banging/sensirion_i2c_hal.c
@@ -88,7 +88,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
int8_t ret;
uint8_t send_ack;
uint16_t i;
@@ -123,7 +123,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
int8_t ret;
uint16_t i;
diff --git a/sample-implementations/Nordic_nRF5_series/sensirion_i2c_hal.c b/sample-implementations/Nordic_nRF5_series/sensirion_i2c_hal.c
index c251f0f..e26ba9c 100644
--- a/sample-implementations/Nordic_nRF5_series/sensirion_i2c_hal.c
+++ b/sample-implementations/Nordic_nRF5_series/sensirion_i2c_hal.c
@@ -92,8 +92,8 @@ void sensirion_i2c_hal_free(void) {
* error codes: 3 -> error detected by hardware (internal error)
* 17 -> driver not ready for new transfer (busy)
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
- int8_t err = nrf_drv_twi_rx(&i2c_instance, address, data, (uint8_t)count);
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
+ int8_t err = nrf_drv_twi_rx(&i2c_instance, address, data, count);
return err;
}
@@ -112,9 +112,8 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* 17 -> driver not ready for new transfer (busy)
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
- int8_t err =
- nrf_drv_twi_tx(&i2c_instance, address, data, (uint8_t)count, false);
+ uint8_t count) {
+ int8_t err = nrf_drv_twi_tx(&i2c_instance, address, data, count, false);
return err;
}
diff --git a/sample-implementations/STM32F1_series/sensirion_i2c_hal.c b/sample-implementations/STM32F1_series/sensirion_i2c_hal.c
index 424b2e1..83db176 100644
--- a/sample-implementations/STM32F1_series/sensirion_i2c_hal.c
+++ b/sample-implementations/STM32F1_series/sensirion_i2c_hal.c
@@ -79,7 +79,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
return (int8_t)HAL_I2C_Master_Receive(&hi2c1, (uint16_t)(address << 1),
data, count, 100);
}
@@ -96,7 +96,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
return (int8_t)HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)(address << 1),
(uint8_t*)data, count, 100);
}
diff --git a/sample-implementations/esp32/sensirion_i2c_esp32_config.h b/sample-implementations/esp32/sensirion_i2c_esp32_config.h
new file mode 100644
index 0000000..a7e4d15
--- /dev/null
+++ b/sample-implementations/esp32/sensirion_i2c_esp32_config.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2023, 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_ESP32_CONFIG_H
+#define SENSIRION_I2C_ESP32_CONFIG_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int esp_err_t;
+
+struct esp32_i2c_config {
+ uint32_t freq;
+ uint8_t addr;
+ i2c_port_t port;
+ gpio_num_t sda;
+ gpio_num_t scl;
+ bool sda_pullup;
+ bool scl_pullup;
+};
+
+extern esp_err_t sensirion_i2c_config_esp32(struct esp32_i2c_config* cfg);
+extern esp_err_t sensirion_i2c_esp32_ok(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SENSIRION_I2C_ESP32_CONFIG_H */
diff --git a/sample-implementations/esp32/sensirion_i2c_hal.c b/sample-implementations/esp32/sensirion_i2c_hal.c
new file mode 100644
index 0000000..b6c89dc
--- /dev/null
+++ b/sample-implementations/esp32/sensirion_i2c_hal.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2023, 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 "sensirion_i2c_hal.h"
+#include "sensirion_common.h"
+#include "sensirion_config.h"
+
+#include
+#include
+#include
+#include
+
+#include "sensirion_i2c_esp32_config.h"
+
+static const char* TAG = "sensirion_i2c_hal";
+
+#define SLEEP_MS(x) \
+ vTaskDelay(((x) + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS)
+#define CHECK(x) \
+ do { \
+ esp_err_t __; \
+ if ((__ = x) != ESP_OK) \
+ return __; \
+ } while (0)
+#define CHECK_ARG(VAL) \
+ do { \
+ if (!(VAL)) \
+ return ESP_ERR_INVALID_ARG; \
+ } while (0)
+#define UNUSED_PARAM(x) (void)x
+
+static i2c_dev_t dev = {0};
+static struct esp32_i2c_config i2c_cfg = {0};
+static esp_err_t i2c_ok = ESP_OK;
+
+/*
+ * INSTRUCTIONS
+ * ============
+ *
+ * Implement all functions where they are marked as IMPLEMENT.
+ * Follow the function specification in the comments.
+ */
+
+/**
+ * Select the current i2c bus by index.
+ * All following i2c operations will be directed at that bus.
+ *
+ * THE IMPLEMENTATION IS OPTIONAL ON SINGLE-BUS SETUPS (all sensors on the same
+ * bus)
+ *
+ * @param bus_idx Bus index to select
+ * @returns 0 on success, an error code otherwise
+ */
+int16_t sensirion_i2c_hal_select_bus(uint8_t bus_idx) {
+ /* TODO:IMPLEMENT or leave empty if all sensors are located on one single
+ * bus
+ */
+ return NOT_IMPLEMENTED_ERROR;
+}
+
+esp_err_t sensirion_i2c_config_esp32(struct esp32_i2c_config* cfg) {
+ if (cfg != NULL) {
+ memcpy(&i2c_cfg, cfg, sizeof(*cfg));
+ return ESP_OK;
+ } else {
+ return ESP_FAIL;
+ }
+}
+
+esp_err_t sensirion_i2c_esp32_ok(void) {
+ return i2c_ok;
+}
+
+/**
+ * Initialize all hard- and software components that are needed for the I2C
+ * communication.
+ */
+void sensirion_i2c_hal_init(void) {
+ memset(&dev, 0, sizeof(i2c_dev_t));
+ // dev.addr = addr;
+ dev.port = i2c_cfg.port;
+ dev.cfg.mode = I2C_MODE_MASTER;
+ dev.cfg.sda_io_num = i2c_cfg.sda;
+ dev.cfg.scl_io_num = i2c_cfg.scl;
+ dev.cfg.sda_pullup_en = i2c_cfg.sda_pullup;
+ dev.cfg.scl_pullup_en = i2c_cfg.scl_pullup;
+#if HELPER_TARGET_IS_ESP32
+ dev.cfg.master.clk_speed = i2c_cfg.freq;
+#endif
+
+ esp_err_t err = i2c_dev_create_mutex(&dev);
+ if (err == ESP_OK) {
+ ESP_LOGI(
+ TAG,
+ "Sensirion I2C initialized. Address: 0x%x Port: %d SDA: %d SCL: %d",
+ i2c_cfg.addr, i2c_cfg.port, i2c_cfg.sda, i2c_cfg.scl);
+ } else {
+ ESP_LOGE(TAG,
+ "Error initializing Sensirion I2C! Address: 0x%x Port: %d "
+ "SDA: %d SCL: %d",
+ i2c_cfg.addr, i2c_cfg.port, i2c_cfg.sda, i2c_cfg.scl);
+ }
+
+ i2c_ok = err;
+}
+
+/**
+ * Release all resources initialized by sensirion_i2c_hal_init().
+ */
+void sensirion_i2c_hal_free(void) {
+}
+
+/**
+ * Execute one read transaction on the I2C bus, reading a given number of bytes.
+ * If the device does not acknowledge the read command, an error shall be
+ * returned.
+ *
+ * @param address 7-bit I2C address to read from
+ * @param data pointer to the buffer where the data is to be stored
+ * @param count number of bytes to read from I2C and store in the buffer
+ * @returns 0 on success, error code otherwise
+ */
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+ ESP_LOGI(TAG, "sensirion_i2c_hal_read: len: %d", count);
+ dev.addr = address;
+ I2C_DEV_TAKE_MUTEX(&dev);
+ I2C_DEV_CHECK(&dev, i2c_dev_read(&dev, NULL, 0, data, count));
+ I2C_DEV_GIVE_MUTEX(&dev);
+ ESP_LOGI(TAG, "READ OK");
+ return (int8_t)ESP_OK;
+}
+
+/**
+ * Execute one write transaction on the I2C bus, sending a given number of
+ * bytes. The bytes in the supplied buffer must be sent to the given address. If
+ * the slave device does not acknowledge any of the bytes, an error shall be
+ * returned.
+ *
+ * @param address 7-bit I2C address to write to
+ * @param data pointer to the buffer containing the data to write
+ * @param count number of bytes to read from the buffer and send over I2C
+ * @returns 0 on success, error code otherwise
+ */
+int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
+ uint16_t count) {
+ ESP_LOGI(TAG, "sensirion_i2c_hal_write: len: %d", count);
+ dev.addr = address;
+ I2C_DEV_TAKE_MUTEX(&dev);
+ I2C_DEV_CHECK(&dev, i2c_dev_write(&dev, NULL, 0, data, count));
+ I2C_DEV_GIVE_MUTEX(&dev);
+ ESP_LOGI(TAG, "WRITE OK");
+ return (int8_t)ESP_OK;
+}
+
+/**
+ * Sleep for a given number of microseconds. The function should delay the
+ * execution for at least the given time, but may also sleep longer.
+ *
+ * Despite the unit, a <10 millisecond precision is sufficient.
+ *
+ * @param useconds the sleep time in microseconds
+ */
+void sensirion_i2c_hal_sleep_usec(uint32_t useconds) {
+ ESP_LOGI(TAG, "sensirion_i2c_hal_sleep: %d usec", useconds);
+ SLEEP_MS(useconds / 1000);
+}
diff --git a/sample-implementations/linux_user_space/sensirion_i2c_hal.c b/sample-implementations/linux_user_space/sensirion_i2c_hal.c
index d55ecc8..74a7f57 100644
--- a/sample-implementations/linux_user_space/sensirion_i2c_hal.c
+++ b/sample-implementations/linux_user_space/sensirion_i2c_hal.c
@@ -89,7 +89,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
if (i2c_address != address) {
ioctl(i2c_device, I2C_SLAVE, address);
i2c_address = address;
@@ -113,7 +113,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
if (i2c_address != address) {
ioctl(i2c_device, I2C_SLAVE, address);
i2c_address = address;
diff --git a/sample-implementations/mbed/sensirion_i2c_hal.cpp b/sample-implementations/mbed/sensirion_i2c_hal.cpp
index 9b3b841..ce846a1 100644
--- a/sample-implementations/mbed/sensirion_i2c_hal.cpp
+++ b/sample-implementations/mbed/sensirion_i2c_hal.cpp
@@ -63,7 +63,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
if (i2c_connection.read(address << 1, (char*)data, count) != 0)
return E_MBED_I2C_READ_FAILED;
return 0;
@@ -81,7 +81,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
if (i2c_connection.write(address << 1, (char*)data, count) != 0)
return E_MBED_I2C_WRITE_FAILED;
return 0;
diff --git a/sample-implementations/zephyr_user_space/sensirion_i2c_hal.c b/sample-implementations/zephyr_user_space/sensirion_i2c_hal.c
index fc96443..a0dd0d4 100644
--- a/sample-implementations/zephyr_user_space/sensirion_i2c_hal.c
+++ b/sample-implementations/zephyr_user_space/sensirion_i2c_hal.c
@@ -91,7 +91,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
return i2c_read(i2c_dev, data, count, address);
}
@@ -107,7 +107,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
return i2c_write(i2c_dev, data, count, address);
}
diff --git a/scd4x_i2c.c b/scd4x_i2c.c
index 47b54de..7712af7 100644
--- a/scd4x_i2c.c
+++ b/scd4x_i2c.c
@@ -1,12 +1,12 @@
/*
- * THIS FILE IS AUTOMATICALLY GENERATED AND MUST NOT BE EDITED MANUALLY!
+ * THIS FILE IS AUTOMATICALLY GENERATED
*
- * I2C-Generator: 0.2.0
- * Yaml Version: 0.1.0
- * Template Version: 0.2.1
+ * Generator: sensirion-driver-generator 1.1.2
+ * Product: scd4x
+ * Model-Version: 2.0
*/
/*
- * Copyright (c) 2021, Sensirion AG
+ * Copyright (c) 2025, Sensirion AG
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,414 +41,618 @@
#include "sensirion_i2c.h"
#include "sensirion_i2c_hal.h"
-#define SCD4X_I2C_ADDRESS 98
+#define sensirion_hal_sleep_us sensirion_i2c_hal_sleep_usec
-int16_t scd4x_start_periodic_measurement() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x21B1);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
- }
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
-}
-
-int16_t scd4x_read_measurement_ticks(uint16_t* co2, uint16_t* temperature,
- uint16_t* humidity) {
- int16_t error;
- uint8_t buffer[9];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xEC05);
+#define ROUND(x) ((int32_t)((x) + 0.5))
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
- }
+static uint8_t communication_buffer[9] = {0};
- sensirion_i2c_hal_sleep_usec(1000);
+static uint8_t _i2c_address;
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 6);
- if (error) {
- return error;
- }
- *co2 = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- *temperature = sensirion_common_bytes_to_uint16_t(&buffer[2]);
- *humidity = sensirion_common_bytes_to_uint16_t(&buffer[4]);
- return NO_ERROR;
+void scd4x_init(uint8_t i2c_address) {
+ _i2c_address = i2c_address;
}
-int16_t scd4x_read_measurement(uint16_t* co2, int32_t* temperature_m_deg_c,
- int32_t* humidity_m_percent_rh) {
- int16_t error;
- uint16_t temperature;
- uint16_t humidity;
-
- error = scd4x_read_measurement_ticks(co2, &temperature, &humidity);
- if (error) {
- return error;
- }
- *temperature_m_deg_c = ((21875 * (int32_t)temperature) >> 13) - 45000;
- *humidity_m_percent_rh = ((12500 * (int32_t)humidity) >> 13);
- return NO_ERROR;
+uint16_t scd4x_signal_co2_concentration(uint16_t raw_co2_concentration) {
+ uint16_t co2_concentration = 0;
+ co2_concentration = raw_co2_concentration;
+ return co2_concentration;
}
-int16_t scd4x_stop_periodic_measurement() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3F86);
+uint32_t scd4x_signal_ambient_pressure(uint16_t raw_ambient_pressure) {
+ uint32_t ambient_pressure = 0;
+ ambient_pressure = (uint32_t)raw_ambient_pressure * 100;
+ return ambient_pressure;
+}
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_set_ambient_pressure(uint32_t ambient_pressure) {
+ int16_t local_error = 0;
+ uint16_t raw_ambient_pressure = (uint16_t)ROUND(ambient_pressure / 100.0);
+ local_error = scd4x_set_ambient_pressure_raw(raw_ambient_pressure);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(500000);
- return NO_ERROR;
+ return local_error;
}
-int16_t scd4x_get_temperature_offset_ticks(uint16_t* t_offset) {
- int16_t error;
- uint8_t buffer[3];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2318);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_ambient_pressure(uint32_t* a_ambient_pressure) {
+ uint16_t raw_ambient_pressure = 0;
+ int16_t local_error = 0;
+ local_error = scd4x_get_ambient_pressure_raw(&raw_ambient_pressure);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
+ *a_ambient_pressure = scd4x_signal_ambient_pressure(raw_ambient_pressure);
- sensirion_i2c_hal_sleep_usec(1000);
+ return local_error;
+}
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+int16_t scd4x_get_data_ready_status(bool* arg_0) {
+ uint16_t data_ready_status = 0;
+ int16_t local_error = 0;
+ local_error = scd4x_get_data_ready_status_raw(&data_ready_status);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *t_offset = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- return NO_ERROR;
+ *arg_0 = (data_ready_status & 2047) != 0;
+ ;
+ return local_error;
}
-int16_t scd4x_get_temperature_offset(int32_t* t_offset_m_deg_c) {
- int16_t error;
- uint16_t t_offset;
-
- error = scd4x_get_temperature_offset_ticks(&t_offset);
- if (error) {
- return error;
+int16_t scd4x_get_sensor_variant(scd4x_sensor_variant* a_sensor_variant) {
+ uint16_t raw_sensor_variant = 0;
+ int16_t local_error = 0;
+ local_error = scd4x_get_sensor_variant_raw(&raw_sensor_variant);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *t_offset_m_deg_c = ((21875 * (int32_t)t_offset) >> 13);
- return NO_ERROR;
+ uint16_t variant = (uint16_t)(raw_sensor_variant & 4);
+ if (variant == 0) {
+ *a_sensor_variant = SCD4X_SENSOR_VARIANT_SCD40;
+ ;
+ return local_error;
+ } else if (variant == 1) {
+ *a_sensor_variant = SCD4X_SENSOR_VARIANT_SCD41;
+ ;
+ return local_error;
+ }
+ *a_sensor_variant = SCD4X_SENSOR_VARIANT_UNKNOWN;
+ ;
+ return local_error;
}
-int16_t scd4x_set_temperature_offset_ticks(uint16_t t_offset) {
- int16_t error;
- uint8_t buffer[5];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x241D);
-
- offset = sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset, t_offset);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_start_periodic_measurement() {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x21b1);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
+ return local_error;
}
-int16_t scd4x_set_temperature_offset(int32_t t_offset_m_deg_c) {
- uint16_t t_offset = (uint16_t)((t_offset_m_deg_c * 12271) >> 15);
- return scd4x_set_temperature_offset_ticks(t_offset);
+int16_t scd4x_read_measurement_raw(uint16_t* co2_concentration,
+ uint16_t* temperature,
+ uint16_t* relative_humidity) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0xec05);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 6);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ *co2_concentration = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ *temperature = sensirion_common_bytes_to_uint16_t(&buffer_ptr[2]);
+ *relative_humidity = sensirion_common_bytes_to_uint16_t(&buffer_ptr[4]);
+ return local_error;
}
-int16_t scd4x_get_sensor_altitude(uint16_t* sensor_altitude) {
- int16_t error;
- uint8_t buffer[3];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2322);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_stop_periodic_measurement() {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3f86);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
+ sensirion_i2c_hal_sleep_usec(500 * 1000);
+ return local_error;
+}
- sensirion_i2c_hal_sleep_usec(1000);
+int16_t scd4x_set_temperature_offset_raw(uint16_t offset_temperature) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x241d);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, offset_temperature);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+int16_t scd4x_get_temperature_offset_raw(uint16_t* offset_temperature) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2318);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *sensor_altitude = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ *offset_temperature = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_set_sensor_altitude(uint16_t sensor_altitude) {
- int16_t error;
- uint8_t buffer[5];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2427);
-
- offset = sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset,
- sensor_altitude);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2427);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, sensor_altitude);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
}
-int16_t scd4x_set_ambient_pressure(uint16_t ambient_pressure) {
- int16_t error;
- uint8_t buffer[5];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xE000);
+int16_t scd4x_get_sensor_altitude(uint16_t* sensor_altitude) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2322);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ *sensor_altitude = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
+}
- offset = sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset,
- ambient_pressure);
+int16_t scd4x_set_ambient_pressure_raw(uint16_t ambient_pressure) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0xe000);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, ambient_pressure);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_ambient_pressure_raw(uint16_t* ambient_pressure) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0xe000);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
+ *ambient_pressure = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_perform_forced_recalibration(uint16_t target_co2_concentration,
uint16_t* frc_correction) {
- int16_t error;
- uint8_t buffer[5];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x362F);
-
- offset = sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset,
- target_co2_concentration);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x362f);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, target_co2_concentration);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
-
- sensirion_i2c_hal_sleep_usec(400000);
-
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+ sensirion_i2c_hal_sleep_usec(400 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *frc_correction = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- return NO_ERROR;
+ *frc_correction = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
-int16_t scd4x_get_automatic_self_calibration(uint16_t* asc_enabled) {
- int16_t error;
- uint8_t buffer[3];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2313);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_set_automatic_self_calibration_enabled(uint16_t asc_enabled) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2416);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, asc_enabled);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
- sensirion_i2c_hal_sleep_usec(1000);
-
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+int16_t scd4x_get_automatic_self_calibration_enabled(uint16_t* asc_enabled) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2313);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *asc_enabled = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- return NO_ERROR;
+ *asc_enabled = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
-int16_t scd4x_set_automatic_self_calibration(uint16_t asc_enabled) {
- int16_t error;
- uint8_t buffer[5];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2416);
-
- offset =
- sensirion_i2c_add_uint16_t_to_buffer(&buffer[0], offset, asc_enabled);
+int16_t scd4x_set_automatic_self_calibration_target(uint16_t asc_target) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x243a);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, asc_target);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_automatic_self_calibration_target(uint16_t* asc_target) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x233f);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
+ *asc_target = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_start_low_power_periodic_measurement() {
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x21AC);
-
- return sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x21ac);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ return local_error;
}
-int16_t scd4x_get_data_ready_flag(bool* data_ready_flag) {
- int16_t error;
- uint8_t buffer[3];
- uint16_t offset = 0;
- uint16_t local_data_ready = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0xE4B8);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_data_ready_status_raw(uint16_t* data_ready_status) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0xe4b8);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
-
- sensirion_i2c_hal_sleep_usec(1000);
-
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- local_data_ready = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- *data_ready_flag = (local_data_ready & 0x07FF) != 0;
- return NO_ERROR;
+ *data_ready_status = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_persist_settings() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3615);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3615);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(800000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(800 * 1000);
+ return local_error;
}
-int16_t scd4x_get_serial_number(uint16_t* serial_0, uint16_t* serial_1,
- uint16_t* serial_2) {
- int16_t error;
- uint8_t buffer[9];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3682);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_serial_number(uint16_t* serial_number,
+ uint16_t serial_number_size) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3682);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
-
- sensirion_i2c_hal_sleep_usec(1000);
-
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 6);
- if (error) {
- return error;
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 6);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *serial_0 = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- *serial_1 = sensirion_common_bytes_to_uint16_t(&buffer[2]);
- *serial_2 = sensirion_common_bytes_to_uint16_t(&buffer[4]);
- return NO_ERROR;
+ sensirion_common_copy_bytes(&buffer_ptr[0], (uint8_t*)serial_number,
+ (serial_number_size * 2));
+ return local_error;
}
int16_t scd4x_perform_self_test(uint16_t* sensor_status) {
- int16_t error;
- uint8_t buffer[3];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3639);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3639);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
-
- sensirion_i2c_hal_sleep_usec(10000000);
-
- error = sensirion_i2c_read_data_inplace(SCD4X_I2C_ADDRESS, &buffer[0], 2);
- if (error) {
- return error;
+ sensirion_i2c_hal_sleep_usec(10000 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- *sensor_status = sensirion_common_bytes_to_uint16_t(&buffer[0]);
- return NO_ERROR;
+ *sensor_status = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_perform_factory_reset() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3632);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3632);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(800000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(1200 * 1000);
+ return local_error;
}
int16_t scd4x_reinit() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x3646);
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x3646);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(30 * 1000);
+ return local_error;
+}
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+int16_t scd4x_get_sensor_variant_raw(uint16_t* sensor_variant) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x202f);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(20000);
- return NO_ERROR;
+ *sensor_variant = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
int16_t scd4x_measure_single_shot() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x219D);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x219d);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(5000000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(5000 * 1000);
+ return local_error;
}
int16_t scd4x_measure_single_shot_rht_only() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x2196);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2196);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(50000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(50 * 1000);
+ return local_error;
}
int16_t scd4x_power_down() {
- int16_t error;
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x36E0);
-
- error = sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- if (error) {
- return error;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x36e0);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
}
- sensirion_i2c_hal_sleep_usec(1000);
- return NO_ERROR;
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
}
int16_t scd4x_wake_up() {
- uint8_t buffer[2];
- uint16_t offset = 0;
- offset = sensirion_i2c_add_command_to_buffer(&buffer[0], offset, 0x36F6);
-
- // Sensor does not acknowledge the wake-up call, error is ignored
- (void)sensirion_i2c_write_data(SCD4X_I2C_ADDRESS, &buffer[0], offset);
- sensirion_i2c_hal_sleep_usec(20000);
- return NO_ERROR;
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x36f6);
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ sensirion_i2c_hal_sleep_usec(30 * 1000);
+ return local_error;
+}
+
+int16_t scd4x_set_automatic_self_calibration_initial_period(
+ uint16_t asc_initial_period) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2445);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, asc_initial_period);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
+
+int16_t scd4x_get_automatic_self_calibration_initial_period(
+ uint16_t* asc_initial_period) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x2340);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ *asc_initial_period = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
+}
+
+int16_t scd4x_set_automatic_self_calibration_standard_period(
+ uint16_t asc_standard_period) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x244e);
+ local_offset = sensirion_i2c_add_uint16_t_to_buffer(
+ buffer_ptr, local_offset, asc_standard_period);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ return local_error;
+}
+
+int16_t scd4x_get_automatic_self_calibration_standard_period(
+ uint16_t* asc_standard_period) {
+ int16_t local_error = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ uint16_t local_offset = 0;
+ local_offset =
+ sensirion_i2c_add_command16_to_buffer(buffer_ptr, local_offset, 0x234b);
+ local_error =
+ sensirion_i2c_write_data(_i2c_address, buffer_ptr, local_offset);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ sensirion_i2c_hal_sleep_usec(1 * 1000);
+ local_error = sensirion_i2c_read_data_inplace(_i2c_address, buffer_ptr, 2);
+ if (local_error != NO_ERROR) {
+ return local_error;
+ }
+ *asc_standard_period = sensirion_common_bytes_to_uint16_t(&buffer_ptr[0]);
+ return local_error;
}
diff --git a/scd4x_i2c.h b/scd4x_i2c.h
index b5ee44d..9375b14 100644
--- a/scd4x_i2c.h
+++ b/scd4x_i2c.h
@@ -1,12 +1,12 @@
/*
- * THIS FILE IS AUTOMATICALLY GENERATED AND MUST NOT BE EDITED MANUALLY!
+ * THIS FILE IS AUTOMATICALLY GENERATED
*
- * I2C-Generator: 0.2.0
- * Yaml Version: 0.1.0
- * Template Version: 0.2.1
+ * Generator: sensirion-driver-generator 1.1.2
+ * Product: scd4x
+ * Model-Version: 2.0
*/
/*
- * Copyright (c) 2021, Sensirion AG
+ * Copyright (c) 2025, Sensirion AG
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,335 +44,714 @@ extern "C" {
#endif
#include "sensirion_config.h"
+#define SCD40_I2C_ADDR_62 0x62
+#define SCD41_I2C_ADDR_62 0x62
+
+typedef enum {
+ SCD4X_START_PERIODIC_MEASUREMENT_CMD_ID = 0x21b1,
+ SCD4X_READ_MEASUREMENT_RAW_CMD_ID = 0xec05,
+ SCD4X_STOP_PERIODIC_MEASUREMENT_CMD_ID = 0x3f86,
+ SCD4X_SET_TEMPERATURE_OFFSET_RAW_CMD_ID = 0x241d,
+ SCD4X_GET_TEMPERATURE_OFFSET_RAW_CMD_ID = 0x2318,
+ SCD4X_SET_SENSOR_ALTITUDE_CMD_ID = 0x2427,
+ SCD4X_GET_SENSOR_ALTITUDE_CMD_ID = 0x2322,
+ SCD4X_SET_AMBIENT_PRESSURE_RAW_CMD_ID = 0xe000,
+ SCD4X_GET_AMBIENT_PRESSURE_RAW_CMD_ID = 0xe000,
+ SCD4X_PERFORM_FORCED_RECALIBRATION_CMD_ID = 0x362f,
+ SCD4X_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED_CMD_ID = 0x2416,
+ SCD4X_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED_CMD_ID = 0x2313,
+ SCD4X_SET_AUTOMATIC_SELF_CALIBRATION_TARGET_CMD_ID = 0x243a,
+ SCD4X_GET_AUTOMATIC_SELF_CALIBRATION_TARGET_CMD_ID = 0x233f,
+ SCD4X_START_LOW_POWER_PERIODIC_MEASUREMENT_CMD_ID = 0x21ac,
+ SCD4X_GET_DATA_READY_STATUS_RAW_CMD_ID = 0xe4b8,
+ SCD4X_PERSIST_SETTINGS_CMD_ID = 0x3615,
+ SCD4X_GET_SERIAL_NUMBER_CMD_ID = 0x3682,
+ SCD4X_PERFORM_SELF_TEST_CMD_ID = 0x3639,
+ SCD4X_PERFORM_FACTORY_RESET_CMD_ID = 0x3632,
+ SCD4X_REINIT_CMD_ID = 0x3646,
+ SCD4X_GET_SENSOR_VARIANT_RAW_CMD_ID = 0x202f,
+ SCD4X_MEASURE_SINGLE_SHOT_CMD_ID = 0x219d,
+ SCD4X_MEASURE_SINGLE_SHOT_RHT_ONLY_CMD_ID = 0x2196,
+ SCD4X_POWER_DOWN_CMD_ID = 0x36e0,
+ SCD4X_WAKE_UP_CMD_ID = 0x36f6,
+ SCD4X_SET_AUTOMATIC_SELF_CALIBRATION_INITIAL_PERIOD_CMD_ID = 0x2445,
+ SCD4X_GET_AUTOMATIC_SELF_CALIBRATION_INITIAL_PERIOD_CMD_ID = 0x2340,
+ SCD4X_SET_AUTOMATIC_SELF_CALIBRATION_STANDARD_PERIOD_CMD_ID = 0x244e,
+ SCD4X_GET_AUTOMATIC_SELF_CALIBRATION_STANDARD_PERIOD_CMD_ID = 0x234b,
+} SCD4X_CMD_ID;
+
+typedef enum {
+ SCD4X_SENSOR_VARIANT_UNKNOWN = 0,
+ SCD4X_SENSOR_VARIANT_SCD40 = 1,
+ SCD4X_SENSOR_VARIANT_SCD41 = 2,
+} scd4x_sensor_variant;
/**
- * scd4x_start_periodic_measurement() - start periodic measurement, signal
- * update interval is 5 seconds.
+ * @brief Initialize i2c address of driver
*
- * @note This command is only available in idle mode.
+ * @param[in] i2c_address Used i2c address
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_start_periodic_measurement(void);
+void scd4x_init(uint8_t i2c_address);
/**
- * scd4x_read_measurement_ticks() - read sensor output. The measurement data can
- * only be read out once per signal update interval as the buffer is emptied
- * upon read-out. If no data is available in the buffer, the sensor returns a
- * NACK. To avoid a NACK response the get_data_ready_flag can be issued to
- * check data status. The I2C master can abort the read transfer with a NACK
- * followed by a STOP condition after any data byte if the user is not
- * interested in subsequent data.
+ * @brief scd4x_signal_co2_concentration
*
- * @note This command is only available in measurement mode. The firmware
- * updates the measurement values depending on the measurement mode.
+ * @param[in] raw_co2_concentration
*
- * @param co2 CO₂ concentration in ppm
- *
- * @param temperature Convert value to °C by: -45 °C + 175 °C * value/2^16
+ * @return CO₂ concentration in ppm
+ */
+uint16_t scd4x_signal_co2_concentration(uint16_t raw_co2_concentration);
+
+/**
+ * @brief scd4x_signal_ambient_pressure
*
- * @param humidity Convert value to %RH by: 100%RH * value/2^16
+ * @param[in] raw_ambient_pressure
*
- * @return 0 on success, an error code otherwise
+ * @return Pressure in Pa
*/
-int16_t scd4x_read_measurement_ticks(uint16_t* co2, uint16_t* temperature,
- uint16_t* humidity);
+uint32_t scd4x_signal_ambient_pressure(uint16_t raw_ambient_pressure);
/**
- * scd4x_read_measurement() - read sensor output and convert.
- * See @ref scd4x_read_measurement_ticks() for more details.
+ * @brief Set the ambient pressure around the sensor.
*
- * @note This command is only available in measurement mode. The firmware
- * updates the measurement values depending on the measurement mode.
+ * The set_ambient_pressure command can be sent during periodic measurements to
+ * enable continuous pressure compensation. Note that setting an ambient
+ * pressure overrides any pressure compensation based on a previously set sensor
+ * altitude. Use of this command is highly recommended for applications
+ * experiencing significant ambient pressure changes to ensure sensor accuracy.
+ * Valid input values are between 70000 - 120000 Pa. The default value is 101300
+ * Pa.
*
- * @param co2 CO₂ concentration in ppm
+ * @param[in] ambient_pressure Ambient pressure around the sensor in Pa
*
- * @param temperature_m_deg_c Temperature in milli degrees celsius (°C * 1000)
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_set_ambient_pressure(uint32_t ambient_pressure);
+
+/**
+ * @brief Get the ambient pressure around the sensor.
*
- * @param humidity_m_percent_rh Relative humidity in milli percent RH
- * (%RH * 1000)
+ * @param[out] a_ambient_pressure Pressure in Pa
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_read_measurement(uint16_t* co2, int32_t* temperature_m_deg_c,
- int32_t* humidity_m_percent_rh);
+int16_t scd4x_get_ambient_pressure(uint32_t* a_ambient_pressure);
/**
- * scd4x_stop_periodic_measurement() - Stop periodic measurement and return to
- * idle mode for sensor configuration or to safe energy.
+ * @brief Read if data is ready.
+ *
+ * Polls the sensor for whether data from a periodic or single shot measurement
+ * is ready to be read out.
*
- * @note This command is only available in measurement mode.
+ * @param[out] arg_0
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_stop_periodic_measurement(void);
+int16_t scd4x_get_data_ready_status(bool* arg_0);
/**
- * scd4x_get_temperature_offset_ticks() - The temperature offset represents the
- * difference between the measured temperature by the SCD4x and the actual
- * ambient temperature. Per default, the temperature offset is set to 4°C.
+ * @brief Reads out the SCD4x sensor variant.
*
- * @note Only available in idle mode.
+ * @param[out] a_sensor_variant
*
- * @param t_offset Temperature offset. Convert value to °C by: 175 * value /
- * 2^16
+ * @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_get_temperature_offset_ticks(uint16_t* t_offset);
+int16_t scd4x_get_sensor_variant(scd4x_sensor_variant* a_sensor_variant);
/**
- * scd4x_get_temperature_offset() - The temperature offset represents the
- * difference between the measured temperature by the SCD4x and the actual
- * ambient temperature. Per default, the temperature offset is set to 4°C.
+ * @brief Start periodic measurement mode.
*
- * @note Only available in idle mode.
+ * Starts the periodic measurement mode. The signal update interval is 5
+ * seconds.
*
- * @param t_offset_m_deg_c Temperature offset in milli degrees Celsius.
+ * @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_get_temperature_offset(int32_t* t_offset_m_deg_c);
+int16_t scd4x_start_periodic_measurement();
/**
- * scd4x_set_temperature_offset_ticks() - Setting the temperature offset of the
- * SCD4x inside the customer device correctly allows the user to leverage the RH
- * and T output signal. Note that the temperature offset can depend on various
- * factors such as the SCD4x measurement mode, self-heating of close components,
- * the ambient temperature and air flow. Thus, the SCD4x temperature offset
- * should be determined inside the customer device under its typical operation
- * and in thermal equilibrium.
- *
- * @note Only available in idle mode.
+ * @brief Read CO₂, temperature, and humidity measurements raw values.
+ *
+ * Reads the sensor output. The measurement data can only be read out once per
+ * signal update interval as the buffer is emptied upon read-out. If no data is
+ * available in the buffer, the sensor returns a NACK. To avoid a NACK response,
+ * the get_data_ready_status can be issued to check data status. The I2C master
+ * can abort the read transfer with a NACK followed by a STOP condition after
+ * any data byte if the user is not interested in subsequent data.
+ *
+ * @param[out] co2_concentration CO₂ concentration in ppm
+ * @param[out] temperature Convert to degrees celsius by (175 * value / 65535) -
+ * 45
+ * @param[out] relative_humidity Convert to relative humidity in % by (100 *
+ * value / 65535)
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_read_measurement_raw(uint16_t* co2_concentration,
+ uint16_t* temperature,
+ uint16_t* relative_humidity);
+
+/**
+ * @brief Stop periodic measurement to change the sensor configuration or to
+ * save power.
*
- * @param t_offset Temperature offset. Convert °C to value by: T * 2^16 / 175.
+ * Command returns a sensor running in periodic measurement mode or low power
+ * periodic measurement mode back to the idle state, e.g. to then allow changing
+ * the sensor configuration or to save power.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_set_temperature_offset_ticks(uint16_t t_offset);
+int16_t scd4x_stop_periodic_measurement();
/**
- * scd4x_set_temperature_offset() - Setting the temperature offset of the SCD4x
- * inside the customer device correctly allows the user to leverage the RH and T
- * output signal. Note that the temperature offset can depend on various factors
- * such as the SCD4x measurement mode, self-heating of close components, the
- * ambient temperature and air flow. Thus, the SCD4x temperature offset should
- * be determined inside the customer device under its typical operation and in
- * thermal equilibrium.
+ * @brief Set the temperature compensation offset (raw value).
+ *
+ * Setting the temperature offset of the SCD4x inside the customer device allows
+ * the user to optimize the RH and T output signal. The temperature offset can
+ * depend on several factors such as the SCD4x measurement mode, self-heating of
+ * close components, the ambient temperature and air flow. Thus, the SCD4x
+ * temperature offset should be determined after integration into the final
+ * device and under its typical operating conditions (including the operation
+ * mode to be used in the application) in thermal equilibrium. By default, the
+ * temperature offset is set to 4 °C. To save the setting to the EEPROM, the
+ * persist_settings command may be issued. Equation (1) details how the
+ * characteristic temperature offset can be calculated using the current
+ * temperature output of the sensor (TSCD4x), a reference temperature value
+ * (TReference), and the previous temperature offset (Toffset_pervious) obtained
+ * using the get_temperature_offset_raw command:
+ *
+ * Toffset_actual = TSCD4x - TReference + Toffset_pervious.
+ *
+ * Recommended temperature offset values are between 0 °C and 20 °C. The
+ * temperature offset does not impact the accuracy of the CO2 output.
+ *
+ * @param[in] offset_temperature Temperature offset. Convert Toffset in °C to
+ * value by: (Toffset * 65535 / 175)
*
- * @note Only available in idle mode.
+ * @note This command is only available in idle mode.
*
- * @param t_offset_m_deg_c Temperature offset in milli degrees Celsius.
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_temperature_offset_raw(1498);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_set_temperature_offset(int32_t t_offset_m_deg_c);
+int16_t scd4x_set_temperature_offset_raw(uint16_t offset_temperature);
/**
- * scd4x_get_sensor_altitude() - Get configured sensor altitude in meters above
- * sea level. Per default, the sensor altitude is set to 0 meter above
- * sea-level.
+ * @brief Get the raw temperature compensation offset used by the sensor.
*
- * @note Only available in idle mode.
+ * @param[out] offset_temperature Convert to °C by (175 * value / 65535)
*
- * @param sensor_altitude Sensor altitude in meters.
+ * @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_get_sensor_altitude(uint16_t* sensor_altitude);
+int16_t scd4x_get_temperature_offset_raw(uint16_t* offset_temperature);
/**
- * scd4x_set_sensor_altitude() - Set sensor altitude in meters above sea level.
- * Note that setting a sensor altitude to the sensor overrides any pressure
- * compensation based on a previously set ambient pressure.
+ * @brief Set the altitude of the sensor (in meters above sea level).
+ *
+ * Typically, the sensor altitude is set once after device installation. To save
+ * the setting to the EEPROM, the persist_settings command must be issued. The
+ * default sensor altitude value is set to 0 meters above sea level. Note that
+ * setting a sensor altitude to the sensor overrides any pressure compensation
+ * based on a previously set ambient pressure.
*
- * @note Only available in idle mode.
+ * @param[in] sensor_altitude Sensor altitude in meters above sea level. Valid
+ * input values are between 0 - 3000 m.
+ *
+ * @note This command is only available in idle mode.
*
- * @param sensor_altitude Sensor altitude in meters.
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_sensor_altitude(0);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
int16_t scd4x_set_sensor_altitude(uint16_t sensor_altitude);
/**
- * scd4x_set_ambient_pressure() - The set_ambient_pressure command can be sent
- * during periodic measurements to enable continuous pressure compensation. Note
- * that setting an ambient pressure to the sensor overrides any pressure
- * compensation based on a previously set sensor altitude.
+ * @brief Get the sensor altitude used by the sensor.
+ *
+ * @param[out] sensor_altitude Sensor altitude used by the sensor in meters
+ * above sea level.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_sensor_altitude(uint16_t* sensor_altitude);
+
+/**
+ * @brief Set the raw ambient pressure value.
+ *
+ * The set_ambient_pressure command can be sent during periodic measurements to
+ * enable continuous pressure compensation. Note that setting an ambient
+ * pressure overrides any pressure compensation based on a previously set sensor
+ * altitude. Use of this command is highly recommended for applications
+ * experiencing significant ambient pressure changes to ensure sensor accuracy.
+ * Valid input values are between 70000 - 120000 Pa. The default value is 101300
+ * Pa.
+ *
+ * @param[in] ambient_pressure Convert ambient_pressure in hPa to Pa by
+ * ambient_pressure / 100.
*
* @note Available during measurements.
*
- * @param ambient_pressure Ambient pressure in hPa. Convert value to Pa by:
- * value * 100.
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_ambient_pressure_raw(1013);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_set_ambient_pressure(uint16_t ambient_pressure);
+int16_t scd4x_set_ambient_pressure_raw(uint16_t ambient_pressure);
/**
- * scd4x_perform_forced_recalibration() - To successfully conduct an accurate
-forced recalibration, the following steps need to be carried out:
-1. Operate the SCD4x in a periodic measurement mode for > 3 minutes in an
-environment with homogenous and constant CO₂ concentration.
-2. Stop periodic measurement. Wait 500 ms.
-3. Subsequently issue the perform_forced_recalibration command and optionally
-read out the baseline correction. A return value of 0xffff indicates that the
-forced recalibration failed.
+ * @brief Get the ambient pressure around the sensor.
+ *
+ * @param[out] ambient_pressure Convert to Pa by value = ambient_pressure * 100.
*
- * @param target_co2_concentration Target CO₂ concentration in ppm.
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_ambient_pressure_raw(uint16_t* ambient_pressure);
+
+/**
+ * @brief Perform a forced recalibration (FRC) of the CO₂ concentration.
*
- * @param frc_correction FRC correction value in CO₂ ppm or 0xFFFF if the
-command failed. Convert value to CO₂ ppm with: value - 0x8000
+ * To successfully conduct an accurate FRC, the following steps need to be
+ * carried out:
*
- * @return 0 on success, an error code otherwise
+ * 1. Operate the SCD4x in the operation mode later used for normal sensor
+ * operation (e.g. periodic measurement) for at least 3 minutes in an
+ * environment with a homogenous and constant CO2 concentration. The sensor must
+ * be operated at the voltage desired for the application when performing the
+ * FRC sequence. 2. Issue the stop_periodic_measurement command. 3. Issue the
+ * perform_forced_recalibration command.
+ *
+ * A return value of 0xffff indicates that the FRC has failed because the sensor
+ * was not operated before sending the command.
+ *
+ * @param[in] target_co2_concentration Target CO₂ concentration in ppm CO₂.
+ * @param[out] frc_correction Convert to FRC correction in ppm CO₂ by
+ * frc_correction - 0x8000. A return value of 0xFFFF indicates that the FRC has
+ * failed because the sensor was not operated before sending the command.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
int16_t scd4x_perform_forced_recalibration(uint16_t target_co2_concentration,
uint16_t* frc_correction);
/**
- * scd4x_get_automatic_self_calibration() - By default, the ASC is enabled.
+ * @brief Enable or disable automatic self calibration (ASC).
+ *
+ * Sets the current state (enabled / disabled) of the ASC. By default, ASC is
+ * enabled. To save the setting to the EEPROM, the persist_settings command must
+ * be issued. The ASC enables excellent long-term stability of SCD4x without the
+ * need for regular user intervention. The algorithm leverages the sensor's
+ * measurement history and the assumption of exposure of the sensor to a known
+ * minimum background CO₂ concentration at least once over a period of
+ * cumulative operation. By default, the ASC algorithm assumes that the sensor
+ * is exposed to outdoor fresh air at 400 ppm CO₂ concentration at least once
+ * per week of accumulated operation using one of the following measurement
+ * modes for at least 4 hours without interruption at a time: periodic
+ * measurement mode, low power periodic measurement mode or single shot mode
+ * with a measurement interval of 5 minutes (SCD41 only).
+ *
+ * @param[in] asc_enabled 1 enables ASC, 0 disables ASC.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
*
- * @param asc_enabled 1 if ASC is enabled, 0 if ASC is disabled
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_automatic_self_calibration_enabled(1);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_get_automatic_self_calibration(uint16_t* asc_enabled);
+int16_t scd4x_set_automatic_self_calibration_enabled(uint16_t asc_enabled);
/**
- * scd4x_set_automatic_self_calibration() - By default, the ASC is enabled.
+ * @brief Check if automatic self calibration (ASC) is enabled.
+ *
+ * @param[out] asc_enabled 1 if ASC is enabled, 0 if ASC is disabled.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_automatic_self_calibration_enabled(uint16_t* asc_enabled);
+
+/**
+ * @brief Set the value of ASC baseline target in ppm.
+ *
+ * Sets the value of the ASC baseline target, i.e. the CO₂ concentration in ppm
+ * which the ASC algorithm will assume as lower-bound background to which the
+ * SCD4x is exposed to regularly within one ASC period of operation. To save the
+ * setting to the EEPROM, the persist_settings command must be issued
+ * subsequently. The factory default value is 400 ppm.
+ *
+ * @param[in] asc_target ASC baseline value in ppm CO₂
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_automatic_self_calibration_target(400);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
*
- * @param asc_enabled 1 to enable ASC, 0 to disable ASC
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_set_automatic_self_calibration(uint16_t asc_enabled);
+int16_t scd4x_set_automatic_self_calibration_target(uint16_t asc_target);
/**
- * scd4x_start_low_power_periodic_measurement() - Start low power periodic
- * measurement, signal update interval is 30 seconds.
+ * @brief Reads out the ASC baseline target concentration parameter.
+ *
+ * @param[out] asc_target ASC baseline target concentration parameter in ppm
+ * CO₂.
*
* @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_automatic_self_calibration_target(uint16_t* asc_target);
+
+/**
+ * @brief Start a low-power periodic measurement (interval 30 s).
+ *
+ * To enable use-cases with a constrained power budget, the SCD4x features a low
+ * power periodic measurement mode with a signal update interval of
+ * approximately 30 seconds. The low power periodic measurement mode is
+ * initiated using the start_low_power_periodic_measurement command and read-out
+ * in a similar manner as the periodic measurement mode using the
+ * read_measurement command. To periodically check whether a new measurement
+ * result is available for read out, the get_data_ready_status command can be
+ * used to synchronize to the sensor's internal measurement interval as an
+ * alternative to relying on the ACK/NACK status of the
+ * read_measurement_command.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_start_low_power_periodic_measurement(void);
+int16_t scd4x_start_low_power_periodic_measurement();
/**
- * scd4x_get_data_ready_flag() - Check whether new measurement data is
- * available for read-out.
+ * @brief Read if data is ready.
*
- * @param data_ready_flag True if data available, otherwise false.
+ * Polls the sensor for whether data from a periodic or single shot measurement
+ * is ready to be read out.
*
- * @return 0 on success, an error code otherwise
+ * @param[out] data_ready_status If one or more of the 11 least significant bits
+ * are 1, then the data is ready.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_get_data_ready_flag(bool* data_ready_flag);
+int16_t scd4x_get_data_ready_status_raw(uint16_t* data_ready_status);
/**
- * scd4x_persist_settings() - Configuration settings such as the temperature
- * offset, sensor altitude and the ASC enabled/disabled parameter are by default
- * stored in the volatile memory (RAM) only and will be lost after a
- * power-cycle. The persist_settings command stores the current configuration in
- * the EEPROM of the SCD4x, making them resistant to power-cycling. To avoid
- * unnecessary wear of the EEPROM, the persist_settings command should only be
- * sent when persistence is required and if actual changes to the configuration
- * have been made. Note that field calibration history (i.e. FRC and ASC) is
- * stored in the EEPROM automatically.
+ * @brief Store volatile sensor settings in the EEPROM.
+ *
+ * Configuration settings such as the temperature offset, sensor altitude and
+ * the ASC enabled/disabled parameters are by default stored in the volatile
+ * memory (RAM) only. The persist_settings command stores the current
+ * configuration in the EEPROM of the SCD4x, ensuring the current settings
+ * persist after power-cycling. To avoid unnecessary wear of the EEPROM, the
+ * persist_settings command should only be sent following configuration changes
+ * whose persistence is required. The EEPROM is guaranteed to withstand at least
+ * 2000 write cycles. Note that field calibration history (i.e. FRC and ASC) is
+ * automatically stored in a separate EEPROM dimensioned for the specified
+ * sensor lifetime when operated continuously in either periodic measurement
+ * mode, low power periodic measurement mode or single shot mode with 5 minute
+ * measurement interval (SCD41 only).
*
- * @note
+ * @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_persist_settings(void);
+int16_t scd4x_persist_settings();
/**
- * scd4x_get_serial_number() - Reading out the serial number can be used to
- * identify the chip and to verify the presence of the sensor. The get serial
- * number command returns 3 words. Together, the 3 words constitute a unique
- * serial number with a length of 48 bits (big endian format).
+ * @brief Read the sensor's unique serial number.
*
- * @param serial_0 First word of the 48 bit serial number
+ * Reading out the serial number can be used to identify the chip and to verify
+ * the presence of the sensor. The get_serial_number command returns 3 words,
+ * and every word is followed by an 8-bit CRC checksum. Together, the 3 words
+ * constitute a unique serial number with a length of 48 bits (in big endian
+ * format).
*
- * @param serial_1 Second word of the 48 bit serial number
+ * @param[out] serial_number 48-bit unique serial number of the sensor.
*
- * @param serial_2 Third word of the 48 bit serial number
+ * @note This command is only available in idle mode.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_get_serial_number(uint16_t* serial_0, uint16_t* serial_1,
- uint16_t* serial_2);
+int16_t scd4x_get_serial_number(uint16_t* serial_number,
+ uint16_t serial_number_size);
/**
- * scd4x_perform_self_test() - The perform_self_test feature can be used as an
- * end-of-line test to confirm sensor functionality.
+ * @brief Perform self test to assess sensor functionality and power supply.
*
- * @param sensor_status 0 means no malfunction detected
+ * Can be used as an end-of-line test to check the sensor functionality.
*
- * @return 0 on success, an error code otherwise
+ * @param[out] sensor_status If sensor status is equal to 0, no malfunction has
+ * been detected.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
int16_t scd4x_perform_self_test(uint16_t* sensor_status);
/**
- * scd4x_perform_factory_reset() - Initiates the reset of all configurations
- * stored in the EEPROM and erases the FRC and ASC algorithm history.
+ * @brief Perform factory reset to erase the settings stored in the EEPROM.
+ *
+ * The perform_factory_reset command resets all configuration settings stored in
+ * the EEPROM and erases the FRC and ASC algorithm history.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_perform_factory_reset();
+
+/**
+ * @brief Reinitialize the sensor by reloading the settings from the EEPROM.
+ *
+ * The reinit command reinitialize the sensor by reloading user settings from
+ * EEPROM. The sensor must be in the idle state before sending the reinit
+ * command. If the reinit command does not trigger the desired
+ * re-initialization, a power-cycle should be applied to the SCD4x.
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_reinit();
+
+/**
+ * @brief Reads out the SCD4x sensor variant.
+ *
+ * @param[out] sensor_variant Bits[15…12] = 0000 → SCD40 Bits[15…12] = 0001 →
+ * SCD41
+ *
+ * @note This command is only available in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_sensor_variant_raw(uint16_t* sensor_variant);
+
+/**
+ * @brief On-demand measurement of the CO₂ concentration, temperature, and
+ * humidity.
+ *
+ * The sensor output is read out by using the read_measurement command. The
+ * fastest possible sampling interval for single shot measurements is 5 seconds.
+ * The ASC is enabled by default in single shot operation and optimized for
+ * single shot measurements performed every 5 minutes. For more details about
+ * single shot measurements and optimization of power consumption please refer
+ * to the datasheet.
+ *
+ * @note This command is only available for SCD41.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_perform_factory_reset(void);
+int16_t scd4x_measure_single_shot();
/**
- * scd4x_reinit() - The reinit command reinitializes the sensor by reloading
- * user settings from EEPROM. Before sending the reinit command, the stop
- * measurement command must be issued. If reinit command does not trigger the
- * desired re-initialization, a power-cycle should be applied to the SCD4x.
+ * @brief On-demand measurement of the temperature and humidity only.
*
- * @note Only available in idle mode.
+ * For more details about single shot measurements and optimization of power
+ * consumption please refer to the datasheet.
*
- * @return 0 on success, an error code otherwise
+ * @note This command is only available for SCD41.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_reinit(void);
+int16_t scd4x_measure_single_shot_rht_only();
/**
- * scd4x_measure_single_shot() - On-demand measurement of CO₂ concentration,
- * relative humidity and temperature. The sensor output is read with the
- * read_measurement command.
+ * @brief Put the sensor into sleep mode from idle mode.
+ *
+ * Put the sensor from idle to sleep to reduce power consumption. Can be used to
+ * power down when operating the sensor in power-cycled single shot mode.
*
- * @note Only available in idle mode.
+ * @note This command is only available in idle mode. Only for SCD41.
*
- * @return 0 on success, an error code otherwise
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_measure_single_shot(void);
+int16_t scd4x_power_down();
/**
- * scd4x_measure_single_shot_rht_only() - On-demand measurement of relative
- * humidity and temperature only.
+ * @brief Wake up sensor from sleep mode to idle mode.
*
- * @note Only available in idle mode.
+ * Wake up the sensor from sleep mode into idle mode. Note that the SCD4x does
+ * not acknowledge the wake_up command. The sensor's idle state after wake up
+ * can be verified by reading out the serial number.
*
- * @return 0 on success, an error code otherwise
+ * @note This command is only available for SCD41.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_measure_single_shot_rht_only(void);
+int16_t scd4x_wake_up();
/**
- * scd4x_power_down() - Put the sensor from idle to sleep mode to reduce current
- * consumption.
+ * @brief Sets the initial period for ASC correction
+ *
+ * Sets the duration of the initial period for ASC correction (in hours). By
+ * default, the initial period for ASC correction is 44 hours. Allowed values
+ * are integer multiples of 4 hours. A value of 0 results in an immediate
+ * correction. To save the setting to the EEPROM, the persist_settings command
+ * must be issued.
+ *
+ * For single shot operation, this parameter always assumes a measurement
+ * interval of 5 minutes, counting the number of single shots to calculate
+ * elapsed time. If single shot measurements are taken more / less frequently
+ * than once every 5 minutes, this parameter must be scaled accordingly to
+ * achieve the intended period in hours (e.g. for a 10-minute measurement
+ * interval, the scaled parameter value is obtained by multiplying the intended
+ * period in hours by 0.5).
+ *
+ * @param[in] asc_initial_period ASC initial period in hours
*
- * @note Only available in idle mode.
+ * @note This command is available for SCD41 and only in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_automatic_self_calibration_initial_period(44);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
*
- * @return 0 on success, an error code otherwise
*/
-int16_t scd4x_power_down(void);
+int16_t scd4x_set_automatic_self_calibration_initial_period(
+ uint16_t asc_initial_period);
/**
- * scd4x_wake_up() - Wake up sensor from sleep mode to idle mode.
+ * @brief Read out the initial period for ASC correction
*
- * @note Only available in sleep mode.
+ * @param[out] asc_initial_period ASC initial period in hours
*
- * @return 0 on success, an error code otherwise
+ * @note This command is only available for SCD41 and only in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
*/
-int16_t scd4x_wake_up(void);
+int16_t scd4x_get_automatic_self_calibration_initial_period(
+ uint16_t* asc_initial_period);
+
+/**
+ * @brief Sets the standard period for ASC correction.
+ *
+ * Sets the standard period for ASC correction (in hours). By default, the
+ * standard period for ASC correction is 156 hours. Allowed values are integer
+ * multiples of 4 hours. Note: a value of 0 results in an immediate correction.
+ * To save the setting to the EEPROM, the persist_settings (see Section 3.10.1)
+ * command must be issued.
+ *
+ * For single shot operation, this parameter always assumes a measurement
+ * interval of 5 minutes, counting the number of single shots to calculate
+ * elapsed time. If single shot measurements are taken more / less frequently
+ * than once every 5 minutes, this parameter must be scaled accordingly to
+ * achieve the intended period in hours (e.g. for a 10-minute measurement
+ * interval, the scaled parameter value is obtained by multiplying the intended
+ * period in hours by 0.5).
+ *
+ * @param[in] asc_standard_period ASC standard period in hours
+ *
+ * @note This command is only available for SCD41 and only in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ *
+ * Example:
+ * --------
+ *
+ * @code{.c}
+ *
+ * int16_t local_error = 0;
+ * local_error = scd4x_set_automatic_self_calibration_standard_period(156);
+ * if (local_error != NO_ERROR) {
+ * return local_error;
+ * }
+ *
+ * @endcode
+ *
+ */
+int16_t scd4x_set_automatic_self_calibration_standard_period(
+ uint16_t asc_standard_period);
+
+/**
+ * @brief Get the standard period for ASC correction.
+ *
+ * @param[out] asc_standard_period ASC standard period in hours
+ *
+ * @note This command is only available for SCD41 and only in idle mode.
+ *
+ * @return error_code 0 on success, an error code otherwise.
+ */
+int16_t scd4x_get_automatic_self_calibration_standard_period(
+ uint16_t* asc_standard_period);
#ifdef __cplusplus
}
#endif
-
-#endif /* SCD4X_I2C_H */
+#endif // SCD4X_I2C_H
diff --git a/scd4x_i2c_example_usage.c b/scd4x_i2c_example_usage.c
deleted file mode 100644
index 89f6bb5..0000000
--- a/scd4x_i2c_example_usage.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 // printf
-
-#include "scd4x_i2c.h"
-#include "sensirion_common.h"
-#include "sensirion_i2c_hal.h"
-
-/**
- * TO USE CONSOLE OUTPUT (PRINTF) IF NOT PRESENT ON YOUR PLATFORM
- */
-//#define printf(...)
-
-int main(void) {
- int16_t error = 0;
-
- sensirion_i2c_hal_init();
-
- // Clean up potential SCD40 states
- scd4x_wake_up();
- scd4x_stop_periodic_measurement();
- scd4x_reinit();
-
- uint16_t serial_0;
- uint16_t serial_1;
- uint16_t serial_2;
- error = scd4x_get_serial_number(&serial_0, &serial_1, &serial_2);
- if (error) {
- printf("Error executing scd4x_get_serial_number(): %i\n", error);
- } else {
- printf("serial: 0x%04x%04x%04x\n", serial_0, serial_1, serial_2);
- }
-
- // Start Measurement
-
- error = scd4x_start_periodic_measurement();
- if (error) {
- printf("Error executing scd4x_start_periodic_measurement(): %i\n",
- error);
- }
-
- printf("Waiting for first measurement... (5 sec)\n");
-
- for (;;) {
- // Read Measurement
- sensirion_i2c_hal_sleep_usec(100000);
- bool data_ready_flag = false;
- error = scd4x_get_data_ready_flag(&data_ready_flag);
- if (error) {
- printf("Error executing scd4x_get_data_ready_flag(): %i\n", error);
- continue;
- }
- if (!data_ready_flag) {
- continue;
- }
-
- uint16_t co2;
- int32_t temperature;
- int32_t humidity;
- error = scd4x_read_measurement(&co2, &temperature, &humidity);
- if (error) {
- printf("Error executing scd4x_read_measurement(): %i\n", error);
- } else if (co2 == 0) {
- printf("Invalid sample detected, skipping.\n");
- } else {
- printf("CO2: %u\n", co2);
- printf("Temperature: %d m°C\n", temperature);
- printf("Humidity: %d mRH\n", humidity);
- }
- }
-
- return 0;
-}
diff --git a/sensirion_common.c b/sensirion_common.c
index 4ee7a96..3cab3c1 100644
--- a/sensirion_common.c
+++ b/sensirion_common.c
@@ -60,27 +60,27 @@ float sensirion_common_bytes_to_float(const uint8_t* bytes) {
}
void sensirion_common_uint32_t_to_bytes(const uint32_t value, uint8_t* bytes) {
- bytes[0] = value >> 24;
- bytes[1] = value >> 16;
- bytes[2] = value >> 8;
- bytes[3] = value;
+ bytes[0] = (uint8_t)(value >> 24);
+ bytes[1] = (uint8_t)(value >> 16);
+ bytes[2] = (uint8_t)(value >> 8);
+ bytes[3] = (uint8_t)(value);
}
void sensirion_common_uint16_t_to_bytes(const uint16_t value, uint8_t* bytes) {
- bytes[0] = value >> 8;
- bytes[1] = value;
+ bytes[0] = (uint8_t)(value >> 8);
+ bytes[1] = (uint8_t)value;
}
void sensirion_common_int32_t_to_bytes(const int32_t value, uint8_t* bytes) {
- bytes[0] = value >> 24;
- bytes[1] = value >> 16;
- bytes[2] = value >> 8;
- bytes[3] = value;
+ bytes[0] = (uint8_t)(value >> 24);
+ bytes[1] = (uint8_t)(value >> 16);
+ bytes[2] = (uint8_t)(value >> 8);
+ bytes[3] = (uint8_t)value;
}
void sensirion_common_int16_t_to_bytes(const int16_t value, uint8_t* bytes) {
- bytes[0] = value >> 8;
- bytes[1] = value;
+ bytes[0] = (uint8_t)(value >> 8);
+ bytes[1] = (uint8_t)value;
}
void sensirion_common_float_to_bytes(const float value, uint8_t* bytes) {
@@ -99,3 +99,22 @@ void sensirion_common_copy_bytes(const uint8_t* source, uint8_t* destination,
destination[i] = source[i];
}
}
+
+void sensirion_common_to_integer(const uint8_t* source, uint8_t* destination,
+ INT_TYPE int_type, uint8_t data_length) {
+
+ if (data_length > int_type) {
+ data_length = 0; // we do not read at all if data_length is bigger than
+ // the provided integer!
+ }
+
+ // pad missing bytes
+ uint8_t offset = int_type - data_length;
+ for (uint8_t i = 0; i < offset; i++) {
+ destination[int_type - i - 1] = 0;
+ }
+
+ for (uint8_t i = 1; i <= data_length; i++) {
+ destination[int_type - offset - i] = source[i - 1];
+ }
+}
diff --git a/sensirion_common.h b/sensirion_common.h
index cfcd19f..e290933 100644
--- a/sensirion_common.h
+++ b/sensirion_common.h
@@ -50,6 +50,11 @@ extern "C" {
#define SENSIRION_NUM_WORDS(x) (sizeof(x) / SENSIRION_WORD_SIZE)
#define SENSIRION_MAX_BUFFER_WORDS 32
+/**
+ * Enum to describe the type of an integer
+ */
+typedef enum { BYTE = 1, SHORT = 2, INTEGER = 4, LONG_INTEGER = 8 } INT_TYPE;
+
/**
* sensirion_common_bytes_to_int16_t() - Convert an array of bytes to an int16_t
*
@@ -174,6 +179,17 @@ void sensirion_common_float_to_bytes(const float value, uint8_t* bytes);
void sensirion_common_copy_bytes(const uint8_t* source, uint8_t* destination,
uint16_t data_length);
+/**
+ * sensirion_common_to_integer() - Copy bytes from byte array to integer.
+ *
+ * @param source Array of bytes to be copied.
+ * @param int_value Pointer to integer of bytes to be copied to.
+ * @param int_type Type (size) of the integer to be copied.
+ * @param data_length Number of bytes to copy.
+ */
+void sensirion_common_to_integer(const uint8_t* source, uint8_t* destination,
+ INT_TYPE int_type, uint8_t data_length);
+
#ifdef __cplusplus
}
#endif
diff --git a/sensirion_i2c.c b/sensirion_i2c.c
index 784c402..5f709fc 100644
--- a/sensirion_i2c.c
+++ b/sensirion_i2c.c
@@ -177,6 +177,19 @@ uint16_t sensirion_i2c_add_command_to_buffer(uint8_t* buffer, uint16_t offset,
return offset;
}
+uint16_t sensirion_i2c_add_command16_to_buffer(uint8_t* buffer, uint16_t offset,
+ uint16_t command) {
+ buffer[offset++] = (uint8_t)((command & 0xFF00) >> 8);
+ buffer[offset++] = (uint8_t)((command & 0x00FF) >> 0);
+ return offset;
+}
+
+uint16_t sensirion_i2c_add_command8_to_buffer(uint8_t* buffer, uint16_t offset,
+ uint8_t command) {
+ buffer[offset++] = command;
+ return offset;
+}
+
uint16_t sensirion_i2c_add_uint32_t_to_buffer(uint8_t* buffer, uint16_t offset,
uint32_t data) {
buffer[offset++] = (uint8_t)((data & 0xFF000000) >> 24);
@@ -238,7 +251,7 @@ uint16_t sensirion_i2c_add_float_to_buffer(uint8_t* buffer, uint16_t offset,
}
uint16_t sensirion_i2c_add_bytes_to_buffer(uint8_t* buffer, uint16_t offset,
- uint8_t* data,
+ const uint8_t* data,
uint16_t data_length) {
uint16_t i;
diff --git a/sensirion_i2c.h b/sensirion_i2c.h
index db99c20..45ff5c3 100644
--- a/sensirion_i2c.h
+++ b/sensirion_i2c.h
@@ -181,6 +181,39 @@ int16_t sensirion_i2c_read_cmd(uint8_t address, uint16_t cmd,
uint16_t sensirion_i2c_add_command_to_buffer(uint8_t* buffer, uint16_t offset,
uint16_t command);
+/**
+ * sensirion_i2c_add_command16_to_buffer() - Add a command to the buffer at
+ * the specified offset. This function is equivalent to the
+ * function sensirion_i2c_add_command_to_buffer().
+ *
+ * @param buffer Pointer to buffer in which the write frame will be prepared.
+ * Caller needs to make sure that there is enough space after
+ * offset left to write the data into the buffer.
+ * @param offset Offset of the next free byte in the buffer.
+ * @param command Command to be written into the buffer.
+ *
+ * @return Offset of next free byte in the buffer after writing the data.
+ */
+uint16_t sensirion_i2c_add_command16_to_buffer(uint8_t* buffer, uint16_t offset,
+ uint16_t command);
+
+/**
+ * sensirion_i2c_add_command8_to_buffer() - Add a command to the buffer at
+ * offset. Adds one bytes command to the buffer.
+ * This is used for sensor that only take one command byte such as
+ * SHT.
+ *
+ * @param buffer Pointer to buffer in which the write frame will be prepared.
+ * Caller needs to make sure that there is enough space after
+ * offset left to write the data into the buffer.
+ * @param offset Offset of the next free byte in the buffer.
+ * @param command Command to be written into the buffer.
+ *
+ * @return Offset of next free byte in the buffer after writing the data.
+ */
+uint16_t sensirion_i2c_add_command8_to_buffer(uint8_t* buffer, uint16_t offset,
+ uint8_t command);
+
/**
* sensirion_i2c_add_uint32_t_to_buffer() - Add a uint32_t to the buffer at
* offset. Adds 6 bytes to the buffer.
@@ -274,7 +307,8 @@ uint16_t sensirion_i2c_add_float_to_buffer(uint8_t* buffer, uint16_t offset,
* data.
*/
uint16_t sensirion_i2c_add_bytes_to_buffer(uint8_t* buffer, uint16_t offset,
- uint8_t* data, uint16_t data_length);
+ const uint8_t* data,
+ uint16_t data_length);
/**
* sensirion_i2c_write_data() - Writes data to the Sensor.
diff --git a/sensirion_i2c_hal.c b/sensirion_i2c_hal.c
index d63f815..d368cf2 100644
--- a/sensirion_i2c_hal.c
+++ b/sensirion_i2c_hal.c
@@ -83,7 +83,7 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
/* TODO:IMPLEMENT */
return NOT_IMPLEMENTED_ERROR;
}
@@ -100,7 +100,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count) {
+ uint8_t count) {
/* TODO:IMPLEMENT */
return NOT_IMPLEMENTED_ERROR;
}
diff --git a/sensirion_i2c_hal.h b/sensirion_i2c_hal.h
index f97444a..d6267b8 100644
--- a/sensirion_i2c_hal.h
+++ b/sensirion_i2c_hal.h
@@ -71,7 +71,7 @@ void sensirion_i2c_hal_free(void);
* @param count number of bytes to read from I2C and store in the buffer
* @returns 0 on success, error code otherwise
*/
-int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count);
+int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count);
/**
* Execute one write transaction on the I2C bus, sending a given number of
@@ -85,7 +85,7 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count);
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
- uint16_t count);
+ uint8_t count);
/**
* Sleep for a given number of microseconds. The function should delay the
diff --git a/tests/Makefile b/tests/Makefile
index a0b32ba..3da3839 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,19 +1,33 @@
-driver_dir := ..
-mux_dir := ../i2c-mux-testbed
-i2c_mux_sources = ${mux_dir}/i2c_mux.h ${mux_dir}/i2c_mux.c
-common_sources = ${driver_dir}/sensirion_config.h ${driver_dir}/sensirion_common.h ${driver_dir}/sensirion_common.c
-i2c_sources = ${driver_dir}/sensirion_i2c_hal.h ${driver_dir}/sensirion_i2c.h ${driver_dir}/sensirion_i2c.c
-sensirion_test_sources = sensirion_test_setup.cpp ${i2c_mux_sources}
+# use the second argument of make as argument to control test bed initialization
+TEST_ARG := $(wordlist 2, 2, $(MAKECMDGOALS))
+# ...turn it into do-nothing target
+$(eval $(TEST_ARG):;@:)
+
+ ifeq ($(TEST_ARG), mux)
+ driver_dir := ..
+ mux_dir := ../i2c-mux-testbed
+ i2c_mux_sources = ${mux_dir}/i2c_mux.h ${mux_dir}/i2c_mux.c
+ macros := "-D USE_MUX"
+ else
+ mux_dir := .
+ i2c_mux_sources =
+ macros :=
+ endif
+
+driver_dir := ..
+common_sources = $(driver_dir)/sensirion_config.h $(driver_dir)/sensirion_common.h $(driver_dir)/sensirion_common.c
+i2c_sources = $(driver_dir)/sensirion_i2c_hal.h ${driver_dir}/sensirion_i2c.h $(driver_dir)/sensirion_i2c.c
+sensirion_test_sources = sensirion_test_setup.cpp $(i2c_mux_sources)
-sw_i2c_dir := ${driver_dir}/sample-implementations/GPIO_bit_banging
+sw_i2c_dir := $(driver_dir)/sample-implementations/GPIO_bit_banging
-hw_i2c_impl_src = ${driver_dir}/sample-implementations/linux_user_space/sensirion_i2c_hal.c
-sw_i2c_impl_src = ${sw_i2c_dir}/sample-implementations/linux_user_space/sensirion_i2c_gpio.c ${sw_i2c_dir}/sensirion_i2c_hal.c
+hw_i2c_impl_src = $(driver_dir)/sample-implementations/linux_user_space/sensirion_i2c_hal.c
+sw_i2c_impl_src = $(sw_i2c_dir)/sample-implementations/linux_user_space/sensirion_i2c_gpio.c $(sw_i2c_dir)/sensirion_i2c_hal.c
-scd4x_sources = ${driver_dir}/scd4x_i2c.h ${driver_dir}/scd4x_i2c.c
+scd4x_sources = $(driver_dir)/scd4x_i2c.h $(driver_dir)/scd4x_i2c.c
-CXXFLAGS ?= $(CFLAGS) -fsanitize=address -I${mux_dir} -I${driver_dir} -I${sw_i2c_dir}
+CXXFLAGS ?= $(CFLAGS) -fsanitize=address -I$(mux_dir) -I$(driver_dir) -I$(sw_i2c_dir) ${macros}
ifdef CI
CXXFLAGS += -Werror
endif
@@ -22,18 +36,18 @@ LDFLAGS ?= -lasan -lstdc++ -lCppUTest -lCppUTestExt
.PHONY: clean test
-scd4x_test_binaries := scd4x-test-hw_i2c scd4x-test-sw_i2c
+scd4x_test_binaries := scd4x_test_hw_i2c scd4x_test_sw_i2c
-all: ${scd4x_test_binaries}
+all: $(scd4x_test_binaries)
-scd4x-test-hw_i2c: scd4x_i2c_test.cpp ${scd4x_sources} ${sensirion_test_sources} ${i2c_sources} ${hw_i2c_impl_src} ${common_sources}
+scd4x_test_hw_i2c: scd4x_i2c_test.cpp $(scd4x_sources) $(sensirion_test_sources) $(i2c_sources) $(hw_i2c_impl_src) $(common_sources)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
-scd4x-test-sw_i2c: scd4x_i2c_test.cpp ${scd4x_sources} ${sensirion_test_sources} ${i2c_sources} ${sw_i2c_impl_src} ${common_sources}
+scd4x_test_sw_i2c: scd4x_i2c_test.cpp $(scd4x_sources) $(sensirion_test_sources) $(i2c_sources) $(sw_i2c_impl_src) $(common_sources)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
-test: ${scd4x_test_binaries}
- set -ex; for test in ${scd4x_test_binaries}; do echo $${test}; ./$${test}; echo; done;
+test: $(scd4x_test_binaries)
+ set -ex; for test in $(scd4x_test_binaries); do echo $${test}; ./$${test}; echo; done;
clean:
- $(RM) ${scd4x_test_binaries}
+ $(RM) $(scd4x_test_binaries)
diff --git a/tests/scd4x_i2c_test.cpp b/tests/scd4x_i2c_test.cpp
index 0bce7cb..0dff761 100644
--- a/tests/scd4x_i2c_test.cpp
+++ b/tests/scd4x_i2c_test.cpp
@@ -1,35 +1,11 @@
/*
- * Copyright (c) 2021, Sensirion AG
- * All rights reserved.
+ * THIS FILE IS AUTOMATICALLY GENERATED
*
- * 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.
+ * Generator: sensirion-driver-generator 1.1.2
+ * Product: scd4x
+ * Model-Version: 2.0
*/
-#include "i2c_mux.h"
#include "scd4x_i2c.h"
#include "sensirion_common.h"
#include "sensirion_i2c.h"
@@ -38,268 +14,268 @@
#include
#include
-TEST_GROUP (SCD4X_Tests) {
- void setup() {
- sensirion_i2c_hal_init();
-
- // Select MUX 2 channel 0
- int16_t error = sensirion_i2c_mux_set_single_channel(0x72, 0);
- CHECK_EQUAL_ZERO_TEXT(error, "sensirion_i2c_mux_set_single_channel");
+#define sensirion_hal_sleep_us sensirion_i2c_hal_sleep_usec
- // try to reset sensor
- (void)scd4x_wake_up();
- (void)scd4x_stop_periodic_measurement();
- error = scd4x_reinit();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_reinit");
+void print_ushort_array(uint16_t* array, uint16_t len) {
+ uint16_t i = 0;
+ printf("0x");
+ for (; i < len; i++) {
+ printf("%04x", array[i]);
}
+}
- void teardown() {
- sensirion_i2c_hal_free();
+TEST_GROUP (SCD4X_Tests) {
+ void setup() {
+ scd4x_init(0x62);
}
};
-TEST (SCD4X_Tests, SCD4X_Test_start_periodic_measurement) {
- int16_t error;
- error = scd4x_start_periodic_measurement();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_start_periodic_measurement");
-
- sensirion_i2c_hal_sleep_usec(5000000);
- uint16_t co2;
- uint16_t temperature;
- uint16_t humidity;
- error = scd4x_read_measurement_ticks(&co2, &temperature, &humidity);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_read_measurement_ticks");
-
- printf("co2: %i\n", co2);
- printf("temperature: %i\n", temperature);
- printf("humidity: %i\n", humidity);
-
- error = scd4x_stop_periodic_measurement();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_stop_periodic_measurement");
+TEST (SCD4X_Tests, test_set_temperature_offset_raw1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_temperature_offset_raw(1498);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_temperature_offset_raw");
}
-TEST (SCD4X_Tests, SCD4X_Test_read_measurement_ticks_fails_in_idle) {
- int16_t error;
- uint16_t co2;
- uint16_t temperature;
- uint16_t humidity;
- error = scd4x_read_measurement_ticks(&co2, &temperature, &humidity);
- CHECK_TEXT(error != 0, "scd4x_read_measurement_ticks should fail in idle");
+TEST (SCD4X_Tests, test_get_temperature_offset_raw1) {
+ int16_t local_error = 0;
+ uint16_t offset_temperature = 0;
+ local_error = scd4x_get_temperature_offset_raw(&offset_temperature);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_temperature_offset_raw");
+ printf("offset_temperature: %u\n", offset_temperature);
}
-TEST (SCD4X_Tests, SCD4X_Test_stop_periodic_measurement_in_idle) {
- int16_t error;
- error = scd4x_stop_periodic_measurement();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_stop_periodic_measurement");
+TEST (SCD4X_Tests, test_set_sensor_altitude1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_sensor_altitude(0);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_sensor_altitude");
}
-TEST (SCD4X_Tests, SCD4X_Test_get_temperature_offset_ticks_after_reinit) {
- int16_t error;
- uint16_t t_offset;
- error = scd4x_get_temperature_offset_ticks(&t_offset);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_temperature_offset");
- printf("t_offset: %i\n", t_offset);
-
- CHECK_EQUAL_TEXT(t_offset, 1498, "T offset wrong after reinit")
+TEST (SCD4X_Tests, test_get_sensor_altitude1) {
+ int16_t local_error = 0;
+ uint16_t sensor_altitude = 0;
+ local_error = scd4x_get_sensor_altitude(&sensor_altitude);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_sensor_altitude");
+ printf("sensor_altitude: %u\n", sensor_altitude);
}
-TEST (SCD4X_Tests, SCD4X_Test_set_temperature_offset_ticks) {
- int16_t error;
- error = scd4x_set_temperature_offset_ticks(0);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_set_temperature_offset");
-
- uint16_t t_offset;
- error = scd4x_get_temperature_offset_ticks(&t_offset);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_temperature_offset");
- printf("t_offset: %i\n", t_offset);
-
- CHECK_EQUAL_TEXT(t_offset, 0, "T offset should be 0")
+TEST (SCD4X_Tests, test_get_serial_number1) {
+ int16_t local_error = 0;
+ uint16_t serial_number[3] = {0};
+ local_error = scd4x_get_serial_number(serial_number, 3);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_serial_number");
+ printf("serial_number: ");
+ print_ushort_array(serial_number, 3);
+ printf("\n");
}
-TEST (SCD4X_Tests, SCD4X_Test_get_sensor_altitude_default) {
- int16_t error;
- uint16_t sensor_altitude;
- error = scd4x_get_sensor_altitude(&sensor_altitude);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_sensor_altitude");
- printf("sensor_altitude: %i\n", sensor_altitude);
-
- CHECK_EQUAL_TEXT(sensor_altitude, 0,
- "sensor_altitude should be 0 by default");
+TEST (SCD4X_Tests, test_perform_forced_recalibration1) {
+ int16_t local_error = 0;
+ uint16_t frc_correction = 0;
+ local_error = scd4x_perform_forced_recalibration(400, &frc_correction);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "perform_forced_recalibration");
+ printf("frc_correction: %u\n", frc_correction);
}
-TEST (SCD4X_Tests, SCD4X_Test_set_sensor_altitude) {
- int16_t error;
- error = scd4x_set_sensor_altitude(42);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_set_sensor_altitude");
-
- uint16_t sensor_altitude;
- error = scd4x_get_sensor_altitude(&sensor_altitude);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_sensor_altitude");
- printf("sensor_altitude: %i\n", sensor_altitude);
-
- CHECK_EQUAL_TEXT(sensor_altitude, 42,
- "sensor_altitude should be the set value");
+TEST (SCD4X_Tests, test_set_automatic_self_calibration_enabled1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_automatic_self_calibration_enabled(1);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "set_automatic_self_calibration_enabled");
}
-TEST (SCD4X_Tests, SCD4X_Test_set_ambient_pressure) {
- int16_t error;
- uint16_t ambient_pressure = 0;
- error = scd4x_set_ambient_pressure(ambient_pressure);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_set_ambient_pressure");
+TEST (SCD4X_Tests, test_get_automatic_self_calibration_enabled1) {
+ int16_t local_error = 0;
+ uint16_t asc_enabled = 0;
+ local_error = scd4x_get_automatic_self_calibration_enabled(&asc_enabled);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "get_automatic_self_calibration_enabled");
+ printf("asc_enabled: %u\n", asc_enabled);
}
-TEST (SCD4X_Tests, SCD4X_Test_perform_forced_recalibration) {
- int16_t error;
- uint16_t target_co2_concentration = 400;
- uint16_t frc_correction;
- error = scd4x_perform_forced_recalibration(target_co2_concentration,
- &frc_correction);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_perform_forced_recalibration");
- printf("frc_correction: %i\n", frc_correction);
+TEST (SCD4X_Tests, test_set_automatic_self_calibration_target1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_automatic_self_calibration_target(400);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_automatic_self_calibration_target");
}
-TEST (SCD4X_Tests, SCD4X_Test_get_automatic_self_calibration_default) {
- int16_t error;
- uint16_t asc_enabled;
- error = scd4x_get_automatic_self_calibration(&asc_enabled);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_automatic_self_calibration");
- printf("asc_enabled: %i\n", asc_enabled);
- CHECK_EQUAL_TEXT(asc_enabled, 1, "ASC should be enabled by default");
+TEST (SCD4X_Tests, test_get_automatic_self_calibration_target1) {
+ int16_t local_error = 0;
+ uint16_t asc_target = 0;
+ local_error = scd4x_get_automatic_self_calibration_target(&asc_target);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_automatic_self_calibration_target");
+ printf("asc_target: %u\n", asc_target);
}
-TEST (SCD4X_Tests, SCD4X_Test_set_automatic_self_calibration) {
- int16_t error;
- uint16_t asc_enabled = 0;
- error = scd4x_set_automatic_self_calibration(asc_enabled);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_set_automatic_self_calibration");
-
- error = scd4x_get_automatic_self_calibration(&asc_enabled);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_automatic_self_calibration");
- printf("asc_enabled: %i\n", asc_enabled);
- CHECK_EQUAL_TEXT(asc_enabled, 0, "ASC should be set correctly");
+TEST (SCD4X_Tests, test_persist_settings1) {
+ int16_t local_error = 0;
+ local_error = scd4x_persist_settings();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "persist_settings");
}
-TEST (SCD4X_Tests, SCD4X_Test_start_low_power_periodic_measurement) {
- int16_t error;
- error = scd4x_start_low_power_periodic_measurement();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_start_low_power_periodic_measurement");
-
- sensirion_i2c_hal_sleep_usec(3000000);
-
- uint16_t co2;
- uint16_t temperature;
- uint16_t humidity;
- error = scd4x_read_measurement_ticks(&co2, &temperature, &humidity);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_read_measurement_ticks");
-
- printf("co2: %i\n", co2);
- printf("temperature: %i\n", temperature);
- printf("humidity: %i\n", humidity);
-
- error = scd4x_stop_periodic_measurement();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_stop_periodic_measurement");
+TEST (SCD4X_Tests, test_perform_self_test1) {
+ int16_t local_error = 0;
+ uint16_t sensor_status = 0;
+ local_error = scd4x_perform_self_test(&sensor_status);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "perform_self_test");
+ printf("sensor_status: %u\n", sensor_status);
}
-TEST (SCD4X_Tests, SCD4X_Test_get_data_ready_flag) {
- int16_t error;
- bool data_ready;
- error = scd4x_get_data_ready_flag(&data_ready);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_data_ready_flag");
- printf("data_ready: %i\n", data_ready);
+TEST (SCD4X_Tests, test_perform_factory_reset1) {
+ int16_t local_error = 0;
+ local_error = scd4x_perform_factory_reset();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "perform_factory_reset");
}
-/*
- * Persist settings may break the test
-TEST (SCD4X_Tests, SCD4X_Test_persist_settings) {
- int16_t error;
- error = scd4x_persist_settings();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_persist_settings");
+TEST (SCD4X_Tests, test_reinit1) {
+ int16_t local_error = 0;
+ local_error = scd4x_reinit();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "reinit");
}
-*/
-TEST (SCD4X_Tests, SCD4X_Test_get_serial_number) {
- int16_t error;
- uint16_t serial_0;
- uint16_t serial_1;
- uint16_t serial_2;
- error = scd4x_get_serial_number(&serial_0, &serial_1, &serial_2);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_get_serial_number");
- printf("serial_0: %i\n", serial_0);
- printf("serial_1: %i\n", serial_1);
- printf("serial_2: %i\n", serial_2);
+TEST (SCD4X_Tests, test_get_sensor_variant_raw1) {
+ int16_t local_error = 0;
+ uint16_t sensor_variant = 0;
+ local_error = scd4x_get_sensor_variant_raw(&sensor_variant);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_sensor_variant_raw");
+ printf("sensor_variant: %u\n", sensor_variant);
}
-TEST (SCD4X_Tests, SCD4X_Test_perform_self_test) {
- int16_t error;
- uint16_t sensor_status;
- error = scd4x_perform_self_test(&sensor_status);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_perform_self_test");
- printf("sensor_status: %i\n", sensor_status);
+TEST (SCD4X_Tests, test_get_sensor_variant1) {
+ int16_t local_error = 0;
+ scd4x_sensor_variant a_sensor_variant = SCD4X_SENSOR_VARIANT_UNKNOWN;
+ local_error = scd4x_get_sensor_variant(&a_sensor_variant);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_sensor_variant");
+ printf("a_sensor_variant: %i\n", a_sensor_variant);
}
-/*
- * Continous factory reset may break the device
-TEST (SCD4X_Tests, SCD4X_Test_perform_factory_reset) {
- int16_t error;
- error = scd4x_perform_factory_reset();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_perform_factory_reset");
+TEST (SCD4X_Tests, test_set_automatic_self_calibration_initial_period1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_automatic_self_calibration_initial_period(44);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "set_automatic_self_calibration_initial_period");
}
-*/
-TEST (SCD4X_Tests, SCD4X_Test_reinit) {
- int16_t error;
- error = scd4x_reinit();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_reinit");
+TEST (SCD4X_Tests, test_get_automatic_self_calibration_initial_period1) {
+ int16_t local_error = 0;
+ uint16_t asc_initial_period = 0;
+ local_error = scd4x_get_automatic_self_calibration_initial_period(
+ &asc_initial_period);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "get_automatic_self_calibration_initial_period");
+ printf("asc_initial_period: %u\n", asc_initial_period);
}
-TEST (SCD4X_Tests, SCD4X_Test_measure_single_shot) {
- int16_t error;
- error = scd4x_measure_single_shot();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_measure_single_shot");
-
- uint16_t co2;
- uint16_t temperature;
- uint16_t humidity;
- error = scd4x_read_measurement_ticks(&co2, &temperature, &humidity);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_read_measurement_ticks");
-
- printf("co2: %i\n", co2);
- printf("temperature: %i\n", temperature);
- printf("humidity: %i\n", humidity);
+TEST (SCD4X_Tests, test_set_automatic_self_calibration_standard_period1) {
+ int16_t local_error = 0;
+ local_error = scd4x_set_automatic_self_calibration_standard_period(156);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "set_automatic_self_calibration_standard_period");
}
-TEST (SCD4X_Tests, SCD4X_Test_measure_single_shot_rht_only) {
- int16_t error;
- error = scd4x_measure_single_shot_rht_only();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_measure_single_shot_rht_only");
-
- uint16_t co2;
- uint16_t temperature;
- uint16_t humidity;
- error = scd4x_read_measurement_ticks(&co2, &temperature, &humidity);
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_read_measurement_ticks");
-
- printf("co2: %i\n", co2);
- printf("temperature: %i\n", temperature);
- printf("humidity: %i\n", humidity);
-
- CHECK_EQUAL_TEXT(co2, 0, "CO2 should be zero in rht only measurement");
+TEST (SCD4X_Tests, test_get_automatic_self_calibration_standard_period1) {
+ int16_t local_error = 0;
+ uint16_t asc_standard_period = 0;
+ local_error = scd4x_get_automatic_self_calibration_standard_period(
+ &asc_standard_period);
+ CHECK_EQUAL_ZERO_TEXT(local_error,
+ "get_automatic_self_calibration_standard_period");
+ printf("asc_standard_period: %u\n", asc_standard_period);
}
-TEST (SCD4X_Tests, SCD4X_Test_power_down) {
- int16_t error;
- error = scd4x_power_down();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_power_down");
+TEST (SCD4X_Tests, test_measure_single_shot_rht_only1) {
+ int16_t local_error = 0;
+ local_error = scd4x_measure_single_shot_rht_only();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "measure_single_shot_rht_only");
+ local_error = scd4x_read_measurement_raw(&co2_concentration, &temperature,
+ &relative_humidity);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "read_measurement_raw");
+ printf("co2_concentration: %u ", co2_concentration);
+ printf("temperature: %u ", temperature);
+ printf("relative_humidity: %u\n", relative_humidity);
+}
- sensirion_i2c_hal_sleep_usec(20000);
+TEST (SCD4X_Tests, test_measure_single_shot1) {
+ int16_t local_error = 0;
+ local_error = scd4x_measure_single_shot();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "measure_single_shot");
+ local_error = scd4x_read_measurement_raw(&co2_concentration, &temperature,
+ &relative_humidity);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "read_measurement_raw");
+ printf("co2_concentration: %u ", co2_concentration);
+ printf("temperature: %u ", temperature);
+ printf("relative_humidity: %u\n", relative_humidity);
+}
- error = scd4x_wake_up();
- printf("error: %i\n", error);
- CHECK_EQUAL_ZERO_TEXT(error, "wake-up should not forward error");
+TEST (SCD4X_Tests, test_start_periodic_measurement1) {
+ int16_t local_error = 0;
+ uint16_t co2_concentration = 0;
+ uint16_t temperature = 0;
+ uint16_t relative_humidity = 0;
+ uint32_t a_ambient_pressure = 0;
+ uint16_t ambient_pressure = 0;
+ bool arg_0 = false;
+ uint16_t data_ready_status = 0;
+ local_error = scd4x_start_periodic_measurement();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "start_periodic_measurement");
+ // wait for measurement
+ sensirion_hal_sleep_us(5000000);
+ local_error = scd4x_get_data_ready_status(&arg_0);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_data_ready_status");
+ printf("arg_0: %d\n", arg_0);
+ local_error = scd4x_get_data_ready_status_raw(&data_ready_status);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_data_ready_status_raw");
+ printf("data_ready_status: %u\n", data_ready_status);
+ local_error = scd4x_read_measurement_raw(&co2_concentration, &temperature,
+ &relative_humidity);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "read_measurement_raw");
+ printf("co2_concentration: %u ", co2_concentration);
+ printf("temperature: %u ", temperature);
+ printf("relative_humidity: %u\n", relative_humidity);
+ local_error = scd4x_set_ambient_pressure(101300);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_ambient_pressure");
+ local_error = scd4x_get_ambient_pressure(&a_ambient_pressure);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_ambient_pressure");
+ printf("a_ambient_pressure: %u\n", a_ambient_pressure);
+ local_error = scd4x_set_ambient_pressure_raw(1013);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_ambient_pressure_raw");
+ local_error = scd4x_get_ambient_pressure_raw(&ambient_pressure);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_ambient_pressure_raw");
+ printf("ambient_pressure: %u\n", ambient_pressure);
+ local_error = scd4x_stop_periodic_measurement();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "stop_periodic_measurement");
}
-TEST (SCD4X_Tests, SCD4X_Test_wake_up) {
- int16_t error;
- error = scd4x_wake_up();
- CHECK_EQUAL_ZERO_TEXT(error, "scd4x_wake_up");
+TEST (SCD4X_Tests, test_start_low_power_periodic_measurement1) {
+ int16_t local_error = 0;
+ uint16_t co2_concentration = 0;
+ uint16_t temperature = 0;
+ uint16_t relative_humidity = 0;
+ uint32_t a_ambient_pressure = 0;
+ uint16_t ambient_pressure = 0;
+ bool arg_0 = false;
+ uint16_t data_ready_status = 0;
+ local_error = scd4x_start_low_power_periodic_measurement();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "start_low_power_periodic_measurement");
+ local_error = scd4x_read_measurement_raw(&co2_concentration, &temperature,
+ &relative_humidity);
+ // as we do not wait the read measurement command returns with nack/error
+ CHECK_EQUAL_TEXT(local_error, 1, "read_measurement_raw");
+ local_error = scd4x_set_ambient_pressure(101300);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_ambient_pressure");
+ local_error = scd4x_get_ambient_pressure(&a_ambient_pressure);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_ambient_pressure");
+ printf("a_ambient_pressure: %u\n", a_ambient_pressure);
+ local_error = scd4x_set_ambient_pressure_raw(1013);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "set_ambient_pressure_raw");
+ local_error = scd4x_get_ambient_pressure_raw(&ambient_pressure);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_ambient_pressure_raw");
+ printf("ambient_pressure: %u\n", ambient_pressure);
+ local_error = scd4x_get_data_ready_status(&arg_0);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_data_ready_status");
+ printf("arg_0: %d\n", arg_0);
+ local_error = scd4x_get_data_ready_status_raw(&data_ready_status);
+ CHECK_EQUAL_ZERO_TEXT(local_error, "get_data_ready_status_raw");
+ printf("data_ready_status: %u\n", data_ready_status);
+ local_error = scd4x_stop_periodic_measurement();
+ CHECK_EQUAL_ZERO_TEXT(local_error, "stop_periodic_measurement");
}
diff --git a/tests/sensirion_test_setup.cpp b/tests/sensirion_test_setup.cpp
index 22dbb6e..e47f022 100644
--- a/tests/sensirion_test_setup.cpp
+++ b/tests/sensirion_test_setup.cpp
@@ -1,5 +1,21 @@
+#include "sensirion_test_setup.h"
#include "CppUTest/CommandLineTestRunner.h"
+#include "sensirion_i2c_hal.h"
+
+#ifdef USE_MUX
+#include "i2c_mux.h"
+#define INIT_TESTBED(x, y) sensirion_i2c_mux_set_single_channel((x), (y))
+#else
+#define INIT_TESTBED(x, y) 0
+#endif
+
+#define MUX_CHANNEL 0x71
int main(int argc, char** argv) {
- return CommandLineTestRunner::RunAllTests(argc, argv);
+ sensirion_i2c_hal_init();
+ int16_t error = INIT_TESTBED(MUX_CHANNEL, 1);
+ CHECK_EQUAL_ZERO_TEXT(error, "test-bed initialization failed");
+ int result = CommandLineTestRunner::RunAllTests(argc, argv);
+ sensirion_i2c_hal_free();
+ return result;
}