Contiki-NG
weather-meter.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, Zolertia <http://www.zolertia.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32/*---------------------------------------------------------------------------*/
33/**
34 * \addtogroup zoul-weather-meter-sensor
35 * @{
36 *
37 * The Sparkfun's weather meter comprises an anemometer, wind vane and rain
38 * gauge, see https://www.sparkfun.com/products/8942
39 *
40 * \file
41 * Weather meter sensor driver
42 * \author
43 * Antonio Lignan <alinan@zolertia.com>
44 */
45/*---------------------------------------------------------------------------*/
46#include <stdio.h>
47#include "contiki.h"
48#include "dev/adc-zoul.h"
49#include "dev/weather-meter.h"
50#include "dev/zoul-sensors.h"
51#include "lib/sensors.h"
52#include "dev/sys-ctrl.h"
53#include "dev/gpio.h"
54#include "dev/gpio-hal.h"
55#include "dev/ioc.h"
56#include "sys/timer.h"
57#include "sys/ctimer.h"
58/*---------------------------------------------------------------------------*/
59#define DEBUG 0
60#if DEBUG
61#define PRINTF(...) printf(__VA_ARGS__)
62#else
63#define PRINTF(...)
64#endif
65/*---------------------------------------------------------------------------*/
66#define DEBOUNCE_DURATION (CLOCK_SECOND >> 6)
67/*---------------------------------------------------------------------------*/
68#define ANEMOMETER_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(ANEMOMETER_SENSOR_PORT)
69#define ANEMOMETER_SENSOR_PIN_MASK GPIO_PIN_MASK(ANEMOMETER_SENSOR_PIN)
70#define RAIN_GAUGE_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(RAIN_GAUGE_SENSOR_PORT)
71#define RAIN_GAUGE_SENSOR_PIN_MASK GPIO_PIN_MASK(RAIN_GAUGE_SENSOR_PIN)
72/*---------------------------------------------------------------------------*/
73void (*rain_gauge_int_callback)(uint16_t value);
74void (*anemometer_int_callback)(uint16_t value);
75/*---------------------------------------------------------------------------*/
76static uint8_t enabled;
77/*---------------------------------------------------------------------------*/
78process_event_t anemometer_int_event;
79process_event_t rain_gauge_int_event;
80/*---------------------------------------------------------------------------*/
81static struct ctimer ct;
82static struct timer debouncetimer;
83/*---------------------------------------------------------------------------*/
84typedef struct {
85 uint16_t ticks;
86 uint16_t value;
87 uint8_t int_en;
88 uint16_t int_thres;
89} weather_meter_sensors_t;
90
91typedef struct {
92 uint16_t value_max;
93 uint64_t ticks_avg;
94 uint64_t value_avg;
95 uint32_t value_buf_xm;
96 uint16_t value_avg_xm;
97} weather_meter_ext_t;
98
99typedef struct {
100 uint16_t wind_vane;
101 weather_meter_sensors_t rain_gauge;
102 weather_meter_sensors_t anemometer;
103} weather_meter_sensors;
104
105typedef struct {
106 int32_t value_buf_xm;
107 int16_t value_prev;
108 int16_t value_avg_xm;
109} weather_meter_wind_vane_ext_t;
110
111static weather_meter_sensors weather_sensors;
112static weather_meter_ext_t anemometer;
113static weather_meter_wind_vane_ext_t wind_vane;
114/*---------------------------------------------------------------------------*/
115typedef struct {
116 uint16_t mid_point;
117 uint16_t degree;
118} wind_vane_mid_point_t;
119
120/* From the datasheet we adjusted the values for a 3V divider, using a 10K
121 * resistor, the check values are the following:
122 * --------------------+------------------+-------------------------------
123 * Direction (Degrees) Resistance (Ohms) Voltage (mV)
124 * 0 33k 2532.55 *
125 * 22.5 6.57k 1308.44 *
126 * 45 8.2k 1486.81 *
127 * 67.5 891 269.97 *
128 * 90 1k 300.00 *
129 * 112.5 688 212.42 *
130 * 135 2.2k 595.08 *
131 * 157.5 1.41k 407.80 *
132 * 180 3.9k 925.89 *
133 * 202.5 3.14k 788.58 *
134 * 225 16k 2030.76 *
135 * 247.5 14.12k 1930.84 *
136 * 270 120k 3046.15 *
137 * 292.5 42.12k 2666.84 *
138 * 315 64.9k 2859.41 *
139 * 337.5 21.88k 2264.86 *
140 * --------------------+------------------+-------------------------------
141 */
142static const wind_vane_mid_point_t wind_vane_table[16] = {
143 { 2124, 1125 },
144 { 2699, 675 },
145 { 3000, 900 },
146 { 4078, 1575 },
147 { 5950, 1350 },
148 { 7885, 2025 },
149 { 9258, 1800 },
150 { 13084, 225 },
151 { 14868, 450 },
152 { 19308, 2475 },
153 { 20307, 2250 },
154 { 22648, 3375 },
155 { 25325, 0 },
156 { 26668, 2925 },
157 { 28594, 3150 },
158 { 30461, 2700 },
159};
160/*---------------------------------------------------------------------------*/
161static int
162weather_meter_wind_vane_degrees(uint16_t value)
163{
164 uint8_t i;
165 for(i = 0; i < 16; i++) {
166 if(value <= wind_vane_table[i].mid_point) {
167 return (int)wind_vane_table[i].degree;
168 } else {
169 if(i == 15) {
170 return (int)wind_vane_table[i].degree;
171 }
172 }
173 }
174
175 PRINTF("Weather: invalid wind vane value\n");
176 return WEATHER_METER_ERROR;
177}
178/*---------------------------------------------------------------------------*/
179static int
180weather_meter_get_wind_dir(void)
181{
182 weather_sensors.wind_vane = adc_zoul.value(WIND_VANE_ADC);
183 if((int16_t)weather_sensors.wind_vane < 0) {
184 weather_sensors.wind_vane = 0;
185 }
186 return weather_meter_wind_vane_degrees(weather_sensors.wind_vane);
187}
188/*---------------------------------------------------------------------------*/
189static void
190ct_callback(void *ptr)
191{
192 uint32_t wind_speed;
193 int16_t wind_dir;
194 int16_t wind_dir_delta;
195
196 /* Disable to make the calculations in an interrupt-safe context */
197 GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
198 ANEMOMETER_SENSOR_PIN_MASK);
199 wind_speed = weather_sensors.anemometer.ticks;
200 wind_speed *= WEATHER_METER_ANEMOMETER_SPEED_1S;
201 weather_sensors.anemometer.value = (uint16_t)wind_speed;
202 anemometer.ticks_avg++;
203 anemometer.value_avg += weather_sensors.anemometer.value;
204 anemometer.value_buf_xm += weather_sensors.anemometer.value;
205
206 /* Take maximum value */
207 if(weather_sensors.anemometer.value > anemometer.value_max) {
208 anemometer.value_max = weather_sensors.anemometer.value;
209 }
210
211 /* Mitsuta method to get the wind direction average */
212 wind_dir = weather_meter_get_wind_dir();
213 wind_dir_delta = wind_dir - wind_vane.value_prev;
214
215 if(wind_dir_delta < -1800) {
216 wind_vane.value_prev += wind_dir_delta + 3600;
217 } else if(wind_dir_delta > 1800) {
218 wind_vane.value_prev += wind_dir_delta - 3600;
219 } else {
220 wind_vane.value_prev += wind_dir_delta;
221 }
222
223 wind_vane.value_buf_xm += wind_vane.value_prev;
224
225 /* Calculate the 2 minute average */
226 if(!(anemometer.ticks_avg % WEATHER_METER_AVG_PERIOD)) {
227 PRINTF("\nWeather: calculate the %u averages ***\n", WEATHER_METER_AVG_PERIOD);
228
229 if(anemometer.value_buf_xm) {
230 anemometer.value_avg_xm = anemometer.value_buf_xm / WEATHER_METER_AVG_PERIOD;
231 anemometer.value_buf_xm = 0;
232 } else {
233 anemometer.value_avg_xm = 0;
234 }
235
236 if(wind_vane.value_buf_xm >= 0) {
237 wind_vane.value_buf_xm = wind_vane.value_buf_xm / WEATHER_METER_AVG_PERIOD;
238 wind_vane.value_avg_xm = wind_vane.value_buf_xm;
239 } else {
240 wind_vane.value_buf_xm = ABS(wind_vane.value_buf_xm) / WEATHER_METER_AVG_PERIOD;
241 wind_vane.value_avg_xm = wind_vane.value_buf_xm;
242 wind_vane.value_avg_xm = ~wind_vane.value_avg_xm + 1;
243 }
244
245 if(wind_vane.value_avg_xm >= 3600) {
246 wind_vane.value_avg_xm -= 3600;
247 } else if(wind_vane.value_avg_xm < 0) {
248 wind_vane.value_avg_xm += 3600;
249 }
250
251 wind_vane.value_buf_xm = 0;
252 wind_vane.value_prev = wind_dir;
253 }
254
255 /* Check for roll-over */
256 if(!anemometer.ticks_avg) {
257 anemometer.value_avg = 0;
258 }
259
260 weather_sensors.anemometer.ticks = 0;
261
262 /* Enable the interrupt again */
263 GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
264 ANEMOMETER_SENSOR_PIN_MASK);
265
266 ctimer_set(&ct, CLOCK_SECOND, ct_callback, NULL);
267}
268/*---------------------------------------------------------------------------*/
269PROCESS(weather_meter_int_process, "Weather meter interrupt process handler");
270/*---------------------------------------------------------------------------*/
271PROCESS_THREAD(weather_meter_int_process, ev, data)
272{
275
276 while(1) {
278
279 if((ev == anemometer_int_event) && (weather_sensors.anemometer.int_en)) {
280 if(weather_sensors.anemometer.ticks >=
281 weather_sensors.anemometer.int_thres) {
282 anemometer_int_callback(weather_sensors.anemometer.ticks);
283 }
284 }
285
286 if((ev == rain_gauge_int_event) && (weather_sensors.rain_gauge.int_en)) {
287 if(weather_sensors.rain_gauge.ticks >=
288 weather_sensors.rain_gauge.int_thres) {
289 rain_gauge_int_callback(weather_sensors.rain_gauge.ticks);
290 }
291 }
292 }
293 PROCESS_END();
294}
295/*---------------------------------------------------------------------------*/
296static void weather_meter_interrupt_handler(gpio_hal_pin_mask_t pin_mask);
297/*---------------------------------------------------------------------------*/
298static gpio_hal_event_handler_t rain_handler = {
299 .next = NULL,
300 .handler = weather_meter_interrupt_handler,
301 .pin_mask = gpio_hal_pin_to_mask(RAIN_GAUGE_SENSOR_PIN) << (RAIN_GAUGE_SENSOR_PORT << 3),
302};
303/*---------------------------------------------------------------------------*/
304static gpio_hal_event_handler_t anemometer_handler = {
305 .next = NULL,
306 .handler = weather_meter_interrupt_handler,
307 .pin_mask = gpio_hal_pin_to_mask(ANEMOMETER_SENSOR_PIN) << (ANEMOMETER_SENSOR_PORT << 3),
308};
309/*---------------------------------------------------------------------------*/
310static void
311weather_meter_interrupt_handler(gpio_hal_pin_mask_t pin_mask)
312{
313 uint32_t aux;
314
315 /* Prevent bounce events */
316 if(!timer_expired(&debouncetimer)) {
317 return;
318 }
319
320 timer_set(&debouncetimer, DEBOUNCE_DURATION);
321
322 /* We make a process_post() to check in the pollhandler any specific threshold
323 * value
324 */
325
326 if(pin_mask == rain_handler.pin_mask) {
327 weather_sensors.anemometer.ticks++;
328 process_post(&weather_meter_int_process, anemometer_int_event, NULL);
329 } else if(pin_mask == anemometer_handler.pin_mask) {
330 weather_sensors.rain_gauge.ticks++;
331 aux = weather_sensors.rain_gauge.ticks * WEATHER_METER_AUX_RAIN_MM;
332 aux /= 1000;
333 weather_sensors.rain_gauge.value = (uint16_t)aux;
334 process_post(&weather_meter_int_process, rain_gauge_int_event, NULL);
335 }
336}
337/*---------------------------------------------------------------------------*/
338static int
339value(int type)
340{
341 uint64_t aux;
342
343 if((type != WEATHER_METER_ANEMOMETER) &&
344 (type != WEATHER_METER_RAIN_GAUGE) &&
345 (type != WEATHER_METER_WIND_VANE) &&
346 (type != WEATHER_METER_WIND_VANE_AVG_X) &&
347 (type != WEATHER_METER_ANEMOMETER_AVG) &&
348 (type != WEATHER_METER_ANEMOMETER_AVG_X) &&
349 (type != WEATHER_METER_ANEMOMETER_MAX)) {
350 PRINTF("Weather: requested an invalid sensor value\n");
351 return WEATHER_METER_ERROR;
352 }
353
354 if(!enabled) {
355 PRINTF("Weather: module is not configured\n");
356 return WEATHER_METER_ERROR;
357 }
358
359 switch(type) {
360 case WEATHER_METER_WIND_VANE:
361 return weather_meter_get_wind_dir();
362
363 case WEATHER_METER_WIND_VANE_AVG_X:
364 return wind_vane.value_avg_xm;
365
366 case WEATHER_METER_ANEMOMETER:
367 return weather_sensors.anemometer.value;
368
369 case WEATHER_METER_ANEMOMETER_AVG:
370 if(anemometer.value_avg <= 0) {
371 return (uint16_t)anemometer.value_avg;
372 }
373 aux = anemometer.value_avg / anemometer.ticks_avg;
374 return (uint16_t)aux;
375
376 case WEATHER_METER_ANEMOMETER_AVG_X:
377 return anemometer.value_avg_xm;
378
379 case WEATHER_METER_ANEMOMETER_MAX:
380 return anemometer.value_max;
381
382 /* as the default return type is int, we have a lower resolution if returning
383 * the calculated value as it is truncated, an alternative is returning the
384 * ticks and calculating on your own with WEATHER_METER_AUX_RAIN_MM
385 */
386 case WEATHER_METER_RAIN_GAUGE:
387#if WEATHER_METER_RAIN_RETURN_TICKS
388 return weather_sensors.rain_gauge.ticks;
389#else
390 return weather_sensors.rain_gauge.value;
391#endif
392
393 default:
394 return WEATHER_METER_ERROR;
395 }
396}
397/*---------------------------------------------------------------------------*/
398static int
399configure(int type, int value)
400{
401 if((type != WEATHER_METER_ACTIVE) &&
402 (type != WEATHER_METER_ANEMOMETER_INT_OVER) &&
403 (type != WEATHER_METER_RAIN_GAUGE_INT_OVER) &&
404 (type != WEATHER_METER_ANEMOMETER_INT_DIS) &&
405 (type != WEATHER_METER_RAIN_GAUGE_INT_DIS)) {
406 PRINTF("Weather: invalid configuration option\n");
407 return WEATHER_METER_ERROR;
408 }
409
410 if(type == WEATHER_METER_ACTIVE) {
411
412 anemometer.value_avg = 0;
413 anemometer.ticks_avg = 0;
414
415 weather_sensors.anemometer.int_en = 0;
416 weather_sensors.rain_gauge.int_en = 0;
417 weather_sensors.anemometer.ticks = 0;
418 weather_sensors.rain_gauge.ticks = 0;
419 weather_sensors.anemometer.value = 0;
420 weather_sensors.rain_gauge.value = 0;
421
422 if(!value) {
423 anemometer_int_callback = NULL;
424 rain_gauge_int_callback = NULL;
425 GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
426 ANEMOMETER_SENSOR_PIN_MASK);
427 GPIO_DISABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE,
428 RAIN_GAUGE_SENSOR_PIN_MASK);
429 process_exit(&weather_meter_int_process);
430 enabled = 0;
431 PRINTF("Weather: disabled\n");
432 return WEATHER_METER_SUCCESS;
433 }
434
435 /* Configure the wind vane */
436 adc_zoul.configure(SENSORS_HW_INIT, WIND_VANE_ADC);
437
438 /* Configure anemometer interruption */
439 GPIO_SOFTWARE_CONTROL(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
440 GPIO_SET_INPUT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
441 GPIO_DETECT_RISING(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
442 GPIO_TRIGGER_SINGLE_EDGE(ANEMOMETER_SENSOR_PORT_BASE,
443 ANEMOMETER_SENSOR_PIN_MASK);
444 ioc_set_over(ANEMOMETER_SENSOR_PORT, ANEMOMETER_SENSOR_PIN, IOC_OVERRIDE_DIS);
445 gpio_hal_register_handler(&anemometer_handler);
446
447 /* Configure rain gauge interruption */
448 GPIO_SOFTWARE_CONTROL(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
449 GPIO_SET_INPUT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
450 GPIO_DETECT_RISING(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
451 GPIO_TRIGGER_SINGLE_EDGE(RAIN_GAUGE_SENSOR_PORT_BASE,
452 RAIN_GAUGE_SENSOR_PIN_MASK);
453 ioc_set_over(RAIN_GAUGE_SENSOR_PORT, RAIN_GAUGE_SENSOR_PIN, IOC_OVERRIDE_DIS);
454 gpio_hal_register_handler(&rain_handler);
455
456 process_start(&weather_meter_int_process, NULL);
457
458 /* Initialize here prior the first second tick */
459 wind_vane.value_prev = weather_meter_get_wind_dir();
460
461 ctimer_set(&ct, CLOCK_SECOND, ct_callback, NULL);
462
463 GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
464 GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
465 NVIC_EnableIRQ(ANEMOMETER_SENSOR_VECTOR);
466 NVIC_EnableIRQ(RAIN_GAUGE_SENSOR_VECTOR);
467
468 enabled = 1;
469 PRINTF("Weather: started\n");
470 return WEATHER_METER_SUCCESS;
471 }
472
473 switch(type) {
474 case WEATHER_METER_ANEMOMETER_INT_OVER:
475 weather_sensors.anemometer.int_en = 1;
476 weather_sensors.anemometer.int_thres = value;
477 PRINTF("Weather: anemometer threshold %u\n", value);
478 break;
479 case WEATHER_METER_RAIN_GAUGE_INT_OVER:
480 weather_sensors.rain_gauge.int_en = 1;
481 weather_sensors.rain_gauge.int_thres = value;
482 PRINTF("Weather: rain gauge threshold %u\n", value);
483 break;
484 case WEATHER_METER_ANEMOMETER_INT_DIS:
485 PRINTF("Weather: anemometer int disabled\n");
486 weather_sensors.anemometer.int_en = 0;
487 break;
488 case WEATHER_METER_RAIN_GAUGE_INT_DIS:
489 PRINTF("Weather: rain gauge int disabled\n");
490 weather_sensors.rain_gauge.int_en = 0;
491 break;
492 default:
493 return WEATHER_METER_ERROR;
494 }
495
496 return WEATHER_METER_SUCCESS;
497}
498/*---------------------------------------------------------------------------*/
499SENSORS_SENSOR(weather_meter, WEATHER_METER_SENSOR, value, configure, NULL);
500/*---------------------------------------------------------------------------*/
501/** @} */
502
Header file for the Zoul ADC interface.
Header file for the callback timer.
Header file for the GPIO HAL.
Header file with register and macro declarations for the cc2538 GPIO module.
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:258
#define GPIO_DISABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Disable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:209
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:78
#define GPIO_DETECT_RISING(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on rising edge.
Definition: gpio.h:185
#define GPIO_TRIGGER_SINGLE_EDGE(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to trigger an interrupt on single edge (controlled by G...
Definition: gpio.h:177
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:201
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
#define IOC_OVERRIDE_DIS
Override Disabled.
Definition: ioc.h:226
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void gpio_hal_register_handler(gpio_hal_event_handler_t *handler)
Register a function to be called whenever a pin triggers an event.
Definition: gpio-hal.c:55
uint32_t gpio_hal_pin_mask_t
GPIO pin mask representation.
Definition: gpio-hal.h:142
#define gpio_hal_pin_to_mask(pin)
Convert a pin to a pin mask.
Definition: gpio-hal.h:255
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD()
Yield the currently running process.
Definition: process.h:164
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:123
Header file with declarations for the I/O Control module.
Datatype for GPIO event handlers.
Definition: gpio-hal.h:180
A timer.
Definition: timer.h:82
Header file for the cc2538 System Control driver.
Timer library header file.
Weather meter header file.
Implementation of a generic module controlling Zoul sensors.