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