From cb1e7c2c4551515c027f88badeb32525036dc14b Mon Sep 17 00:00:00 2001 From: Aitor Mejias Date: Thu, 28 Jan 2016 10:12:19 +0100 Subject: [PATCH] Added VOC (iAQ-Core) drivers and test application --- examples/zolertia/zoul/Makefile | 4 +- examples/zolertia/zoul/test-iaq.c | 112 +++++++++++++++++ platform/zoul/dev/iaq.c | 202 ++++++++++++++++++++++++++++++ platform/zoul/dev/iaq.h | 125 ++++++++++++++++++ 4 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 examples/zolertia/zoul/test-iaq.c create mode 100644 platform/zoul/dev/iaq.c create mode 100644 platform/zoul/dev/iaq.h diff --git a/examples/zolertia/zoul/Makefile b/examples/zolertia/zoul/Makefile index a0a8dee0d..fe3a6ddf8 100644 --- a/examples/zolertia/zoul/Makefile +++ b/examples/zolertia/zoul/Makefile @@ -3,12 +3,12 @@ DEFINES+=PROJECT_CONF_H=\"project-conf.h\" CONTIKI_PROJECT = zoul-demo test-tsl2563 test-sht25 test-pwm test-power-mgmt CONTIKI_PROJECT += test-bmp085-bmp180 test-motion test-rotation-sensor CONTIKI_PROJECT += test-grove-light-sensor test-grove-loudness-sensor -CONTIKI_PROJECT += test-weather-meter test-grove-gyro test-lcd +CONTIKI_PROJECT += test-weather-meter test-grove-gyro test-lcd test-iaq CONTIKI_PROJECT += test-pm10-sensor test-vac-sensor test-aac-sensor CONTIKI_TARGET_SOURCEFILES += tsl2563.c sht25.c bmpx8x.c motion-sensor.c CONTIKI_TARGET_SOURCEFILES += adc-sensors.c weather-meter.c grove-gyro.c -CONTIKI_TARGET_SOURCEFILES += rgb-bl-lcd.c pm10-sensor.c +CONTIKI_TARGET_SOURCEFILES += rgb-bl-lcd.c pm10-sensor.c iaq.c all: $(CONTIKI_PROJECT) diff --git a/examples/zolertia/zoul/test-iaq.c b/examples/zolertia/zoul/test-iaq.c new file mode 100644 index 000000000..147ecd8a7 --- /dev/null +++ b/examples/zolertia/zoul/test-iaq.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016, Zolertia - http://www.zolertia.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup remote-examples + * @{ + * \defgroup remote-iaq-test + * + * RE-Mote external IAQ test application + * Example of iAQ-Core implementation and simple operation reading the value + * of CO2, TVOC sensor and Status. The test checks for a each 5 minutes in + * order to get the first true measurement as datasheet recomendation + * (standard result of 0x82 is obtained in first time). + * Then, once initialized, periodically each 5 seconds reads + * the values of the IAQ sensor and shows in the screen, toggling the LED + * red if CO2 was not initialized and LED green if the reading was succeed. + * + * @{ + * \file + * RE-Mote implementation of external IAQ-CORE-C test application + * \author + * Aitor Mejias + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "iaq.h" +#include "dev/i2c.h" +#include "dev/leds.h" +#include +#include +/*---------------------------------------------------------------------------*/ +/* Standard warm up time iAQ Sensor */ +#define IAQ_INIT_WAIT 325L +#define LOOP_PERIOD 5L +#define LOOP_INTERVAL (CLOCK_SECOND * LOOP_PERIOD) +/*---------------------------------------------------------------------------*/ +PROCESS(test_remote_iaq_process, "Test IAQ driver process"); +AUTOSTART_PROCESSES(&test_remote_iaq_process); +/*---------------------------------------------------------------------------*/ +static struct etimer et; +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(test_remote_iaq_process, ev, data) +{ + static uint16_t count_delay = 0; + static uint16_t status = 0; + + PROCESS_BEGIN(); + + /* Configure IAQ and return structure with all parameters */ + SENSORS_ACTIVATE(iaq); + + while(1) { + /* Wait a bit */ + etimer_set(&et, (LOOP_INTERVAL)); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + status = iaq.status(IAQ_DRIVER_STATUS); + + if(status == IAQ_INIT_STATE) { + count_delay += LOOP_PERIOD; + leds_toggle(LEDS_RED); + printf("Test-IAQ: Initializing Time-elapsed: %u seconds of aprox. %lu sec.\n", + count_delay, IAQ_INIT_WAIT); + } else if(status == IAQ_ACTIVE) { + leds_off(LEDS_RED); + leds_toggle(LEDS_GREEN); + + /* Get data from sensor: VOC, CO2 and internal status */ + printf("CO2 current value is: %d ppm\n", iaq.value(IAQ_VOC_VALUE)); + printf("TIAQ current value is: %d ppb\n", iaq.value(IAQ_CO2_VALUE)); + printf("Status is: 0x%0X\n", iaq.value(IAQ_STATUS)); + } + else { + printf("iAQ-Core Error: 0x%02X\n", status); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ + diff --git a/platform/zoul/dev/iaq.c b/platform/zoul/dev/iaq.c new file mode 100644 index 000000000..7bc929a26 --- /dev/null +++ b/platform/zoul/dev/iaq.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Zolertia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup zoul-iaq-sensor + * @{ + * Driver for the RE-Mote IAQ iAQ-Core (Indoor Air Quality Sensor) + * \file + * Driver for the RE-Mote RF IAQ iAQ-Core sensor (IAQ) + * \author + * Aitor Mejias + */ +/*---------------------------------------------------------------------------*/ +#include +#include "contiki.h" +#include "dev/gpio.h" +#include "dev/i2c.h" +#include "iaq.h" +#include "sys/timer.h" +#include "sys/etimer.h" +#include "lib/sensors.h" +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/* Callback pointers when interrupt occurs */ +void (*iaq_enable_callback)(uint16_t value); +/*---------------------------------------------------------------------------*/ +static int16_t enabled; +/*---------------------------------------------------------------------------*/ +static struct etimer et; +static simple_iaq_data iaq_data; +static uint8_t iaq_buffer[IAQ_FRAME_SIZE+1]; +/*---------------------------------------------------------------------------*/ +PROCESS(iaq_process, "IAQ process handler"); +/*---------------------------------------------------------------------------*/ +static int +status(int type) +{ +/* Return the status of the iAQ-Core or the status of the driver */ + if (type == IAQ_STATUS) { + return (uint16_t)iaq_data.status; + } else if (type == IAQ_DRIVER_STATUS) { + return enabled; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(iaq_process, ev, data) +{ + #if DEBUG + uint8_t i = 0; + #endif + + PROCESS_EXITHANDLER(); + PROCESS_BEGIN(); + i2c_init(I2C_SDA_PORT, I2C_SDA_PIN, I2C_SCL_PORT, I2C_SCL_PIN, + I2C_SCL_NORMAL_BUS_SPEED); + + while(1) { + etimer_set(&et, (IAQ_POLLING_TIME)); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + i2c_master_enable(); + if(i2c_burst_receive(IAQ_ADDR, &iaq_buffer[0], IAQ_FRAME_SIZE) != + I2C_MASTER_ERR_NONE) { + PRINTF("IAQ: Failed to retrieve data from IAQ\n"); + enabled = IAQ_ERROR; + iaq_data.status = IAQ_INTERNAL_ERROR; + } else { + #if DEBUG + PRINTF("IAQ: Buffer "); + for (i=1;i<10;i++) { + PRINTF("[%d] %x, ", i-1, iaq_buffer[i-1]); + } + PRINTF("\n"); + #endif + /* Update the status of the sensor. This value readed represents the + internal status of the external driver. */ + switch (iaq_buffer[2]) { + case IAQ_INTERNAL_SUCCESS: + enabled = IAQ_ACTIVE; + break; + case IAQ_INTERNAL_RUNIN: + enabled = IAQ_INIT_STATE; + break; + case IAQ_INTERNAL_BUSY: + case IAQ_INTERNAL_ERROR: + enabled = IAQ_ERROR; + break; + default: + enabled = IAQ_ERROR; + break; + } + + iaq_data.tvoc = ((uint16_t)iaq_buffer[0] << 8) + iaq_buffer[1]; + iaq_data.co2 = ((uint16_t)iaq_buffer[7] << 8) + iaq_buffer[8]; + iaq_data.status = iaq_buffer[2]; + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +static int +value(int type) +{ + if (!enabled) { + PRINTF("IAQ: Sensor not enabled\n"); + return IAQ_ERROR; + } + if (enabled == IAQ_INIT_STATE) { + PRINTF("IAQ: Sensor initializing\n"); + return IAQ_INIT_STATE; + } + if (type == IAQ_CO2_VALUE) { + return iaq_data.co2; + } + if (type == IAQ_VOC_VALUE) { + return iaq_data.tvoc; + } + if (type == IAQ_STATUS) { + #if DEBUG + switch (iaq_data.status) { + case IAQ_INTERNAL_SUCCESS: + PRINTF("IAQ Status: SUCCESS\n"); + break; + case IAQ_INTERNAL_RUNIN: + PRINTF("IAQ Status: WARM UP\n"); + break; + case IAQ_INTERNAL_BUSY: + case IAQ_INTERNAL_ERROR: + PRINTF("IAQ Status: ERROR\n"); + break; + default: + PRINTF("IAQ Status: UNKNOWN STATUS %d\n", iaq_data.status); + break; + } + #endif + return iaq_data.status; + } + + return IAQ_ERROR; +} +/*---------------------------------------------------------------------------*/ +static int +configure(int type, int value) +{ + /* Check the current status. If is initialized or is active, return the same + state */ + if ((enabled == IAQ_INIT_STATE) || (enabled == IAQ_ACTIVE)) { + return IAQ_ERROR; + } + + /* Fix the status in initial wait status */ + enabled = IAQ_INIT_STATE; + + /* Start Internal process to measure the iAQ Sensor */ + process_start(&iaq_process, NULL); + + return enabled; +} +/*---------------------------------------------------------------------------*/ +/* name, type, value, configure, status */ +SENSORS_SENSOR(iaq, IAQ_SENSOR, value, configure, status); +/*---------------------------------------------------------------------------*/ +/** + * @} + */ + diff --git a/platform/zoul/dev/iaq.h b/platform/zoul/dev/iaq.h new file mode 100644 index 000000000..92562dfd7 --- /dev/null +++ b/platform/zoul/dev/iaq.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Zolertia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + */ +/* -------------------------------------------------------------------------- */ +/** + * \addtogroup zoul-sensors + * @{ + * \defgroup zoul-iaq-sensor IAQ driver (Indoor Air Quality) Sensor Module + * IAQ driver RE-Mote Indoor Air Quality Sensor Module + * Driver for the RE-Mote Sensor pack: Air Quality Sensor Module (IAQ) + * @{ + * \file + * Header file for the RE-Mote Sensor IAQ + */ +/* -------------------------------------------------------------------------- */ +#ifndef IAQ_H_ +#define IAQ_H_ +/* -------------------------------------------------------------------------- */ +#include +#include "lib/sensors.h" +#include "dev/zoul-sensors.h" +#include "iaq.h" +#include "i2c.h" +#include "sys/timer.h" +#include "sys/rtimer.h" +/* -------------------------------------------------------------------------- */ +/** \name IAQ address and definition + * @{ + */ +/* Address of the sensor: 1011010(1) Addr (R/W bit) */ +#define IAQ_ADDR 0x5A +#define IAQ_SENSOR "iAQ" +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name IAQ sensor types in iAQ-Core module + * @{ + */ +extern const struct sensors_sensor iaq; +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name IAQ error values and definitions + * @{ + */ +#define IAQ_ACTIVE SENSORS_ACTIVE +#define IAQ_INIT_STATE SENSORS_HW_INIT +#define IAQ_ERROR (-1) +#define IAQ_SUCCESS 0x00 +#define IAQ_FRAME_SIZE 0x09 + +/* Variables used by external driver to get the state */ +#define IAQ_INTERNAL_SUCCESS 0x00 +#define IAQ_INTERNAL_RUNIN 0x10 +#define IAQ_INTERNAL_BUSY 0x01 +#define IAQ_INTERNAL_ERROR 0x80 + +/* Value types for the sensor readings */ +#define IAQ_CO2_VALUE 0x00 +#define IAQ_VOC_VALUE 0x01 +#define IAQ_STATUS 0x02 +#define IAQ_DRIVER_STATUS 0x03 + +/* Definition that corresponds with the two models of iAQ Sensor */ +#ifdef IAQ_PULSE_MODE +#define IAQ_POLLING_TIME (CLOCK_SECOND * 11) +#else +#define IAQ_POLLING_TIME (CLOCK_SECOND) +#endif +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name IAQ enumeration and options + * @{ + */ +enum { + IAQ_INIT = 0, + IAQ_STARTED, +}; +/** @} */ +/* -------------------------------------------------------------------------- */ +/** \name Readable IAQ-Core interface result conversion implementation as + * datasheet specification. + * + * @{ + */ +typedef struct iaq_struct_simple_td_reg { + uint16_t co2; + uint8_t status; + int32_t resistance; + uint16_t tvoc; +} __attribute__ ((packed)) simple_iaq_data; +/** @} */ +/* -------------------------------------------------------------------------- */ +#endif +/* -------------------------------------------------------------------------- */ +/** + * @} + * @} + */