From 103911f619af93cce70749c99b0b6a129b5d4fe0 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Sun, 17 Jan 2016 00:04:32 +0100 Subject: [PATCH 1/8] Added driver for the Sparkfun's weather meter station --- examples/zolertia/zoul/Makefile | 3 +- examples/zolertia/zoul/test-weather-meter.c | 124 +++++++++ platform/zoul/dev/weather-meter.c | 262 ++++++++++++++++++++ platform/zoul/dev/weather-meter.h | 147 +++++++++++ 4 files changed, 535 insertions(+), 1 deletion(-) create mode 100644 examples/zolertia/zoul/test-weather-meter.c create mode 100644 platform/zoul/dev/weather-meter.c create mode 100644 platform/zoul/dev/weather-meter.h diff --git a/examples/zolertia/zoul/Makefile b/examples/zolertia/zoul/Makefile index 7ead94a69..3cfa30021 100644 --- a/examples/zolertia/zoul/Makefile +++ b/examples/zolertia/zoul/Makefile @@ -3,9 +3,10 @@ DEFINES+=PROJECT_CONF_H=\"project-conf.h\" CONTIKI_PROJECT = zoul-demo test-tsl2563 test-sht25 test-pwm test-power-mgmt CONTIKI_PROJECT += test-bmp085 test-motion test-rotation-sensor CONTIKI_PROJECT += test-grove-light-sensor test-grove-loudness-sensor +CONTIKI_PROJECT += test-weather-meter CONTIKI_TARGET_SOURCEFILES += tsl2563.c sht25.c bmp085.c motion-sensor.c -CONTIKI_TARGET_SOURCEFILES += adc-sensors.c +CONTIKI_TARGET_SOURCEFILES += adc-sensors.c weather-meter.c all: $(CONTIKI_PROJECT) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c new file mode 100644 index 000000000..5f04f4015 --- /dev/null +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, Zolertia - http://www.zolertia.com + * 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. + * + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup zoul-examples + * @{ + * + * \defgroup zoul-weather-meter-test Test the Sparkfun's weather meter + * + * The example application shows how to read data from the anemometer, wind vane + * and rain gauge, on board the Sparkfun's weater meter + * + * @{ + * + * \file + * Test application for the Sparkfun's weather meter + * + * \author + * Antonio Lignan + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "cpu.h" +#include "sys/etimer.h" +#include "dev/leds.h" +#include "dev/weather-meter.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +#define READ_SENSOR_PERIOD CLOCK_SECOND +/*---------------------------------------------------------------------------*/ +static struct etimer et; +/*---------------------------------------------------------------------------*/ +PROCESS(test_weather_meter_sensors, "Test Weather meter sensors"); +AUTOSTART_PROCESSES(&test_weather_meter_sensors); +/*---------------------------------------------------------------------------*/ +static void +rain_callback(uint8_t value) +{ + printf("*** Rain\n"); +} +/*---------------------------------------------------------------------------*/ +static void +wind_speed_callback(uint8_t value) +{ + printf("*** Wind speed\n"); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(test_weather_meter_sensors, ev, data) +{ + PROCESS_BEGIN(); + + static uint32_t rain; + static uint16_t wind_speed; + static uint16_t wind_dir; + + /* Register the callback handler when thresholds are met */ + WEATHER_METER_REGISTER_ANEMOMETER_INT(wind_speed_callback); + WEATHER_METER_REGISTER_RAIN_GAUGE_INT(rain_callback); + + SENSORS_ACTIVATE(weather_meter); + + etimer_set(&et, READ_SENSOR_PERIOD); + + while(1) { + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + rain = weather_meter.value(WEATHER_METER_RAIN_GAUGE); + wind_speed = weather_meter.value(WEATHER_METER_ANEMOMETER); + wind_dir = weather_meter.value(WEATHER_METER_WIND_VANE); + + #if WEATHER_METER_RAIN_RETURN_TICKS + rain *= WEATHER_METER_AUX_RAIN_MM; + if(rain > (WEATHER_METER_AUX_RAIN_MM * 3)) { + printf("Rain: %lu.%lu mm\n", (rain / 10000), (rain % 10000)); + #else + if(rain >= 10) { + printf("Rain: %u.%u mm\n", (rain / 10), (rain % 10)); + #endif + } else { + printf("Rain: 0.%lu mm\n", rain); + } + + printf("Wind direction: %u metres/hour\n", wind_dir); + printf("Wind speed %u\n", wind_speed); + etimer_reset(&et); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + * @} + */ diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c new file mode 100644 index 000000000..bfb99945b --- /dev/null +++ b/platform/zoul/dev/weather-meter.c @@ -0,0 +1,262 @@ +/* + * 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-weather-meter-sensor + * @{ + * + * The Sparkfun's weather meter comprises an anemometer, wind vane and rain + * gauge, see https://www.sparkfun.com/products/8942 + * + * \file + * Weather meter sensor driver + * \author + * Antonio Lignan + */ +/*---------------------------------------------------------------------------*/ +#include +#include "contiki.h" +#include "dev/adc-sensors.h" +#include "dev/weather-meter.h" +#include "lib/sensors.h" +#include "dev/sys-ctrl.h" +#include "dev/gpio.h" +#include "dev/ioc.h" +#include "sys/timer.h" +#include "sys/etimer.h" +/*---------------------------------------------------------------------------*/ +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 6) +/*---------------------------------------------------------------------------*/ +#define ANEMOMETER_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(ANEMOMETER_SENSOR_PORT) +#define ANEMOMETER_SENSOR_PIN_MASK GPIO_PIN_MASK(ANEMOMETER_SENSOR_PIN) +#define RAIN_GAUGE_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(RAIN_GAUGE_SENSOR_PORT) +#define RAIN_GAUGE_SENSOR_PIN_MASK GPIO_PIN_MASK(RAIN_GAUGE_SENSOR_PIN) +/*---------------------------------------------------------------------------*/ +void (*rain_gauge_int_callback)(uint8_t value); +void (*anemometer_int_callback)(uint8_t value); +/*---------------------------------------------------------------------------*/ +process_event_t anemometer_int_event; +process_event_t rain_gauge_int_event; +/*---------------------------------------------------------------------------*/ +static struct etimer et; +static struct timer debouncetimer; +/*---------------------------------------------------------------------------*/ +typedef struct { + uint16_t ticks; + uint16_t value; +} a_ticking_sensor_t; + +typedef struct { + uint16_t wind_vane; + a_ticking_sensor_t rain_gauge; + a_ticking_sensor_t anemometer; +} weather_meter_sensors; +static weather_meter_sensors weather_sensors; +/*---------------------------------------------------------------------------*/ +PROCESS(weather_meter_int_process, "Weather meter interrupt process handler"); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(weather_meter_int_process, ev, data) +{ + PROCESS_EXITHANDLER(); + PROCESS_BEGIN(); + static uint32_t mph; + static uint16_t rpm; + + etimer_set(&et, CLOCK_SECOND); + + while(1) { + PROCESS_YIELD(); + + /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h + * makes the switch close every second, convert RPM to linear velocity + */ + + if(ev == PROCESS_EVENT_TIMER) { + + /* Disable to make the calculations in an interrupt-safe context */ + GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + + /* Two ticks per rotation */ + rpm = weather_sensors.anemometer.ticks * 30; + + mph = rpm * WEATHER_METER_AUX_ANGULAR; + mph /= 1000; + + /* This will return values in metres per hour */ + weather_sensors.anemometer.value = (uint16_t)mph; + + /* Restart the counter */ + weather_sensors.anemometer.ticks = 0; + + /* Enable the interrupt again */ + GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + etimer_restart(&et); + } + + // anemometer_int_callback(0); + // rain_gauge_int_callback(0); + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +static void +weather_meter_interrupt_handler(uint8_t port, uint8_t pin) +{ + uint32_t aux; + + /* Prevent bounce events */ + if(!timer_expired(&debouncetimer)) { + return; + } + + timer_set(&debouncetimer, DEBOUNCE_DURATION); + + /* We make a process_post() to check in the pollhandler any specific threshold + * value + */ + + if((port == ANEMOMETER_SENSOR_PORT) && (pin == ANEMOMETER_SENSOR_PIN)) { + weather_sensors.anemometer.ticks++; + process_post(&weather_meter_int_process, anemometer_int_event, NULL); + + } else if((port == RAIN_GAUGE_SENSOR_PORT) && (pin == RAIN_GAUGE_SENSOR_PIN)) { + weather_sensors.rain_gauge.ticks++; + aux = weather_sensors.rain_gauge.ticks * WEATHER_METER_AUX_RAIN_MM; + aux /= 1000; + weather_sensors.rain_gauge.value = (uint16_t)aux; + process_post(&weather_meter_int_process, rain_gauge_int_event, NULL); + } +} +/*---------------------------------------------------------------------------*/ +static int +value(int type) +{ + if((type != WEATHER_METER_ANEMOMETER) && (type != WEATHER_METER_RAIN_GAUGE) && + (type != WEATHER_METER_WIND_VANE)) { + PRINTF("Weather: requested an invalid sensor value\n"); + return WEATHER_METER_ERROR; + } + + switch(type) { + case WEATHER_METER_WIND_VANE: + /* FIXME: return the values in degrees */ + weather_sensors.wind_vane = adc_sensors.value(WIND_VANE_ADC); + return weather_sensors.wind_vane; + + case WEATHER_METER_ANEMOMETER: + return weather_sensors.anemometer.value; + + /* as the default return type is int, we have a lower resolution if returning + * the calculated value as it is truncated, an alternative is returning the + * ticks and calculating on your own with WEATHER_METER_AUX_RAIN_MM + */ + case WEATHER_METER_RAIN_GAUGE: + #if WEATHER_METER_RAIN_RETURN_TICKS + return weather_sensors.rain_gauge.ticks; + #else + return weather_sensors.rain_gauge.value; + #endif + + default: + return WEATHER_METER_ERROR; + } +} +/*---------------------------------------------------------------------------*/ +static int +configure(int type, int value) +{ + if(type != WEATHER_METER_ACTIVE) { + PRINTF("Weather: invalid configuration option\n"); + return WEATHER_METER_ERROR; + } + + weather_sensors.wind_vane = 0; + weather_sensors.anemometer.ticks = 0; + weather_sensors.anemometer.value = 0; + weather_sensors.rain_gauge.ticks = 0; + weather_sensors.rain_gauge.value = 0; + + if(!value) { + anemometer_int_callback = NULL; + rain_gauge_int_callback = NULL; + GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + GPIO_DISABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, + RAIN_GAUGE_SENSOR_PIN_MASK); + return WEATHER_METER_SUCCESS; + } + + /* Configure the wind vane */ + adc_sensors.configure(SENSORS_HW_INIT, WIND_VANE_ADC); + + /* Configure anemometer interruption */ + GPIO_SOFTWARE_CONTROL(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_SET_INPUT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_DETECT_RISING(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_TRIGGER_SINGLE_EDGE(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + ioc_set_over(ANEMOMETER_SENSOR_PORT, ANEMOMETER_SENSOR_PIN, IOC_OVERRIDE_DIS); + gpio_register_callback(weather_meter_interrupt_handler, ANEMOMETER_SENSOR_PORT, + ANEMOMETER_SENSOR_PIN); + + /* Configure rain gauge interruption */ + GPIO_SOFTWARE_CONTROL(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_SET_INPUT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_DETECT_RISING(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_TRIGGER_SINGLE_EDGE(RAIN_GAUGE_SENSOR_PORT_BASE, + RAIN_GAUGE_SENSOR_PIN_MASK); + ioc_set_over(RAIN_GAUGE_SENSOR_PORT, RAIN_GAUGE_SENSOR_PIN, IOC_OVERRIDE_DIS); + gpio_register_callback(weather_meter_interrupt_handler, RAIN_GAUGE_SENSOR_PORT, + RAIN_GAUGE_SENSOR_PIN); + + process_start(&weather_meter_int_process, NULL); + + GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + nvic_interrupt_enable(ANEMOMETER_SENSOR_VECTOR); + nvic_interrupt_enable(RAIN_GAUGE_SENSOR_VECTOR); + + return WEATHER_METER_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +SENSORS_SENSOR(weather_meter, WEATHER_METER_SENSOR, value, configure, NULL); +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/platform/zoul/dev/weather-meter.h b/platform/zoul/dev/weather-meter.h new file mode 100644 index 000000000..bda7c06ab --- /dev/null +++ b/platform/zoul/dev/weather-meter.h @@ -0,0 +1,147 @@ +/* + * 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-weather-meter-sensor Sparkfun's weather meter + * @{ + * + * \file + * Weather meter header file + * \author + * Antonio Lignan + */ +/*---------------------------------------------------------------------------*/ +#include "lib/sensors.h" +/* -------------------------------------------------------------------------- */ +#ifndef WEATHER_METER_H_ +#define WEATHER_METER_H_ +/* -------------------------------------------------------------------------- */ +/** + * \name Weather meter sensor return and operation values + * @{ + */ +#define WEATHER_METER_ANEMOMETER 0x00 +#define WEATHER_METER_RAIN_GAUGE 0x01 +#define WEATHER_METER_WIND_VANE 0x02 + +#define WEATHER_METER_ACTIVE SENSORS_ACTIVE +#define WEATHER_METER_SUCCESS 0 +#define WEATHER_METER_ERROR (-1) + +#define WEATHER_METER_ANEMOMETER_RADIUS 65 /**< 65.2 mm pin to cup centre */ +#define WEATHER_METER_AUX_CAL 377 /**< 2*pi*60 (376.992 rounded) */ +#define WEATHER_METER_AUX_ANGULAR (WEATHER_METER_ANEMOMETER_RADIUS * \ + WEATHER_METER_AUX_CAL) +#define WEATHER_METER_AUX_RAIN_MM 2794 /**< 0.2794mm per tick */ + +#ifdef WEATHER_METER_RAIN_CONF_RETURN +#define WEATHER_METER_RAIN_RETURN_TICKS WEATHER_METER_RAIN_CONF_RETURN +#else +#define WEATHER_METER_RAIN_RETURN_TICKS 1 +#endif +/** @} */ +/* -------------------------------------------------------------------------- */ +/** + * \name Anemometer and rain gauge sensor interrupt callback macro + * @{ + */ +#define WEATHER_METER_REGISTER_ANEMOMETER_INT(ptr) anemometer_int_callback = ptr; +#define WEATHER_METER_REGISTER_RAIN_GAUGE_INT(ptr) rain_gauge_int_callback = ptr; +extern void (*anemometer_int_callback)(uint8_t value); +extern void (*rain_gauge_int_callback)(uint8_t value); +/** @} */ +/* -------------------------------------------------------------------------- */ +/** + * \name Weather meter's anemometer default pin, port and interrupt vector + * @{ + */ +#ifdef WEATHER_METER_CONF_ANEMOMETER_PIN +#define ANEMOMETER_SENSOR_PIN WEATHER_METER_CONF_ANEMOMETER_PIN +#else +#define ANEMOMETER_SENSOR_PIN 1 +#endif +#ifdef WEATHER_METER_CONF_ANEMOMETER_PORT +#define ANEMOMETER_SENSOR_PORT WEATHER_METER_CONF_ANEMOMETER_PORT +#else +#define ANEMOMETER_SENSOR_PORT GPIO_D_NUM +#endif +#ifdef WEATHER_METER_CONF_ANEMOMETER_VECTOR +#define ANEMOMETER_SENSOR_VECTOR WEATHER_METER_CONF_ANEMOMETER_VECTOR +#else +#define ANEMOMETER_SENSOR_VECTOR NVIC_INT_GPIO_PORT_D +#endif +/** @} */ +/* -------------------------------------------------------------------------- */ +/** + * \name Weather meter's rain gauge default pin, port and interrupt vector + * @{ + */ +#ifdef WEATHER_METER_CONF_RAIN_GAUGE_PIN +#define RAIN_GAUGE_SENSOR_PIN WEATHER_METER_CONF_RAIN_GAUGE_PIN +#else +#define RAIN_GAUGE_SENSOR_PIN 2 +#endif +#ifdef WEATHER_METER_CONF_RAIN_GAUGE_PORT +#define RAIN_GAUGE_SENSOR_PORT WEATHER_METER_CONF_RAIN_GAUGE_PORT +#else +#define RAIN_GAUGE_SENSOR_PORT GPIO_D_NUM +#endif +#ifdef WEATHER_METER_CONF_RAIN_GAUGE_VECTOR +#define RAIN_GAUGE_SENSOR_VECTOR WEATHER_METER_CONF_RAIN_GAUGE_VECTOR +#else +#define RAIN_GAUGE_SENSOR_VECTOR NVIC_INT_GPIO_PORT_D +#endif +/** @} */ +/* -------------------------------------------------------------------------- */ +/** + * \name Weather meter's wind vane default ADCx pin (see board.h) + * @{ + */ +#ifdef WEATHER_METER_CONF_RAIN_WIND_VANE_ADC +#define WIND_VANE_ADC WEATHER_METER_CONF_RAIN_WIND_VANE_ADC +#else +#define WIND_VANE_ADC ZOUL_SENSORS_ADC3 +#endif +/** @} */ +/* -------------------------------------------------------------------------- */ +#define WEATHER_METER_SENSOR "Sparkfun weather meter" +/* -------------------------------------------------------------------------- */ +extern const struct sensors_sensor weather_meter; +/* -------------------------------------------------------------------------- */ +#endif /* ifndef WEATHER_METER_H_ */ +/** + * @} + * @} + */ From aacbcd904fd8fb06ada5e4e5a7e97d3ae899fa94 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Sun, 17 Jan 2016 02:22:19 +0100 Subject: [PATCH 2/8] Added interrupt configuration for the weather meter --- examples/zolertia/zoul/test-weather-meter.c | 33 ++-- platform/zoul/dev/weather-meter.c | 168 +++++++++++++------- platform/zoul/dev/weather-meter.h | 36 +++-- 3 files changed, 155 insertions(+), 82 deletions(-) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c index 5f04f4015..3149404e7 100644 --- a/examples/zolertia/zoul/test-weather-meter.c +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -55,7 +55,9 @@ #include #include /*---------------------------------------------------------------------------*/ -#define READ_SENSOR_PERIOD CLOCK_SECOND +#define READ_SENSOR_PERIOD CLOCK_SECOND +#define ANEMOMETER_THRESHOLD_TICK 8 +#define RAIN_GAUGE_THRESHOLD_TICK 15 /*---------------------------------------------------------------------------*/ static struct etimer et; /*---------------------------------------------------------------------------*/ @@ -63,15 +65,17 @@ PROCESS(test_weather_meter_sensors, "Test Weather meter sensors"); AUTOSTART_PROCESSES(&test_weather_meter_sensors); /*---------------------------------------------------------------------------*/ static void -rain_callback(uint8_t value) +rain_callback(uint16_t value) { - printf("*** Rain\n"); + printf("*** Rain gauge over threshold (%u ticks)\n", value); + weather_meter.configure(WEATHER_METER_RAIN_GAUGE_INT_OVER, + (value + RAIN_GAUGE_THRESHOLD_TICK)); } /*---------------------------------------------------------------------------*/ static void -wind_speed_callback(uint8_t value) +wind_speed_callback(uint16_t value) { - printf("*** Wind speed\n"); + printf("*** Wind speed over threshold (%u ticks)\n", value); } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(test_weather_meter_sensors, ev, data) @@ -86,8 +90,17 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) WEATHER_METER_REGISTER_ANEMOMETER_INT(wind_speed_callback); WEATHER_METER_REGISTER_RAIN_GAUGE_INT(rain_callback); + /* Enable the sensors, this has to be called before any of the interrupt calls + * like the ones below + */ SENSORS_ACTIVATE(weather_meter); + /* And the upper threshold value to compare and generate an interrupt */ + weather_meter.configure(WEATHER_METER_ANEMOMETER_INT_OVER, + ANEMOMETER_THRESHOLD_TICK); + weather_meter.configure(WEATHER_METER_RAIN_GAUGE_INT_OVER, + RAIN_GAUGE_THRESHOLD_TICK); + etimer_set(&et, READ_SENSOR_PERIOD); while(1) { @@ -100,17 +113,17 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) #if WEATHER_METER_RAIN_RETURN_TICKS rain *= WEATHER_METER_AUX_RAIN_MM; if(rain > (WEATHER_METER_AUX_RAIN_MM * 3)) { - printf("Rain: %lu.%lu mm\n", (rain / 10000), (rain % 10000)); + printf("Rain: %lu.%lu mm, ", (rain / 10000), (rain % 10000)); #else if(rain >= 10) { - printf("Rain: %u.%u mm\n", (rain / 10), (rain % 10)); + printf("Rain: %u.%u mm, ", (rain / 10), (rain % 10)); #endif } else { - printf("Rain: 0.%lu mm\n", rain); + printf("Rain: 0.%lu mm, ", rain); } - printf("Wind direction: %u metres/hour\n", wind_dir); - printf("Wind speed %u\n", wind_speed); + printf("Wind (dir: %u deg, ", wind_dir); + printf("speed %u m/h)\n", wind_speed); etimer_reset(&et); } diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index bfb99945b..9e874d9e8 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -47,6 +47,7 @@ #include "contiki.h" #include "dev/adc-sensors.h" #include "dev/weather-meter.h" +#include "dev/zoul-sensors.h" #include "lib/sensors.h" #include "dev/sys-ctrl.h" #include "dev/gpio.h" @@ -54,22 +55,24 @@ #include "sys/timer.h" #include "sys/etimer.h" /*---------------------------------------------------------------------------*/ -#define DEBUG 1 +#define DEBUG 0 #if DEBUG #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 6) +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 4) /*---------------------------------------------------------------------------*/ #define ANEMOMETER_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(ANEMOMETER_SENSOR_PORT) #define ANEMOMETER_SENSOR_PIN_MASK GPIO_PIN_MASK(ANEMOMETER_SENSOR_PIN) #define RAIN_GAUGE_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(RAIN_GAUGE_SENSOR_PORT) #define RAIN_GAUGE_SENSOR_PIN_MASK GPIO_PIN_MASK(RAIN_GAUGE_SENSOR_PIN) /*---------------------------------------------------------------------------*/ -void (*rain_gauge_int_callback)(uint8_t value); -void (*anemometer_int_callback)(uint8_t value); +void (*rain_gauge_int_callback)(uint16_t value); +void (*anemometer_int_callback)(uint16_t value); +/*---------------------------------------------------------------------------*/ +static uint8_t enabled; /*---------------------------------------------------------------------------*/ process_event_t anemometer_int_event; process_event_t rain_gauge_int_event; @@ -80,12 +83,14 @@ static struct timer debouncetimer; typedef struct { uint16_t ticks; uint16_t value; -} a_ticking_sensor_t; + uint8_t int_en; + uint16_t int_thres; +} weather_meter_sensors_t; typedef struct { uint16_t wind_vane; - a_ticking_sensor_t rain_gauge; - a_ticking_sensor_t anemometer; + weather_meter_sensors_t rain_gauge; + weather_meter_sensors_t anemometer; } weather_meter_sensors; static weather_meter_sensors weather_sensors; /*---------------------------------------------------------------------------*/ @@ -103,9 +108,19 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) while(1) { PROCESS_YIELD(); - /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h - * makes the switch close every second, convert RPM to linear velocity - */ + if((ev == anemometer_int_event) && (weather_sensors.anemometer.int_en)) { + if(weather_sensors.anemometer.ticks >= + weather_sensors.anemometer.int_thres) { + anemometer_int_callback(weather_sensors.anemometer.ticks); + } + } + + if((ev == rain_gauge_int_event) && (weather_sensors.rain_gauge.int_en)) { + if(weather_sensors.rain_gauge.ticks >= + weather_sensors.rain_gauge.int_thres) { + rain_gauge_int_callback(weather_sensors.rain_gauge.ticks); + } + } if(ev == PROCESS_EVENT_TIMER) { @@ -113,9 +128,10 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); - /* Two ticks per rotation */ + /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h + * makes the switch close every second, convert RPM to linear velocity + */ rpm = weather_sensors.anemometer.ticks * 30; - mph = rpm * WEATHER_METER_AUX_ANGULAR; mph /= 1000; @@ -130,9 +146,6 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) ANEMOMETER_SENSOR_PIN_MASK); etimer_restart(&et); } - - // anemometer_int_callback(0); - // rain_gauge_int_callback(0); } PROCESS_END(); } @@ -175,6 +188,11 @@ value(int type) return WEATHER_METER_ERROR; } + if(!enabled) { + PRINTF("Weather: module is not configured\n"); + return WEATHER_METER_ERROR; + } + switch(type) { case WEATHER_METER_WIND_VANE: /* FIXME: return the values in degrees */ @@ -203,56 +221,92 @@ value(int type) static int configure(int type, int value) { - if(type != WEATHER_METER_ACTIVE) { + if((type != WEATHER_METER_ACTIVE) && + (type != WEATHER_METER_ANEMOMETER_INT_OVER) && + (type != WEATHER_METER_RAIN_GAUGE_INT_OVER) && + (type != WEATHER_METER_ANEMOMETER_INT_DIS) && + (type != WEATHER_METER_RAIN_GAUGE_INT_DIS)) { PRINTF("Weather: invalid configuration option\n"); return WEATHER_METER_ERROR; } - weather_sensors.wind_vane = 0; - weather_sensors.anemometer.ticks = 0; - weather_sensors.anemometer.value = 0; - weather_sensors.rain_gauge.ticks = 0; - weather_sensors.rain_gauge.value = 0; + if(type == WEATHER_METER_ACTIVE) { - if(!value) { - anemometer_int_callback = NULL; - rain_gauge_int_callback = NULL; - GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); - GPIO_DISABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, - RAIN_GAUGE_SENSOR_PIN_MASK); + weather_sensors.anemometer.int_en = 0; + weather_sensors.rain_gauge.int_en = 0; + weather_sensors.anemometer.ticks = 0; + weather_sensors.rain_gauge.ticks = 0; + + if(!value) { + anemometer_int_callback = NULL; + rain_gauge_int_callback = NULL; + GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + GPIO_DISABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, + RAIN_GAUGE_SENSOR_PIN_MASK); + process_exit(&weather_meter_int_process); + enabled = 0; + PRINTF("Weather: disabled\n"); + return WEATHER_METER_SUCCESS; + } + + /* Configure the wind vane */ + adc_sensors.configure(SENSORS_HW_INIT, WIND_VANE_ADC); + + /* Configure anemometer interruption */ + GPIO_SOFTWARE_CONTROL(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_SET_INPUT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_DETECT_RISING(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_TRIGGER_SINGLE_EDGE(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + ioc_set_over(ANEMOMETER_SENSOR_PORT, ANEMOMETER_SENSOR_PIN, IOC_OVERRIDE_DIS); + gpio_register_callback(weather_meter_interrupt_handler, ANEMOMETER_SENSOR_PORT, + ANEMOMETER_SENSOR_PIN); + + /* Configure rain gauge interruption */ + GPIO_SOFTWARE_CONTROL(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_SET_INPUT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_DETECT_RISING(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + GPIO_TRIGGER_SINGLE_EDGE(RAIN_GAUGE_SENSOR_PORT_BASE, + RAIN_GAUGE_SENSOR_PIN_MASK); + ioc_set_over(RAIN_GAUGE_SENSOR_PORT, RAIN_GAUGE_SENSOR_PIN, IOC_OVERRIDE_DIS); + gpio_register_callback(weather_meter_interrupt_handler, RAIN_GAUGE_SENSOR_PORT, + RAIN_GAUGE_SENSOR_PIN); + + process_start(&weather_meter_int_process, NULL); + + GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); + GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); + nvic_interrupt_enable(ANEMOMETER_SENSOR_VECTOR); + nvic_interrupt_enable(RAIN_GAUGE_SENSOR_VECTOR); + + enabled = 1; + PRINTF("Weather: started\n"); return WEATHER_METER_SUCCESS; } - /* Configure the wind vane */ - adc_sensors.configure(SENSORS_HW_INIT, WIND_VANE_ADC); - - /* Configure anemometer interruption */ - GPIO_SOFTWARE_CONTROL(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); - GPIO_SET_INPUT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); - GPIO_DETECT_RISING(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); - GPIO_TRIGGER_SINGLE_EDGE(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); - ioc_set_over(ANEMOMETER_SENSOR_PORT, ANEMOMETER_SENSOR_PIN, IOC_OVERRIDE_DIS); - gpio_register_callback(weather_meter_interrupt_handler, ANEMOMETER_SENSOR_PORT, - ANEMOMETER_SENSOR_PIN); - - /* Configure rain gauge interruption */ - GPIO_SOFTWARE_CONTROL(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); - GPIO_SET_INPUT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); - GPIO_DETECT_RISING(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); - GPIO_TRIGGER_SINGLE_EDGE(RAIN_GAUGE_SENSOR_PORT_BASE, - RAIN_GAUGE_SENSOR_PIN_MASK); - ioc_set_over(RAIN_GAUGE_SENSOR_PORT, RAIN_GAUGE_SENSOR_PIN, IOC_OVERRIDE_DIS); - gpio_register_callback(weather_meter_interrupt_handler, RAIN_GAUGE_SENSOR_PORT, - RAIN_GAUGE_SENSOR_PIN); - - process_start(&weather_meter_int_process, NULL); - - GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); - GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); - nvic_interrupt_enable(ANEMOMETER_SENSOR_VECTOR); - nvic_interrupt_enable(RAIN_GAUGE_SENSOR_VECTOR); + switch(type) { + case WEATHER_METER_ANEMOMETER_INT_OVER: + weather_sensors.anemometer.int_en = 1; + weather_sensors.anemometer.int_thres = value; + PRINTF("Weather: anemometer threshold %u\n", value); + break; + case WEATHER_METER_RAIN_GAUGE_INT_OVER: + weather_sensors.rain_gauge.int_en = 1; + weather_sensors.rain_gauge.int_thres = value; + PRINTF("Weather: rain gauge threshold %u\n", value); + break; + case WEATHER_METER_ANEMOMETER_INT_DIS: + PRINTF("Weather: anemometer int disabled\n"); + weather_sensors.anemometer.int_en = 0; + break; + case WEATHER_METER_RAIN_GAUGE_INT_DIS: + PRINTF("Weather: rain gauge int disabled\n"); + weather_sensors.rain_gauge.int_en = 0; + break; + default: + return WEATHER_METER_ERROR; + } return WEATHER_METER_SUCCESS; } diff --git a/platform/zoul/dev/weather-meter.h b/platform/zoul/dev/weather-meter.h index bda7c06ab..3de2d5971 100644 --- a/platform/zoul/dev/weather-meter.h +++ b/platform/zoul/dev/weather-meter.h @@ -44,6 +44,7 @@ */ /*---------------------------------------------------------------------------*/ #include "lib/sensors.h" +#include "dev/zoul-sensors.h" /* -------------------------------------------------------------------------- */ #ifndef WEATHER_METER_H_ #define WEATHER_METER_H_ @@ -52,24 +53,29 @@ * \name Weather meter sensor return and operation values * @{ */ -#define WEATHER_METER_ANEMOMETER 0x00 -#define WEATHER_METER_RAIN_GAUGE 0x01 -#define WEATHER_METER_WIND_VANE 0x02 +#define WEATHER_METER_ANEMOMETER 0x00 +#define WEATHER_METER_RAIN_GAUGE 0x01 +#define WEATHER_METER_WIND_VANE 0x02 -#define WEATHER_METER_ACTIVE SENSORS_ACTIVE -#define WEATHER_METER_SUCCESS 0 -#define WEATHER_METER_ERROR (-1) +#define WEATHER_METER_ACTIVE SENSORS_ACTIVE +#define WEATHER_METER_ANEMOMETER_INT_OVER HW_INT_OVER_THRS +#define WEATHER_METER_ANEMOMETER_INT_DIS HW_INT_DISABLE +#define WEATHER_METER_RAIN_GAUGE_INT_OVER (HW_INT_OVER_THRS << 1) +#define WEATHER_METER_RAIN_GAUGE_INT_DIS (HW_INT_DISABLE << 1) -#define WEATHER_METER_ANEMOMETER_RADIUS 65 /**< 65.2 mm pin to cup centre */ -#define WEATHER_METER_AUX_CAL 377 /**< 2*pi*60 (376.992 rounded) */ -#define WEATHER_METER_AUX_ANGULAR (WEATHER_METER_ANEMOMETER_RADIUS * \ - WEATHER_METER_AUX_CAL) -#define WEATHER_METER_AUX_RAIN_MM 2794 /**< 0.2794mm per tick */ +#define WEATHER_METER_SUCCESS 0 +#define WEATHER_METER_ERROR (-1) + +#define WEATHER_METER_ANEMOMETER_RADIUS 65 /**< 65.2 mm pin to cup centre */ +#define WEATHER_METER_AUX_CAL 377 /**< 2*pi*60 (376.992 rounded) */ +#define WEATHER_METER_AUX_ANGULAR (WEATHER_METER_ANEMOMETER_RADIUS * \ + WEATHER_METER_AUX_CAL) +#define WEATHER_METER_AUX_RAIN_MM 2794 /**< 0.2794mm per tick */ #ifdef WEATHER_METER_RAIN_CONF_RETURN -#define WEATHER_METER_RAIN_RETURN_TICKS WEATHER_METER_RAIN_CONF_RETURN +#define WEATHER_METER_RAIN_RETURN_TICKS WEATHER_METER_RAIN_CONF_RETURN #else -#define WEATHER_METER_RAIN_RETURN_TICKS 1 +#define WEATHER_METER_RAIN_RETURN_TICKS 1 #endif /** @} */ /* -------------------------------------------------------------------------- */ @@ -79,8 +85,8 @@ */ #define WEATHER_METER_REGISTER_ANEMOMETER_INT(ptr) anemometer_int_callback = ptr; #define WEATHER_METER_REGISTER_RAIN_GAUGE_INT(ptr) rain_gauge_int_callback = ptr; -extern void (*anemometer_int_callback)(uint8_t value); -extern void (*rain_gauge_int_callback)(uint8_t value); +extern void (*anemometer_int_callback)(uint16_t value); +extern void (*rain_gauge_int_callback)(uint16_t value); /** @} */ /* -------------------------------------------------------------------------- */ /** From 0cb80b060588ec2947392a2a2ea140fa737bcd60 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Sun, 17 Jan 2016 02:25:00 +0100 Subject: [PATCH 3/8] Prevent calculations if tick is zero --- platform/zoul/dev/weather-meter.c | 38 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index 9e874d9e8..ea7f41331 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -123,28 +123,30 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) } if(ev == PROCESS_EVENT_TIMER) { + if(weather_sensors.anemometer.ticks) { - /* Disable to make the calculations in an interrupt-safe context */ - GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); + /* Disable to make the calculations in an interrupt-safe context */ + GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); - /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h - * makes the switch close every second, convert RPM to linear velocity - */ - rpm = weather_sensors.anemometer.ticks * 30; - mph = rpm * WEATHER_METER_AUX_ANGULAR; - mph /= 1000; + /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h + * makes the switch close every second, convert RPM to linear velocity + */ + rpm = weather_sensors.anemometer.ticks * 30; + mph = rpm * WEATHER_METER_AUX_ANGULAR; + mph /= 1000; - /* This will return values in metres per hour */ - weather_sensors.anemometer.value = (uint16_t)mph; + /* This will return values in metres per hour */ + weather_sensors.anemometer.value = (uint16_t)mph; - /* Restart the counter */ - weather_sensors.anemometer.ticks = 0; + /* Restart the counter */ + weather_sensors.anemometer.ticks = 0; - /* Enable the interrupt again */ - GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); - etimer_restart(&et); + /* Enable the interrupt again */ + GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + etimer_restart(&et); + } } } PROCESS_END(); @@ -236,6 +238,8 @@ configure(int type, int value) weather_sensors.rain_gauge.int_en = 0; weather_sensors.anemometer.ticks = 0; weather_sensors.rain_gauge.ticks = 0; + weather_sensors.anemometer.value = 0; + weather_sensors.rain_gauge.value = 0; if(!value) { anemometer_int_callback = NULL; From 61f151636931f71e89d87cd18935d3499db38881 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Sun, 17 Jan 2016 14:56:12 +0100 Subject: [PATCH 4/8] Reworked instant wind speed calculation and extended the available wind speed return values --- examples/zolertia/zoul/test-weather-meter.c | 25 ++++- platform/zoul/dev/weather-meter.c | 117 ++++++++++++++------ platform/zoul/dev/weather-meter.h | 15 ++- 3 files changed, 111 insertions(+), 46 deletions(-) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c index 3149404e7..9a0adf7f7 100644 --- a/examples/zolertia/zoul/test-weather-meter.c +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -56,8 +56,8 @@ #include /*---------------------------------------------------------------------------*/ #define READ_SENSOR_PERIOD CLOCK_SECOND -#define ANEMOMETER_THRESHOLD_TICK 8 -#define RAIN_GAUGE_THRESHOLD_TICK 15 +#define ANEMOMETER_THRESHOLD_TICK 13 /**< 16 Km/h */ +#define RAIN_GAUGE_THRESHOLD_TICK 15 /**< each increment of 4.19 mm */ /*---------------------------------------------------------------------------*/ static struct etimer et; /*---------------------------------------------------------------------------*/ @@ -67,6 +67,7 @@ AUTOSTART_PROCESSES(&test_weather_meter_sensors); static void rain_callback(uint16_t value) { + /* To calculate ticks from mm of rain, divide by 0.2794 mm */ printf("*** Rain gauge over threshold (%u ticks)\n", value); weather_meter.configure(WEATHER_METER_RAIN_GAUGE_INT_OVER, (value + RAIN_GAUGE_THRESHOLD_TICK)); @@ -75,6 +76,12 @@ rain_callback(uint16_t value) static void wind_speed_callback(uint16_t value) { + /* This checks for instant wind speed values (over a second), the minimum + * value is 1.2 Km/h (one tick), as the reference is 2.4KM/h per rotation, and + * the anemometer makes 2 ticks per rotation. Instant speed is calculated as + * multiples of this, so if you want to check for 16Km/h, then it would be 13 + * ticks + */ printf("*** Wind speed over threshold (%u ticks)\n", value); } /*---------------------------------------------------------------------------*/ @@ -85,6 +92,9 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) static uint32_t rain; static uint16_t wind_speed; static uint16_t wind_dir; + static uint16_t wind_speed_avg; + static uint16_t wind_speed_avg_2m; + static uint16_t wind_speed_max; /* Register the callback handler when thresholds are met */ WEATHER_METER_REGISTER_ANEMOMETER_INT(wind_speed_callback); @@ -109,6 +119,9 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) rain = weather_meter.value(WEATHER_METER_RAIN_GAUGE); wind_speed = weather_meter.value(WEATHER_METER_ANEMOMETER); wind_dir = weather_meter.value(WEATHER_METER_WIND_VANE); + wind_speed_avg = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG); + wind_speed_avg_2m = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_2M); + wind_speed_max = weather_meter.value(WEATHER_METER_ANEMOMETER_MAX); #if WEATHER_METER_RAIN_RETURN_TICKS rain *= WEATHER_METER_AUX_RAIN_MM; @@ -122,8 +135,12 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) printf("Rain: 0.%lu mm, ", rain); } - printf("Wind (dir: %u deg, ", wind_dir); - printf("speed %u m/h)\n", wind_speed); + printf("Wind dir: %u deg,\n", wind_dir); + printf("Wind speed: %u m/h ", wind_speed); + printf("(%u m/h avg, %u m/h 2m avg, %u m/h max)\n\n", wind_speed_avg, + wind_speed_avg_2m, + wind_speed_max); + etimer_reset(&et); } diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index ea7f41331..e0a97e64b 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -53,7 +53,7 @@ #include "dev/gpio.h" #include "dev/ioc.h" #include "sys/timer.h" -#include "sys/etimer.h" +#include "sys/rtimer.h" /*---------------------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG @@ -62,7 +62,7 @@ #define PRINTF(...) #endif /*---------------------------------------------------------------------------*/ -#define DEBOUNCE_DURATION (CLOCK_SECOND >> 4) +#define DEBOUNCE_DURATION (CLOCK_SECOND >> 6) /*---------------------------------------------------------------------------*/ #define ANEMOMETER_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(ANEMOMETER_SENSOR_PORT) #define ANEMOMETER_SENSOR_PIN_MASK GPIO_PIN_MASK(ANEMOMETER_SENSOR_PIN) @@ -77,7 +77,7 @@ static uint8_t enabled; process_event_t anemometer_int_event; process_event_t rain_gauge_int_event; /*---------------------------------------------------------------------------*/ -static struct etimer et; +static struct rtimer rt; static struct timer debouncetimer; /*---------------------------------------------------------------------------*/ typedef struct { @@ -87,12 +87,65 @@ typedef struct { uint16_t int_thres; } weather_meter_sensors_t; +typedef struct { + uint16_t value_max; + uint64_t ticks_avg; + uint64_t value_avg; + uint32_t value_buf_2m; + uint16_t value_avg_2m; +} weather_meter_ext_t; + typedef struct { uint16_t wind_vane; weather_meter_sensors_t rain_gauge; weather_meter_sensors_t anemometer; } weather_meter_sensors; + static weather_meter_sensors weather_sensors; +static weather_meter_ext_t anemometer; +/*---------------------------------------------------------------------------*/ +void +rt_callback(struct rtimer *t, void *ptr) +{ + uint32_t wind_speed; + + /* Disable to make the calculations in an interrupt-safe context */ + GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + wind_speed = weather_sensors.anemometer.ticks; + wind_speed *= WEATHER_METER_ANEMOMETER_SPEED_1S; + weather_sensors.anemometer.value = (uint16_t)wind_speed; + anemometer.ticks_avg++; + anemometer.value_avg += weather_sensors.anemometer.value; + anemometer.value_buf_2m += weather_sensors.anemometer.value; + + /* Take maximum value */ + if(weather_sensors.anemometer.value > anemometer.value_max) { + anemometer.value_max = weather_sensors.anemometer.value; + } + + /* Average every 2 minutes */ + if(!(anemometer.ticks_avg % 120)) { + if(anemometer.value_buf_2m) { + anemometer.value_avg_2m = anemometer.value_buf_2m / 120; + anemometer.value_buf_2m = 0; + } else { + anemometer.value_avg_2m = 0; + } + } + + /* Check for roll-over */ + if(!anemometer.ticks_avg) { + anemometer.value_avg = 0; + } + + weather_sensors.anemometer.ticks = 0; + + /* Enable the interrupt again */ + GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, + ANEMOMETER_SENSOR_PIN_MASK); + rtimer_set(&rt, RTIMER_NOW() + RTIMER_SECOND, 1, rt_callback, NULL); +} /*---------------------------------------------------------------------------*/ PROCESS(weather_meter_int_process, "Weather meter interrupt process handler"); /*---------------------------------------------------------------------------*/ @@ -100,10 +153,6 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) { PROCESS_EXITHANDLER(); PROCESS_BEGIN(); - static uint32_t mph; - static uint16_t rpm; - - etimer_set(&et, CLOCK_SECOND); while(1) { PROCESS_YIELD(); @@ -121,33 +170,6 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) rain_gauge_int_callback(weather_sensors.rain_gauge.ticks); } } - - if(ev == PROCESS_EVENT_TIMER) { - if(weather_sensors.anemometer.ticks) { - - /* Disable to make the calculations in an interrupt-safe context */ - GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); - - /* The anemometer ticks twice per rotation, and a wind speed of 2.4 km/h - * makes the switch close every second, convert RPM to linear velocity - */ - rpm = weather_sensors.anemometer.ticks * 30; - mph = rpm * WEATHER_METER_AUX_ANGULAR; - mph /= 1000; - - /* This will return values in metres per hour */ - weather_sensors.anemometer.value = (uint16_t)mph; - - /* Restart the counter */ - weather_sensors.anemometer.ticks = 0; - - /* Enable the interrupt again */ - GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, - ANEMOMETER_SENSOR_PIN_MASK); - etimer_restart(&et); - } - } } PROCESS_END(); } @@ -184,8 +206,14 @@ weather_meter_interrupt_handler(uint8_t port, uint8_t pin) static int value(int type) { - if((type != WEATHER_METER_ANEMOMETER) && (type != WEATHER_METER_RAIN_GAUGE) && - (type != WEATHER_METER_WIND_VANE)) { + uint64_t aux; + + if((type != WEATHER_METER_ANEMOMETER) && + (type != WEATHER_METER_RAIN_GAUGE) && + (type != WEATHER_METER_WIND_VANE) && + (type != WEATHER_METER_ANEMOMETER_AVG) && + (type != WEATHER_METER_ANEMOMETER_AVG_2M) && + (type != WEATHER_METER_ANEMOMETER_MAX)) { PRINTF("Weather: requested an invalid sensor value\n"); return WEATHER_METER_ERROR; } @@ -204,6 +232,19 @@ value(int type) case WEATHER_METER_ANEMOMETER: return weather_sensors.anemometer.value; + case WEATHER_METER_ANEMOMETER_AVG: + if(anemometer.value_avg <= 0) { + return (uint16_t)anemometer.value_avg; + } + aux = anemometer.value_avg / anemometer.ticks_avg; + return (uint16_t)aux; + + case WEATHER_METER_ANEMOMETER_AVG_2M: + return anemometer.value_avg_2m; + + case WEATHER_METER_ANEMOMETER_MAX: + return anemometer.value_max; + /* as the default return type is int, we have a lower resolution if returning * the calculated value as it is truncated, an alternative is returning the * ticks and calculating on your own with WEATHER_METER_AUX_RAIN_MM @@ -234,6 +275,9 @@ configure(int type, int value) if(type == WEATHER_METER_ACTIVE) { + anemometer.value_avg = 0; + anemometer.ticks_avg = 0; + weather_sensors.anemometer.int_en = 0; weather_sensors.rain_gauge.int_en = 0; weather_sensors.anemometer.ticks = 0; @@ -278,6 +322,7 @@ configure(int type, int value) RAIN_GAUGE_SENSOR_PIN); process_start(&weather_meter_int_process, NULL); + rtimer_set(&rt, RTIMER_NOW() + RTIMER_SECOND, 1, rt_callback, NULL); GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK); diff --git a/platform/zoul/dev/weather-meter.h b/platform/zoul/dev/weather-meter.h index 3de2d5971..47ef859f3 100644 --- a/platform/zoul/dev/weather-meter.h +++ b/platform/zoul/dev/weather-meter.h @@ -53,9 +53,12 @@ * \name Weather meter sensor return and operation values * @{ */ -#define WEATHER_METER_ANEMOMETER 0x00 #define WEATHER_METER_RAIN_GAUGE 0x01 #define WEATHER_METER_WIND_VANE 0x02 +#define WEATHER_METER_ANEMOMETER 0x03 +#define WEATHER_METER_ANEMOMETER_AVG 0x04 +#define WEATHER_METER_ANEMOMETER_AVG_2M 0x05 +#define WEATHER_METER_ANEMOMETER_MAX 0x06 #define WEATHER_METER_ACTIVE SENSORS_ACTIVE #define WEATHER_METER_ANEMOMETER_INT_OVER HW_INT_OVER_THRS @@ -66,11 +69,11 @@ #define WEATHER_METER_SUCCESS 0 #define WEATHER_METER_ERROR (-1) -#define WEATHER_METER_ANEMOMETER_RADIUS 65 /**< 65.2 mm pin to cup centre */ -#define WEATHER_METER_AUX_CAL 377 /**< 2*pi*60 (376.992 rounded) */ -#define WEATHER_METER_AUX_ANGULAR (WEATHER_METER_ANEMOMETER_RADIUS * \ - WEATHER_METER_AUX_CAL) -#define WEATHER_METER_AUX_RAIN_MM 2794 /**< 0.2794mm per tick */ +/* 2.4Km/h per tick, 2 per rotation */ +#define WEATHER_METER_ANEMOMETER_SPEED_1S (1200) + +/* 0.2794mm per tick */ +#define WEATHER_METER_AUX_RAIN_MM 2794 #ifdef WEATHER_METER_RAIN_CONF_RETURN #define WEATHER_METER_RAIN_RETURN_TICKS WEATHER_METER_RAIN_CONF_RETURN From 0902e0fc6d413b50fe45f58a7cbfc7076a5b0170 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Sun, 17 Jan 2016 21:34:52 +0100 Subject: [PATCH 5/8] Added degree converted value for the wind vane sensor. Also added a 2-minutes average wind direction value, replaced the 240 bytes buffer from the reference example, but probably there's room for efficiency improvement --- examples/zolertia/zoul/test-weather-meter.c | 6 +- platform/zoul/dev/weather-meter.c | 126 +++++++++++++++++++- platform/zoul/dev/weather-meter.h | 10 +- 3 files changed, 132 insertions(+), 10 deletions(-) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c index 9a0adf7f7..93998d9e8 100644 --- a/examples/zolertia/zoul/test-weather-meter.c +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -92,6 +92,7 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) static uint32_t rain; static uint16_t wind_speed; static uint16_t wind_dir; + static uint16_t wind_dir_avg_2m; static uint16_t wind_speed_avg; static uint16_t wind_speed_avg_2m; static uint16_t wind_speed_max; @@ -119,6 +120,7 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) rain = weather_meter.value(WEATHER_METER_RAIN_GAUGE); wind_speed = weather_meter.value(WEATHER_METER_ANEMOMETER); wind_dir = weather_meter.value(WEATHER_METER_WIND_VANE); + wind_dir_avg_2m = weather_meter.value(WEATHER_METER_WIND_VANE_AVG_2M); wind_speed_avg = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG); wind_speed_avg_2m = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_2M); wind_speed_max = weather_meter.value(WEATHER_METER_ANEMOMETER_MAX); @@ -135,12 +137,12 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) printf("Rain: 0.%lu mm, ", rain); } - printf("Wind dir: %u deg,\n", wind_dir); + printf("Wind dir: %u.%01u deg, ", (wind_dir / 10), (wind_dir % 10)); + printf("(%u.%01u deg avg)\n", (wind_dir_avg_2m / 10), (wind_dir_avg_2m % 10)); printf("Wind speed: %u m/h ", wind_speed); printf("(%u m/h avg, %u m/h 2m avg, %u m/h max)\n\n", wind_speed_avg, wind_speed_avg_2m, wind_speed_max); - etimer_reset(&et); } diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index e0a97e64b..98324b0d0 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -101,13 +101,96 @@ typedef struct { weather_meter_sensors_t anemometer; } weather_meter_sensors; +typedef struct { + uint32_t value_buf_2m; + uint16_t value_prev; + uint16_t value_avg_2m; +} weather_meter_wind_vane_ext_t; + static weather_meter_sensors weather_sensors; static weather_meter_ext_t anemometer; +static weather_meter_wind_vane_ext_t wind_vane; +/*---------------------------------------------------------------------------*/ +typedef struct { + uint16_t mid_point; + uint16_t degree; +} wind_vane_mid_point_t; + + /* From the datasheet we adjusted the values for a 3V divider, using a 10K + * resistor, the check values are the following: + * --------------------+------------------+------------------------------- + * Direction (Degrees) Resistance (Ohms) Voltage (mV) + * 0 33k 2532.55 * + * 22.5 6.57k 1308.44 * + * 45 8.2k 1486.81 * + * 67.5 891 269.97 * + * 90 1k 300.00 * + * 112.5 688 212.42 * + * 135 2.2k 595.08 * + * 157.5 1.41k 407.80 * + * 180 3.9k 925.89 * + * 202.5 3.14k 788.58 * + * 225 16k 2030.76 * + * 247.5 14.12k 1930.84 * + * 270 120k 3046.15 * + * 292.5 42.12k 2666.84 * + * 315 64.9k 2859.41 * + * 337.5 21.88k 2264.86 * + * --------------------+------------------+------------------------------- + */ +static const wind_vane_mid_point_t wind_vane_table[16] = { + { 2124, 1125 }, + { 2699, 675 }, + { 3000, 900 }, + { 4078, 1575 }, + { 5950, 1350 }, + { 7885, 2025 }, + { 9258, 1800 }, + { 13084, 225 }, + { 14868, 450 }, + { 19308, 2475 }, + { 20307, 2250 }, + { 22648, 3375 }, + { 25325, 0 }, + { 26668, 2925 }, + { 28594, 3150 }, + { 30461, 2700 }, +}; +/*---------------------------------------------------------------------------*/ +static int +weather_meter_wind_vane_degrees(uint16_t value) +{ + uint8_t i; + for(i=0; i<16; i++) { + if(value <= wind_vane_table[i].mid_point) { + return (int)wind_vane_table[i].degree; + } else { + if(i == 15) { + return (int)wind_vane_table[i].degree; + } + } + } + + PRINTF("Weather: invalid wind vane value\n"); + return WEATHER_METER_ERROR; +} +/*---------------------------------------------------------------------------*/ +static int +weather_meter_get_wind_dir(void) +{ + weather_sensors.wind_vane = adc_sensors.value(WIND_VANE_ADC); + if((int16_t)weather_sensors.wind_vane < 0) { + weather_sensors.wind_vane = 0; + } + return weather_meter_wind_vane_degrees(weather_sensors.wind_vane); +} /*---------------------------------------------------------------------------*/ void rt_callback(struct rtimer *t, void *ptr) { uint32_t wind_speed; + int16_t wind_dir; + int16_t wind_dir_delta; /* Disable to make the calculations in an interrupt-safe context */ GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, @@ -124,14 +207,43 @@ rt_callback(struct rtimer *t, void *ptr) anemometer.value_max = weather_sensors.anemometer.value; } - /* Average every 2 minutes */ + /* Mitsuta method to get the wind direction average */ + wind_dir = weather_meter_get_wind_dir(); + wind_dir_delta = wind_dir - wind_vane.value_prev; + + if(wind_dir_delta < -1800) { + wind_vane.value_prev += wind_dir_delta + 3600; + } else if(wind_dir_delta > 1800) { + wind_vane.value_prev += wind_dir_delta - 3600; + } else { + wind_vane.value_prev += wind_dir_delta; + } + + wind_vane.value_buf_2m += wind_vane.value_prev; + + /* Calculate the 2 minute average */ if(!(anemometer.ticks_avg % 120)) { + PRINTF("Weather: calculate the 2m averages ***\n"); + if(anemometer.value_buf_2m) { anemometer.value_avg_2m = anemometer.value_buf_2m / 120; anemometer.value_buf_2m = 0; } else { anemometer.value_avg_2m = 0; } + + wind_vane.value_buf_2m = wind_vane.value_buf_2m / 120; + wind_vane.value_avg_2m = (uint16_t)wind_vane.value_buf_2m; + if(wind_vane.value_avg_2m >= 3600) { + wind_vane.value_avg_2m -= 3600; + } + + if(wind_vane.value_avg_2m < 0) { + wind_vane.value_avg_2m += 3600; + } + + wind_vane.value_buf_2m = 0; + wind_vane.value_prev = wind_dir; } /* Check for roll-over */ @@ -211,6 +323,7 @@ value(int type) if((type != WEATHER_METER_ANEMOMETER) && (type != WEATHER_METER_RAIN_GAUGE) && (type != WEATHER_METER_WIND_VANE) && + (type != WEATHER_METER_WIND_VANE_AVG_2M) && (type != WEATHER_METER_ANEMOMETER_AVG) && (type != WEATHER_METER_ANEMOMETER_AVG_2M) && (type != WEATHER_METER_ANEMOMETER_MAX)) { @@ -225,9 +338,10 @@ value(int type) switch(type) { case WEATHER_METER_WIND_VANE: - /* FIXME: return the values in degrees */ - weather_sensors.wind_vane = adc_sensors.value(WIND_VANE_ADC); - return weather_sensors.wind_vane; + return weather_meter_get_wind_dir(); + + case WEATHER_METER_WIND_VANE_AVG_2M: + return wind_vane.value_avg_2m; case WEATHER_METER_ANEMOMETER: return weather_sensors.anemometer.value; @@ -322,6 +436,10 @@ configure(int type, int value) RAIN_GAUGE_SENSOR_PIN); process_start(&weather_meter_int_process, NULL); + + /* Initialize here prior the first second tick */ + wind_vane.value_prev = weather_meter_get_wind_dir(); + rtimer_set(&rt, RTIMER_NOW() + RTIMER_SECOND, 1, rt_callback, NULL); GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK); diff --git a/platform/zoul/dev/weather-meter.h b/platform/zoul/dev/weather-meter.h index 47ef859f3..1ce941968 100644 --- a/platform/zoul/dev/weather-meter.h +++ b/platform/zoul/dev/weather-meter.h @@ -55,10 +55,11 @@ */ #define WEATHER_METER_RAIN_GAUGE 0x01 #define WEATHER_METER_WIND_VANE 0x02 -#define WEATHER_METER_ANEMOMETER 0x03 -#define WEATHER_METER_ANEMOMETER_AVG 0x04 -#define WEATHER_METER_ANEMOMETER_AVG_2M 0x05 -#define WEATHER_METER_ANEMOMETER_MAX 0x06 +#define WEATHER_METER_WIND_VANE_AVG_2M 0x03 +#define WEATHER_METER_ANEMOMETER 0x04 +#define WEATHER_METER_ANEMOMETER_AVG 0x05 +#define WEATHER_METER_ANEMOMETER_AVG_2M 0x06 +#define WEATHER_METER_ANEMOMETER_MAX 0x07 #define WEATHER_METER_ACTIVE SENSORS_ACTIVE #define WEATHER_METER_ANEMOMETER_INT_OVER HW_INT_OVER_THRS @@ -75,6 +76,7 @@ /* 0.2794mm per tick */ #define WEATHER_METER_AUX_RAIN_MM 2794 +/* Allows to select the return type: ticks or converted value (truncated) */ #ifdef WEATHER_METER_RAIN_CONF_RETURN #define WEATHER_METER_RAIN_RETURN_TICKS WEATHER_METER_RAIN_CONF_RETURN #else From 81bec49a40182a6ec1b195aac127c9a17ec2df68 Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Tue, 19 Jan 2016 18:00:18 +0100 Subject: [PATCH 6/8] Changed fixed 2 minute integration period to allow overriding --- examples/zolertia/zoul/test-weather-meter.c | 7 ++- platform/zoul/dev/weather-meter.c | 50 ++++++++++----------- platform/zoul/dev/weather-meter.h | 11 ++++- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c index 93998d9e8..17417fea1 100644 --- a/examples/zolertia/zoul/test-weather-meter.c +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -97,6 +97,9 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) static uint16_t wind_speed_avg_2m; static uint16_t wind_speed_max; + printf("Weather meter test example, integration period %u\n", + WEATHER_METER_AVG_PERIOD); + /* Register the callback handler when thresholds are met */ WEATHER_METER_REGISTER_ANEMOMETER_INT(wind_speed_callback); WEATHER_METER_REGISTER_RAIN_GAUGE_INT(rain_callback); @@ -120,9 +123,9 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) rain = weather_meter.value(WEATHER_METER_RAIN_GAUGE); wind_speed = weather_meter.value(WEATHER_METER_ANEMOMETER); wind_dir = weather_meter.value(WEATHER_METER_WIND_VANE); - wind_dir_avg_2m = weather_meter.value(WEATHER_METER_WIND_VANE_AVG_2M); + wind_dir_avg_2m = weather_meter.value(WEATHER_METER_WIND_VANE_AVG_X); wind_speed_avg = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG); - wind_speed_avg_2m = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_2M); + wind_speed_avg_2m = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_X); wind_speed_max = weather_meter.value(WEATHER_METER_ANEMOMETER_MAX); #if WEATHER_METER_RAIN_RETURN_TICKS diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index 98324b0d0..f7b972180 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -91,8 +91,8 @@ typedef struct { uint16_t value_max; uint64_t ticks_avg; uint64_t value_avg; - uint32_t value_buf_2m; - uint16_t value_avg_2m; + uint32_t value_buf_xm; + uint16_t value_avg_xm; } weather_meter_ext_t; typedef struct { @@ -102,9 +102,9 @@ typedef struct { } weather_meter_sensors; typedef struct { - uint32_t value_buf_2m; + uint32_t value_buf_xm; uint16_t value_prev; - uint16_t value_avg_2m; + uint16_t value_avg_xm; } weather_meter_wind_vane_ext_t; static weather_meter_sensors weather_sensors; @@ -200,7 +200,7 @@ rt_callback(struct rtimer *t, void *ptr) weather_sensors.anemometer.value = (uint16_t)wind_speed; anemometer.ticks_avg++; anemometer.value_avg += weather_sensors.anemometer.value; - anemometer.value_buf_2m += weather_sensors.anemometer.value; + anemometer.value_buf_xm += weather_sensors.anemometer.value; /* Take maximum value */ if(weather_sensors.anemometer.value > anemometer.value_max) { @@ -219,30 +219,30 @@ rt_callback(struct rtimer *t, void *ptr) wind_vane.value_prev += wind_dir_delta; } - wind_vane.value_buf_2m += wind_vane.value_prev; + wind_vane.value_buf_xm += wind_vane.value_prev; /* Calculate the 2 minute average */ - if(!(anemometer.ticks_avg % 120)) { - PRINTF("Weather: calculate the 2m averages ***\n"); + if(!(anemometer.ticks_avg % WEATHER_METER_AVG_PERIOD)) { + PRINTF("Weather: calculate the %u averages ***\n", WEATHER_METER_AVG_PERIOD); - if(anemometer.value_buf_2m) { - anemometer.value_avg_2m = anemometer.value_buf_2m / 120; - anemometer.value_buf_2m = 0; + if(anemometer.value_buf_xm) { + anemometer.value_avg_xm = anemometer.value_buf_xm / WEATHER_METER_AVG_PERIOD; + anemometer.value_buf_xm = 0; } else { - anemometer.value_avg_2m = 0; + anemometer.value_avg_xm = 0; } - wind_vane.value_buf_2m = wind_vane.value_buf_2m / 120; - wind_vane.value_avg_2m = (uint16_t)wind_vane.value_buf_2m; - if(wind_vane.value_avg_2m >= 3600) { - wind_vane.value_avg_2m -= 3600; + wind_vane.value_buf_xm = wind_vane.value_buf_xm / WEATHER_METER_AVG_PERIOD; + wind_vane.value_avg_xm = (uint16_t)wind_vane.value_buf_xm; + if(wind_vane.value_avg_xm >= 3600) { + wind_vane.value_avg_xm -= 3600; } - if(wind_vane.value_avg_2m < 0) { - wind_vane.value_avg_2m += 3600; + if(wind_vane.value_avg_xm < 0) { + wind_vane.value_avg_xm += 3600; } - wind_vane.value_buf_2m = 0; + wind_vane.value_buf_xm = 0; wind_vane.value_prev = wind_dir; } @@ -323,9 +323,9 @@ value(int type) if((type != WEATHER_METER_ANEMOMETER) && (type != WEATHER_METER_RAIN_GAUGE) && (type != WEATHER_METER_WIND_VANE) && - (type != WEATHER_METER_WIND_VANE_AVG_2M) && + (type != WEATHER_METER_WIND_VANE_AVG_X) && (type != WEATHER_METER_ANEMOMETER_AVG) && - (type != WEATHER_METER_ANEMOMETER_AVG_2M) && + (type != WEATHER_METER_ANEMOMETER_AVG_X) && (type != WEATHER_METER_ANEMOMETER_MAX)) { PRINTF("Weather: requested an invalid sensor value\n"); return WEATHER_METER_ERROR; @@ -340,8 +340,8 @@ value(int type) case WEATHER_METER_WIND_VANE: return weather_meter_get_wind_dir(); - case WEATHER_METER_WIND_VANE_AVG_2M: - return wind_vane.value_avg_2m; + case WEATHER_METER_WIND_VANE_AVG_X: + return wind_vane.value_avg_xm; case WEATHER_METER_ANEMOMETER: return weather_sensors.anemometer.value; @@ -353,8 +353,8 @@ value(int type) aux = anemometer.value_avg / anemometer.ticks_avg; return (uint16_t)aux; - case WEATHER_METER_ANEMOMETER_AVG_2M: - return anemometer.value_avg_2m; + case WEATHER_METER_ANEMOMETER_AVG_X: + return anemometer.value_avg_xm; case WEATHER_METER_ANEMOMETER_MAX: return anemometer.value_max; diff --git a/platform/zoul/dev/weather-meter.h b/platform/zoul/dev/weather-meter.h index 1ce941968..9f6d1fc7f 100644 --- a/platform/zoul/dev/weather-meter.h +++ b/platform/zoul/dev/weather-meter.h @@ -55,12 +55,19 @@ */ #define WEATHER_METER_RAIN_GAUGE 0x01 #define WEATHER_METER_WIND_VANE 0x02 -#define WEATHER_METER_WIND_VANE_AVG_2M 0x03 +#define WEATHER_METER_WIND_VANE_AVG_X 0x03 #define WEATHER_METER_ANEMOMETER 0x04 #define WEATHER_METER_ANEMOMETER_AVG 0x05 -#define WEATHER_METER_ANEMOMETER_AVG_2M 0x06 +#define WEATHER_METER_ANEMOMETER_AVG_X 0x06 #define WEATHER_METER_ANEMOMETER_MAX 0x07 +/* Period (seconds) to calculate an average */ +#ifdef WEATHER_METER_CONF_AVG_PERIOD +#define WEATHER_METER_AVG_PERIOD WEATHER_METER_CONF_AVG_PERIOD +#else +#define WEATHER_METER_AVG_PERIOD 120 +#endif + #define WEATHER_METER_ACTIVE SENSORS_ACTIVE #define WEATHER_METER_ANEMOMETER_INT_OVER HW_INT_OVER_THRS #define WEATHER_METER_ANEMOMETER_INT_DIS HW_INT_DISABLE From 366f11d5df773b3dae5802289520e7bc5056254e Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Tue, 19 Jan 2016 18:03:16 +0100 Subject: [PATCH 7/8] Uncrustified weather meter driver and example --- examples/zolertia/zoul/test-weather-meter.c | 16 ++-- platform/zoul/dev/weather-meter.c | 91 ++++++++++----------- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/examples/zolertia/zoul/test-weather-meter.c b/examples/zolertia/zoul/test-weather-meter.c index 17417fea1..2e2bcba2f 100644 --- a/examples/zolertia/zoul/test-weather-meter.c +++ b/examples/zolertia/zoul/test-weather-meter.c @@ -128,14 +128,14 @@ PROCESS_THREAD(test_weather_meter_sensors, ev, data) wind_speed_avg_2m = weather_meter.value(WEATHER_METER_ANEMOMETER_AVG_X); wind_speed_max = weather_meter.value(WEATHER_METER_ANEMOMETER_MAX); - #if WEATHER_METER_RAIN_RETURN_TICKS - rain *= WEATHER_METER_AUX_RAIN_MM; - if(rain > (WEATHER_METER_AUX_RAIN_MM * 3)) { - printf("Rain: %lu.%lu mm, ", (rain / 10000), (rain % 10000)); - #else - if(rain >= 10) { - printf("Rain: %u.%u mm, ", (rain / 10), (rain % 10)); - #endif +#if WEATHER_METER_RAIN_RETURN_TICKS + rain *= WEATHER_METER_AUX_RAIN_MM; + if(rain > (WEATHER_METER_AUX_RAIN_MM * 3)) { + printf("Rain: %lu.%lu mm, ", (rain / 10000), (rain % 10000)); +#else + if(rain >= 10) { + printf("Rain: %u.%u mm, ", (rain / 10), (rain % 10)); +#endif } else { printf("Rain: 0.%lu mm, ", rain); } diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index f7b972180..933fc975d 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -83,7 +83,7 @@ static struct timer debouncetimer; typedef struct { uint16_t ticks; uint16_t value; - uint8_t int_en; + uint8_t int_en; uint16_t int_thres; } weather_meter_sensors_t; @@ -116,28 +116,28 @@ typedef struct { uint16_t degree; } wind_vane_mid_point_t; - /* From the datasheet we adjusted the values for a 3V divider, using a 10K - * resistor, the check values are the following: - * --------------------+------------------+------------------------------- - * Direction (Degrees) Resistance (Ohms) Voltage (mV) - * 0 33k 2532.55 * - * 22.5 6.57k 1308.44 * - * 45 8.2k 1486.81 * - * 67.5 891 269.97 * - * 90 1k 300.00 * - * 112.5 688 212.42 * - * 135 2.2k 595.08 * - * 157.5 1.41k 407.80 * - * 180 3.9k 925.89 * - * 202.5 3.14k 788.58 * - * 225 16k 2030.76 * - * 247.5 14.12k 1930.84 * - * 270 120k 3046.15 * - * 292.5 42.12k 2666.84 * - * 315 64.9k 2859.41 * - * 337.5 21.88k 2264.86 * - * --------------------+------------------+------------------------------- - */ +/* From the datasheet we adjusted the values for a 3V divider, using a 10K + * resistor, the check values are the following: + * --------------------+------------------+------------------------------- + * Direction (Degrees) Resistance (Ohms) Voltage (mV) + * 0 33k 2532.55 * + * 22.5 6.57k 1308.44 * + * 45 8.2k 1486.81 * + * 67.5 891 269.97 * + * 90 1k 300.00 * + * 112.5 688 212.42 * + * 135 2.2k 595.08 * + * 157.5 1.41k 407.80 * + * 180 3.9k 925.89 * + * 202.5 3.14k 788.58 * + * 225 16k 2030.76 * + * 247.5 14.12k 1930.84 * + * 270 120k 3046.15 * + * 292.5 42.12k 2666.84 * + * 315 64.9k 2859.41 * + * 337.5 21.88k 2264.86 * + * --------------------+------------------+------------------------------- + */ static const wind_vane_mid_point_t wind_vane_table[16] = { { 2124, 1125 }, { 2699, 675 }, @@ -161,7 +161,7 @@ static int weather_meter_wind_vane_degrees(uint16_t value) { uint8_t i; - for(i=0; i<16; i++) { + for(i = 0; i < 16; i++) { if(value <= wind_vane_table[i].mid_point) { return (int)wind_vane_table[i].degree; } else { @@ -232,13 +232,13 @@ rt_callback(struct rtimer *t, void *ptr) anemometer.value_avg_xm = 0; } - wind_vane.value_buf_xm = wind_vane.value_buf_xm / WEATHER_METER_AVG_PERIOD; + wind_vane.value_buf_xm = wind_vane.value_buf_xm / WEATHER_METER_AVG_PERIOD; wind_vane.value_avg_xm = (uint16_t)wind_vane.value_buf_xm; - if(wind_vane.value_avg_xm >= 3600) { + if(wind_vane.value_avg_xm >= 3600) { wind_vane.value_avg_xm -= 3600; } - if(wind_vane.value_avg_xm < 0) { + if(wind_vane.value_avg_xm < 0) { wind_vane.value_avg_xm += 3600; } @@ -271,14 +271,14 @@ PROCESS_THREAD(weather_meter_int_process, ev, data) if((ev == anemometer_int_event) && (weather_sensors.anemometer.int_en)) { if(weather_sensors.anemometer.ticks >= - weather_sensors.anemometer.int_thres) { + weather_sensors.anemometer.int_thres) { anemometer_int_callback(weather_sensors.anemometer.ticks); } } if((ev == rain_gauge_int_event) && (weather_sensors.rain_gauge.int_en)) { if(weather_sensors.rain_gauge.ticks >= - weather_sensors.rain_gauge.int_thres) { + weather_sensors.rain_gauge.int_thres) { rain_gauge_int_callback(weather_sensors.rain_gauge.ticks); } } @@ -305,7 +305,6 @@ weather_meter_interrupt_handler(uint8_t port, uint8_t pin) if((port == ANEMOMETER_SENSOR_PORT) && (pin == ANEMOMETER_SENSOR_PIN)) { weather_sensors.anemometer.ticks++; process_post(&weather_meter_int_process, anemometer_int_event, NULL); - } else if((port == RAIN_GAUGE_SENSOR_PORT) && (pin == RAIN_GAUGE_SENSOR_PIN)) { weather_sensors.rain_gauge.ticks++; aux = weather_sensors.rain_gauge.ticks * WEATHER_METER_AUX_RAIN_MM; @@ -321,12 +320,12 @@ value(int type) uint64_t aux; if((type != WEATHER_METER_ANEMOMETER) && - (type != WEATHER_METER_RAIN_GAUGE) && - (type != WEATHER_METER_WIND_VANE) && - (type != WEATHER_METER_WIND_VANE_AVG_X) && - (type != WEATHER_METER_ANEMOMETER_AVG) && - (type != WEATHER_METER_ANEMOMETER_AVG_X) && - (type != WEATHER_METER_ANEMOMETER_MAX)) { + (type != WEATHER_METER_RAIN_GAUGE) && + (type != WEATHER_METER_WIND_VANE) && + (type != WEATHER_METER_WIND_VANE_AVG_X) && + (type != WEATHER_METER_ANEMOMETER_AVG) && + (type != WEATHER_METER_ANEMOMETER_AVG_X) && + (type != WEATHER_METER_ANEMOMETER_MAX)) { PRINTF("Weather: requested an invalid sensor value\n"); return WEATHER_METER_ERROR; } @@ -364,11 +363,11 @@ value(int type) * ticks and calculating on your own with WEATHER_METER_AUX_RAIN_MM */ case WEATHER_METER_RAIN_GAUGE: - #if WEATHER_METER_RAIN_RETURN_TICKS - return weather_sensors.rain_gauge.ticks; - #else - return weather_sensors.rain_gauge.value; - #endif +#if WEATHER_METER_RAIN_RETURN_TICKS + return weather_sensors.rain_gauge.ticks; +#else + return weather_sensors.rain_gauge.value; +#endif default: return WEATHER_METER_ERROR; @@ -378,11 +377,11 @@ value(int type) static int configure(int type, int value) { - if((type != WEATHER_METER_ACTIVE) && - (type != WEATHER_METER_ANEMOMETER_INT_OVER) && - (type != WEATHER_METER_RAIN_GAUGE_INT_OVER) && - (type != WEATHER_METER_ANEMOMETER_INT_DIS) && - (type != WEATHER_METER_RAIN_GAUGE_INT_DIS)) { + if((type != WEATHER_METER_ACTIVE) && + (type != WEATHER_METER_ANEMOMETER_INT_OVER) && + (type != WEATHER_METER_RAIN_GAUGE_INT_OVER) && + (type != WEATHER_METER_ANEMOMETER_INT_DIS) && + (type != WEATHER_METER_RAIN_GAUGE_INT_DIS)) { PRINTF("Weather: invalid configuration option\n"); return WEATHER_METER_ERROR; } From a6c30b4e09546686aad1bc9d9f340d77e80a6a0a Mon Sep 17 00:00:00 2001 From: Antonio Lignan Date: Tue, 19 Jan 2016 22:23:30 +0100 Subject: [PATCH 8/8] Fixed missing static keyword in both zoul-demo and weather meter driver --- examples/zolertia/zoul/zoul-demo.c | 2 +- platform/zoul/dev/weather-meter.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/zolertia/zoul/zoul-demo.c b/examples/zolertia/zoul/zoul-demo.c index 127c18d50..a88e7c48c 100644 --- a/examples/zolertia/zoul/zoul-demo.c +++ b/examples/zolertia/zoul/zoul-demo.c @@ -108,7 +108,7 @@ broadcast_recv(struct broadcast_conn *c, const linkaddr_t *from) static const struct broadcast_callbacks bc_rx = { broadcast_recv }; static struct broadcast_conn bc; /*---------------------------------------------------------------------------*/ -void +static void rt_callback(struct rtimer *t, void *ptr) { leds_off(LEDS_PERIODIC); diff --git a/platform/zoul/dev/weather-meter.c b/platform/zoul/dev/weather-meter.c index 933fc975d..8d3ee07f1 100644 --- a/platform/zoul/dev/weather-meter.c +++ b/platform/zoul/dev/weather-meter.c @@ -185,7 +185,7 @@ weather_meter_get_wind_dir(void) return weather_meter_wind_vane_degrees(weather_sensors.wind_vane); } /*---------------------------------------------------------------------------*/ -void +static void rt_callback(struct rtimer *t, void *ptr) { uint32_t wind_speed; @@ -223,7 +223,7 @@ rt_callback(struct rtimer *t, void *ptr) /* Calculate the 2 minute average */ if(!(anemometer.ticks_avg % WEATHER_METER_AVG_PERIOD)) { - PRINTF("Weather: calculate the %u averages ***\n", WEATHER_METER_AVG_PERIOD); + PRINTF("\nWeather: calculate the %u averages ***\n", WEATHER_METER_AVG_PERIOD); if(anemometer.value_buf_xm) { anemometer.value_avg_xm = anemometer.value_buf_xm / WEATHER_METER_AVG_PERIOD;