From 4553956ac52981af8dfaae8610449fbe87296d3b Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Mon, 9 Jul 2018 13:21:04 +0200 Subject: [PATCH 1/4] Use absolute URL for submodule The relative URL was wrong plus absolute URL solves the issue of someone forking the driver without the submodule. Uses HTTPS as protocol. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 370116a..81448cc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "embedded-common"] path = embedded-common - url = ./embedded-common + url = https://github.com/Sensirion/embedded-common.git From 3d940e276310f72833878f5387509579ab07bb9c Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Mon, 2 Jul 2018 08:30:45 +0200 Subject: [PATCH 2/4] Initial files --- AUTHORS | 1 + LICENSE | 29 +++++++++++++++++++++++++++++ README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 README.md diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..68d4553 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Andreas Brauchli diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c779ef9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, 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 the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c8b52a --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# embedded-scd +This repository contains the embedded driver sources for Sensirion's SCD product +line. + +## Clone this repository +``` + git clone --recursive https://github.com/Sensirion/embedded-scd.git +``` + +## Repository content +* embedded-common (submodule repository for the common embedded driver HAL) +* scd30 (SCD30 driver related) + +## Collecting resources +``` +make release +``` +This will create the `release` folder with the necessary driver files in it, +including a Makefile. That way, you have just one folder with all the sources +ready to build your driver for your platform. + +## Files to adjust (from embedded-common) +You only need to touch the following files: + +* `sensirion_arch_config.h` (architecture specifics, you need to specify +the integer sizes) + +and depending on your i2c implementation either of the following: + +* `embedded-common/hw_i2c/sensirion_hw_i2c_implementation.c` + functions for hardware i2c communication if your platform supports that +* `embedded-common/sw_i2c/sensirion_sw_i2c_implementation.c` + functions for software i2c communication via GPIOs + +## Building the driver +1. Adjust sensirion\_arch\_config.h if you don't have the `` header + file available +2. Implement necessary functions in one of the `*_implementation.c` files + described above +3. make + +--- + +Please check the [embedded-common](https://github.com/Sensirion/embedded-common) +repository for further information and sample implementations. + +--- From edbab4fa847e6e0a7f23b3204eccea4b88f01fee Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Fri, 6 Jul 2018 13:20:17 +0200 Subject: [PATCH 3/4] Update embedded-common --- embedded-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedded-common b/embedded-common index 25a9ebe..7664d77 160000 --- a/embedded-common +++ b/embedded-common @@ -1 +1 @@ -Subproject commit 25a9ebe3f336d81954d227d56420f18ff5c93915 +Subproject commit 7664d77cab3305d4e6125b89d7814f8379ddd22d From f57d29cff53d7f87b46f9162043c2996c6cc82f1 Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Mon, 2 Jul 2018 08:31:01 +0200 Subject: [PATCH 4/4] Initial scd30 driver --- .gitignore | 5 + Makefile | 42 ++++++ scd30/Makefile | 42 ++++++ scd30/scd30.c | 291 ++++++++++++++++++++++++++++++++++++ scd30/scd30.h | 175 ++++++++++++++++++++++ scd30/scd30_example_usage.c | 97 ++++++++++++ scd30/scd_git_version.h | 36 +++++ 7 files changed, 688 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 scd30/Makefile create mode 100644 scd30/scd30.c create mode 100644 scd30/scd30.h create mode 100644 scd30/scd30_example_usage.c create mode 100644 scd30/scd_git_version.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..277ce41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +/release +/scd30/scd_git_version.c +/scd30/scd30_example_usage_hw_i2c +/scd30/scd30_example_usage_sw_i2c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7dadd28 --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +drivers=scd30 +clean_drivers=$(foreach d, $(drivers), clean_$(d)) +release_drivers=$(foreach d, $(drivers), release/$(d)) + +.PHONY: FORCE all $(release_drivers) $(clean_drivers) + +all: $(drivers) + +$(drivers): scd30/scd_git_version.c FORCE + cd $@ && $(MAKE) $(MFLAGS) + +scd30/scd_git_version.c: FORCE + git describe --always --dirty | \ + awk 'BEGIN \ + {print "/* THIS FILE IS AUTOGENERATED */"} \ + {print "#include \"scd_git_version.h\""} \ + {print "const char * SCD_DRV_VERSION_STR = \"" $$0"\";"} \ + END {}' > $@ + +$(release_drivers): scd30/scd_git_version.c + export rel=$@ && \ + export driver=$${rel#release/} && \ + export tag="$$(git describe --always --dirty)" && \ + export pkgname="$${driver}-$${tag}" && \ + export pkgdir="release/$${pkgname}" && \ + rm -rf "$${pkgdir}" && mkdir -p "$${pkgdir}" && \ + cp -r embedded-common/* "$${pkgdir}" && \ + cp -r $${driver}/* "$${pkgdir}" && \ + perl -pi -e 's/^sensirion_common_dir :=.*$$/sensirion_common_dir := ./' "$${pkgdir}/Makefile" && \ + cd "$${pkgdir}" && $(MAKE) $(MFLAGS) && $(MAKE) clean $(MFLAGS) && cd - && \ + cd release && zip -r "$${pkgname}.zip" "$${pkgname}" && cd - && \ + ln -sf $${pkgname} $@ + +release: clean $(release_drivers) + +$(clean_drivers): + export rel=$@ && \ + export driver=$${rel#clean_} && \ + cd $${driver} && $(MAKE) clean $(MFLAGS) && cd - + +clean: $(clean_drivers) + rm -rf release scd30/scd_git_version.c diff --git a/scd30/Makefile b/scd30/Makefile new file mode 100644 index 0000000..89123a3 --- /dev/null +++ b/scd30/Makefile @@ -0,0 +1,42 @@ +sensirion_common_dir := ../embedded-common +scd_common_dir := . +sw_i2c_dir := ${sensirion_common_dir}/sw_i2c +hw_i2c_dir := ${sensirion_common_dir}/hw_i2c + +CFLAGS := -Os -Wall -Werror -I. -I${sensirion_common_dir} + +sensirion_common_objects := sensirion_common.o +scd_common_objects := scd_git_version.o +scd30_binaries := scd30_example_usage_sw_i2c scd30_example_usage_hw_i2c +scd_binaries += ${scd30_binaries} + +sw_objects := sensirion_sw_i2c.o sensirion_sw_i2c_implementation.o +hw_objects := sensirion_hw_i2c_implementation.o +all_objects := ${sensirion_common_objects} ${scd_common_objects} ${hw_objects} ${sw_objects} scd30.o + +.PHONY: all + +all: ${scd_binaries} + +scd_git_version.o: ${scd_common_dir}/scd_git_version.c + $(CC) $(CFLAGS) -c -o $@ $^ +sensirion_common.o: ${sensirion_common_dir}/sensirion_common.c + $(CC) $(CFLAGS) -c -o $@ $^ +sensirion_sw_i2c_implementation.o: ${sw_i2c_dir}/sample-implementations/linux_user_space/sensirion_sw_i2c_implementation.c + $(CC) -I${sw_i2c_dir} $(CFLAGS) -c -o $@ $^ +sensirion_hw_i2c_implementation.o: ${hw_i2c_dir}/sensirion_hw_i2c_implementation.c + $(CC) $(CFLAGS) -c -o $@ $^ + +sensirion_sw_i2c.o: ${sw_i2c_dir}/sensirion_sw_i2c.c + $(CC) -I${sw_i2c_dir} $(CFLAGS) -c -o $@ $^ + +scd30.o: ${sensirion_common_dir}/sensirion_arch_config.h ${sensirion_common_dir}/sensirion_i2c.h ${scd_common_dir}/scd_git_version.c scd30.h scd30.c + +scd30_example_usage_sw_i2c: ${sensirion_common_objects} ${scd_common_objects} ${sw_objects} scd30.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) scd30_example_usage.c + +scd30_example_usage_hw_i2c: ${sensirion_common_objects} ${scd_common_objects} ${hw_objects} scd30.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) scd30_example_usage.c + +clean: + $(RM) ${all_objects} ${scd_binaries} diff --git a/scd30/scd30.c b/scd30/scd30.c new file mode 100644 index 0000000..5212c84 --- /dev/null +++ b/scd30/scd30.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2018, 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_arch_config.h" +#include "sensirion_i2c.h" +#include "sensirion_common.h" +#include "scd_git_version.h" +#include "scd30.h" + + +#ifdef SCD_ADDRESS +static const u8 SCD_I2C_ADDRESS = SCD_ADDRESS; +#else +static const u8 SCD_I2C_ADDRESS = 0x61; +#endif + +#define SCD_CMD_START_PERIODIC_MEASUREMENT 0x0010 +#define SCD_CMD_STOP_PERIODIC_MEASUREMENT 0x0104 +#define SCD_CMD_READ_MEASUREMENT 0x0300 +#define SCD_CMD_SET_MEASUREMENT_INTERVAL 0x4600 +#define SCD_CMD_GET_DATA_READY 0x0202 +#define SCD_CMD_SET_TEMPERATURE_OFFSET 0x5403 +#define SCD_CMD_SET_ALTITUDE 0x5102 + +#define SCD_WORD_LEN 2 +#define SCD_COMMAND_LEN 2 +#define SCD_MAX_BUFFER_WORDS 24 + + +/** + * scd_i2c_read_words() - read data words from sensor + * @data: Allocated buffer to store the read data. + * The buffer may also have been modified on STATUS_FAIL return. + * @data_words: Number of data words to read (without CRC bytes) + * + * Return: STATUS_OK on success, an error code otherwise + */ +static s16 scd_i2c_read_words(u16 *data, u16 data_words) { + s16 ret; + u16 i, j; + u16 size = data_words * (SCD_WORD_LEN + CRC8_LEN); + u16 word_buf[SCD_MAX_BUFFER_WORDS]; + u8 * const buf8 = (u8 *)word_buf; + + ret = sensirion_i2c_read(SCD_I2C_ADDRESS, buf8, size); + if (ret != STATUS_OK) + return ret; + + /* check the CRC for each word */ + for (i = 0, j = 0; + i < size; + i += SCD_WORD_LEN + CRC8_LEN, j += SCD_WORD_LEN) { + + if (sensirion_common_check_crc(&buf8[i], SCD_WORD_LEN, + buf8[i + SCD_WORD_LEN]) == STATUS_FAIL) { + return STATUS_FAIL; + } + ((u8 *)data)[j] = buf8[i]; + ((u8 *)data)[j + 1] = buf8[i + 1]; + } + + return STATUS_OK; +} + + +/** + * scd_fill_cmd_send_buf() - create the i2c send buffer for a command and a set + * of argument words. + * The output buffer interleaves argument words with + * their checksums. + * @buf: The generated buffer to send over i2c. Then buffer length must + * be at least SCD_COMMAND_LEN + num_args * (SCD_WORD_LEN + + * CRC8_LEN). + * @cmd: The i2c command to send. It already includes a checksum. + * @args: The arguments to the command. Can be NULL if none. + * @num_args: The number of word arguments in args. + */ +static void scd_fill_cmd_send_buf(u8 *buf, u16 cmd, const u16 *args, + u8 num_args) { + u16 word; + u8 crc; + u8 i; + u8 idx = 0; + + buf[idx++] = (u8)((cmd & 0xFF00) >> 8); + buf[idx++] = (u8)((cmd & 0x00FF) >> 0); + + for (i = 0; i < num_args; ++i) { + word = be16_to_cpu(args[i]); + crc = sensirion_common_generate_crc((u8 *)&word, SCD_WORD_LEN); + + buf[idx++] = (u8)((word & 0x00FF) >> 0); + buf[idx++] = (u8)((word & 0xFF00) >> 8); + buf[idx++] = crc; + } +} + + +/** + * scd_i2c_write() - writes to the sensor + * @command: Sensor command + * + * Return: STATUS_OK on success, an error code otherwise + */ +static s16 scd_i2c_write(u16 command) { + u8 buf[SCD_COMMAND_LEN]; + + scd_fill_cmd_send_buf(buf, command, NULL, 0); + return sensirion_i2c_write(SCD_I2C_ADDRESS, buf, SCD_COMMAND_LEN); +} + + +/** + * scd_i2c_read_words_from_cmd() - reads data words from the sensor after a + * command has been issued + * @cmd: Command + * @data_words: Allocated buffer to store the read data + * @num_words: Data words to read (without CRC bytes) + * + * Return: STATUS_OK on success, an error code otherwise + */ +static s16 scd_i2c_read_words_from_cmd(u16 cmd, u16 *data_words, + u16 num_words) { + + s16 ret = scd_i2c_write(cmd); + + if (ret != STATUS_OK) + return ret; + + return scd_i2c_read_words(data_words, num_words); +} + + +s16 scd_start_periodic_measurement(u16 ambient_pressure_mbar) { + const u16 BUF_SIZE = SCD_COMMAND_LEN + SCD_WORD_LEN + CRC8_LEN; + u8 buf[BUF_SIZE]; + + if (ambient_pressure_mbar && (ambient_pressure_mbar < 700 || + ambient_pressure_mbar > 1400)) { + /* out of allowable range */ + return STATUS_FAIL; + } + + scd_fill_cmd_send_buf(buf, SCD_CMD_START_PERIODIC_MEASUREMENT, + &ambient_pressure_mbar, + sizeof(ambient_pressure_mbar) / SCD_WORD_LEN); + + return sensirion_i2c_write(SCD_I2C_ADDRESS, buf, BUF_SIZE); +} + + +s16 scd_stop_periodic_measurement() { + return scd_i2c_write(SCD_CMD_STOP_PERIODIC_MEASUREMENT); +} + + +s16 scd_read_measurement(f32 *co2_ppm, f32 *temperature, f32 *humidity) { + s16 ret; + u16 word_buf[6]; /* 2 words for each co2, temperature, humidity */ + union { + u32 raw; + f32 float32; + } tmp; + + ret = scd_i2c_read_words_from_cmd(SCD_CMD_READ_MEASUREMENT, word_buf, + sizeof(word_buf) / SCD_WORD_LEN); + if (ret != STATUS_OK) + return ret; + + tmp.raw = (((u32)be16_to_cpu(word_buf[0])) << 16) | + ((u32)be16_to_cpu(word_buf[1])); + *co2_ppm = tmp.float32; + + tmp.raw = (((u32)be16_to_cpu(word_buf[2])) << 16) | + ((u32)be16_to_cpu(word_buf[3])); + *temperature = tmp.float32; + + tmp.raw = (((u32)be16_to_cpu(word_buf[4])) << 16) | + ((u32)be16_to_cpu(word_buf[5])); + *humidity = tmp.float32; + + return STATUS_OK; +} + + +s16 scd_set_measurement_interval(u16 interval_sec) { + const u16 BUF_SIZE = SCD_COMMAND_LEN + SCD_WORD_LEN + CRC8_LEN; + u8 buf[BUF_SIZE]; + + if (interval_sec < 2 || interval_sec > 1800) { + /* out of allowable range */ + return STATUS_FAIL; + } + + scd_fill_cmd_send_buf(buf, SCD_CMD_SET_MEASUREMENT_INTERVAL, &interval_sec, + sizeof(interval_sec) / SCD_WORD_LEN); + + return sensirion_i2c_write(SCD_I2C_ADDRESS, buf, BUF_SIZE); +} + + +s16 scd_get_data_ready(u16 *data_ready) { + return scd_i2c_read_words_from_cmd(SCD_CMD_GET_DATA_READY, data_ready, + sizeof(*data_ready) / SCD_WORD_LEN); +} + + +s16 scd_set_temperature_offset(u16 temperature_offset) { + const u16 BUF_SIZE = SCD_COMMAND_LEN + SCD_WORD_LEN + CRC8_LEN; + u8 buf[BUF_SIZE]; + + scd_fill_cmd_send_buf(buf, SCD_CMD_SET_TEMPERATURE_OFFSET, + &temperature_offset, + sizeof(temperature_offset) / SCD_WORD_LEN); + + return sensirion_i2c_write(SCD_I2C_ADDRESS, buf, BUF_SIZE); +} + + +s16 scd_set_altitude(u16 altitude) { + const u16 BUF_SIZE = SCD_COMMAND_LEN + SCD_WORD_LEN + CRC8_LEN; + u8 buf[BUF_SIZE]; + + scd_fill_cmd_send_buf(buf, SCD_CMD_SET_ALTITUDE, &altitude, + sizeof(altitude) / SCD_WORD_LEN); + + return sensirion_i2c_write(SCD_I2C_ADDRESS, buf, BUF_SIZE); +} + + +/** + * scd_get_driver_version() - Return the driver version + * Return: Driver version string + */ +const char *scd_get_driver_version() +{ + return SCD_DRV_VERSION_STR; +} + + +/** + * scd_get_configured_address() - returns the configured I2C address + * + * Return: u8 I2C address + */ +u8 scd_get_configured_address() { + return SCD_I2C_ADDRESS; +} + + +/** + * scd_probe() - check if sensor is available + * + * Return: STATUS_OK on success, an error code otherwise + */ +s16 scd_probe() { + u16 data_ready; + + /* Initialize I2C */ + sensirion_i2c_init(); + + /* try to read data-ready state */ + return scd_get_data_ready(&data_ready); +} diff --git a/scd30/scd30.h b/scd30/scd30.h new file mode 100644 index 0000000..c294075 --- /dev/null +++ b/scd30/scd30.h @@ -0,0 +1,175 @@ +/* +* Copyright (c) 2018, 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 SCD30_H +#define SCD30_H +#include "sensirion_arch_config.h" +#include "sensirion_common.h" +#include "sensirion_i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * scd_probe() - check if the SCD sensor is available and initialize it + * + * Return: 0 on success, an error code otherwise. + */ +s16 scd_probe(void); + +/** + * scd_get_driver_version() - Returns the driver version + * Return: Driver version string + */ +const char *scd_get_driver_version(void); + +/** + * scd_get_configured_address() - Returns the configured I2C address + * + * Return: u8 I2C address + */ +u8 scd_get_configured_address(void); + +/** + * scd_start_periodic_measurement() - Start continuous measurement to measure + * CO2 concentration, relative humidity and temperature or updates the ambient + * pressure if the periodic measurement is already running. + * + * Measurement data which is not read from the sensor is continuously + * overwritten. The CO2 measurement value can be compensated for ambient + * pressure by setting the pressure value in mBar. Setting the ambient pressure + * overwrites previous and future settings of altitude compensation. Setting the + * pressure to zero deactivates the ambient pressure compensation. + * The continuous measurement status is saved in non-volatile memory. The last + * measurement mode is resumed after repowering. + * + * @param ambient_pressure_mbar Ambient pressure in millibars. 0 to deactivate + * ambient pressure compensation (reverts to + * altitude compensation, if set), 700-1200mBar + * allowable range otherwise + * @return 0 if the command was successful, an error code + * otherwise + */ +s16 scd_start_periodic_measurement(u16 ambient_pressure_mbar); + +/** + * scd_stop_periodic_measurement() - Stop the continuous measurement + * + * @return 0 if the command was successful, else an error code + */ +s16 scd_stop_periodic_measurement(void); + +/** + * scd_read_measurement() - Read out an available measurement when new + * measurement data is available. + * Make sure that the measurement is completed by reading the data ready status + * bit with scd_get_data_ready(). + * + * @param co2_ppm CO2 concentration in ppm + * @param temperature the address for the result of the temperature + * measurement + * @param humidity the address for the result of the relative humidity + * measurement + * @return 0 if the command was successful, an error code otherwise + */ +s16 scd_read_measurement(f32 *co2_ppm, f32 *temperature, f32 *humidity); + +/** + * scd_set_measurement_interval() - Sets the measurement interval in continuous + * measurement mode. + * + * The initial value on powerup is 2s. The chosen measurement interval is saved + * in non-volatile memory and thus is not reset to its initial value after power + * up. + * + * @param interval_sec The measurement interval in seconds. The allowable range + * is 2-1800s + * @return 0 if the command was successful, an error code otherwise + */ +s16 scd_set_measurement_interval(u16 interval_sec); + +/** + * scd_get_data_ready() - Get data ready status + * + * Data ready command is used to determine if a measurement can be read from the + * sensor's buffer. Whenever there is a measurement available from the internal + * buffer this command returns 1 and 0 otherwise. As soon as the measurement has + * been read by the return value changes to 0. It is recommended to use the data + * ready status byte before readout of the measurement values with + * scd_read_measurement(). + * + * @param data_ready Pointer to memory of where to set the data ready bit. + * The memory is set to 1 if a measurement is ready to be + * fetched, 0 otherwise. + * @return 0 if the command was successful, an error code otherwise + */ +s16 scd_get_data_ready(u16 *data_ready); + +/** + * scd_set_temperature_offset() - Set the temperature offset + * + * The on-board RH/T sensor is influenced by thermal self-heating of SCD30 and + * other electrical components. Design-in alters the thermal properties of SCD30 + * such that temperature and humidity offsets may occur when operating the + * sensor in end-customer devices. Compensation of those effects is achievable + * by writing the temperature offset found in continuous operation of the device + * into the sensor. + * The temperature offset value is saved in non-volatile memory. The last set + * value will be used after repowering. + * + * @param temperature_offset Temperature offset, unit [degrees Celsius * 100] + * i.e. one tick corresponds to 0.01 degrees C + * @return 0 if the command was successful, an error code + * otherwise + */ +s16 scd_set_temperature_offset(u16 temperature_offset); + +/** + * scd_set_altitude() - Set the altitude above sea level + * + * Measurements of CO2 concentration are influenced by altitude. When a value is + * set, the altitude-effect is compensated. The altitude setting is disregarded + * when an ambient pressure is set on the sensor with + * scd_start_periodic_measurement. + * The altitude is saved in non-volatile memory. The last set value will be used + * after repowering. + * + * @param altitude altitude in meters above sea level, 0 meters is the default + * value and disables altitude compensation + * @return 0 if the command was successful, an error code otherwise + */ +s16 scd_set_altitude(u16 altitude); + +#ifdef __cplusplus +} +#endif + +#endif /* SCD30_H */ diff --git a/scd30/scd30_example_usage.c b/scd30/scd30_example_usage.c new file mode 100644 index 0000000..96cd36d --- /dev/null +++ b/scd30/scd30_example_usage.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, 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 "scd30.h" + +/* TO USE CONSOLE OUTPUT (printf) AND WAIT (sleep/usleep) PLEASE ADAPT THEM TO + * YOUR PLATFORM, OR REMOVE THE DEFINES BELOW TO USE AS-IS. + */ +#include /* printf */ +#include /* sleep, usleep */ +#define printf(...) +#define sleep(...) +#define usleep(...) + + +int main(void) +{ + f32 co2_ppm, temperature, relative_humidity; + u16 data_ready; + s16 ret; + s16 interval_in_seconds = 2; + + /* Busy loop for initialization, because the main loop does not work without + * a sensor. + */ + while (scd_probe() != STATUS_OK) { + printf("SCD30 sensor probing failed\n"); + sleep(1); + } + printf("SCD30 sensor probing successful\n"); + + scd_set_measurement_interval(interval_in_seconds); + usleep(20000); + scd_start_periodic_measurement(0); + sleep(interval_in_seconds); + + while (1) { + /* Measure co2, temperature and relative humidity and store into + * variables. + */ + ret = scd_get_data_ready(&data_ready); + if (ret == STATUS_OK) { + if (data_ready) { + ret = scd_read_measurement(&co2_ppm, &temperature, + &relative_humidity); + if (ret != STATUS_OK) { + printf("error reading measurement\n"); + + } else { + printf("measured co2 concentration: %0.2f ppm, " + "measured temperature: %0.2f degreeCelsius, " + "measured humidity: %0.2f %%RH\n", + co2_ppm, temperature, relative_humidity); + } + } else { + printf("measurement not ready\n"); + usleep(20000); + continue; + } + + } else { + printf("error reading data ready flag\n"); + } + + sleep(interval_in_seconds); + } + + scd_stop_periodic_measurement(); + return 0; +} diff --git a/scd30/scd_git_version.h b/scd30/scd_git_version.h new file mode 100644 index 0000000..be80f60 --- /dev/null +++ b/scd30/scd_git_version.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018, 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 GIT_VERSION_H +#define GIT_VERSION_H + +extern const char * SCD_DRV_VERSION_STR; + +#endif /* GIT_VERSION_H */