Contiki 3.x
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/ioc.h"
55 #include "sys/timer.h"
56 #include "sys/ctimer.h"
57 /*---------------------------------------------------------------------------*/
58 #define DEBUG 0
59 #if DEBUG
60 #define PRINTF(...) printf(__VA_ARGS__)
61 #else
62 #define PRINTF(...)
63 #endif
64 /*---------------------------------------------------------------------------*/
65 #define DEBOUNCE_DURATION (CLOCK_SECOND >> 6)
66 /*---------------------------------------------------------------------------*/
67 #define ANEMOMETER_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(ANEMOMETER_SENSOR_PORT)
68 #define ANEMOMETER_SENSOR_PIN_MASK GPIO_PIN_MASK(ANEMOMETER_SENSOR_PIN)
69 #define RAIN_GAUGE_SENSOR_PORT_BASE GPIO_PORT_TO_BASE(RAIN_GAUGE_SENSOR_PORT)
70 #define RAIN_GAUGE_SENSOR_PIN_MASK GPIO_PIN_MASK(RAIN_GAUGE_SENSOR_PIN)
71 /*---------------------------------------------------------------------------*/
72 void (*rain_gauge_int_callback)(uint16_t value);
73 void (*anemometer_int_callback)(uint16_t value);
74 /*---------------------------------------------------------------------------*/
75 static uint8_t enabled;
76 /*---------------------------------------------------------------------------*/
77 process_event_t anemometer_int_event;
78 process_event_t rain_gauge_int_event;
79 /*---------------------------------------------------------------------------*/
80 static struct ctimer ct;
81 static struct timer debouncetimer;
82 /*---------------------------------------------------------------------------*/
83 typedef struct {
84  uint16_t ticks;
85  uint16_t value;
86  uint8_t int_en;
87  uint16_t int_thres;
88 } weather_meter_sensors_t;
89 
90 typedef struct {
91  uint16_t value_max;
92  uint64_t ticks_avg;
93  uint64_t value_avg;
94  uint32_t value_buf_xm;
95  uint16_t value_avg_xm;
96 } weather_meter_ext_t;
97 
98 typedef struct {
99  uint16_t wind_vane;
100  weather_meter_sensors_t rain_gauge;
101  weather_meter_sensors_t anemometer;
102 } weather_meter_sensors;
103 
104 typedef struct {
105  int32_t value_buf_xm;
106  int16_t value_prev;
107  int16_t value_avg_xm;
108 } weather_meter_wind_vane_ext_t;
109 
110 static weather_meter_sensors weather_sensors;
111 static weather_meter_ext_t anemometer;
112 static weather_meter_wind_vane_ext_t wind_vane;
113 /*---------------------------------------------------------------------------*/
114 typedef struct {
115  uint16_t mid_point;
116  uint16_t degree;
117 } wind_vane_mid_point_t;
118 
119 /* From the datasheet we adjusted the values for a 3V divider, using a 10K
120  * resistor, the check values are the following:
121  * --------------------+------------------+-------------------------------
122  * Direction (Degrees) Resistance (Ohms) Voltage (mV)
123  * 0 33k 2532.55 *
124  * 22.5 6.57k 1308.44 *
125  * 45 8.2k 1486.81 *
126  * 67.5 891 269.97 *
127  * 90 1k 300.00 *
128  * 112.5 688 212.42 *
129  * 135 2.2k 595.08 *
130  * 157.5 1.41k 407.80 *
131  * 180 3.9k 925.89 *
132  * 202.5 3.14k 788.58 *
133  * 225 16k 2030.76 *
134  * 247.5 14.12k 1930.84 *
135  * 270 120k 3046.15 *
136  * 292.5 42.12k 2666.84 *
137  * 315 64.9k 2859.41 *
138  * 337.5 21.88k 2264.86 *
139  * --------------------+------------------+-------------------------------
140  */
141 static const wind_vane_mid_point_t wind_vane_table[16] = {
142  { 2124, 1125 },
143  { 2699, 675 },
144  { 3000, 900 },
145  { 4078, 1575 },
146  { 5950, 1350 },
147  { 7885, 2025 },
148  { 9258, 1800 },
149  { 13084, 225 },
150  { 14868, 450 },
151  { 19308, 2475 },
152  { 20307, 2250 },
153  { 22648, 3375 },
154  { 25325, 0 },
155  { 26668, 2925 },
156  { 28594, 3150 },
157  { 30461, 2700 },
158 };
159 /*---------------------------------------------------------------------------*/
160 static int
161 weather_meter_wind_vane_degrees(uint16_t value)
162 {
163  uint8_t i;
164  for(i = 0; i < 16; i++) {
165  if(value <= wind_vane_table[i].mid_point) {
166  return (int)wind_vane_table[i].degree;
167  } else {
168  if(i == 15) {
169  return (int)wind_vane_table[i].degree;
170  }
171  }
172  }
173 
174  PRINTF("Weather: invalid wind vane value\n");
175  return WEATHER_METER_ERROR;
176 }
177 /*---------------------------------------------------------------------------*/
178 static int
179 weather_meter_get_wind_dir(void)
180 {
181  weather_sensors.wind_vane = adc_zoul.value(WIND_VANE_ADC);
182  if((int16_t)weather_sensors.wind_vane < 0) {
183  weather_sensors.wind_vane = 0;
184  }
185  return weather_meter_wind_vane_degrees(weather_sensors.wind_vane);
186 }
187 /*---------------------------------------------------------------------------*/
188 static void
189 ct_callback(void *ptr)
190 {
191  uint32_t wind_speed;
192  int16_t wind_dir;
193  int16_t wind_dir_delta;
194 
195  /* Disable to make the calculations in an interrupt-safe context */
196  GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
197  ANEMOMETER_SENSOR_PIN_MASK);
198  wind_speed = weather_sensors.anemometer.ticks;
199  wind_speed *= WEATHER_METER_ANEMOMETER_SPEED_1S;
200  weather_sensors.anemometer.value = (uint16_t)wind_speed;
201  anemometer.ticks_avg++;
202  anemometer.value_avg += weather_sensors.anemometer.value;
203  anemometer.value_buf_xm += weather_sensors.anemometer.value;
204 
205  /* Take maximum value */
206  if(weather_sensors.anemometer.value > anemometer.value_max) {
207  anemometer.value_max = weather_sensors.anemometer.value;
208  }
209 
210  /* Mitsuta method to get the wind direction average */
211  wind_dir = weather_meter_get_wind_dir();
212  wind_dir_delta = wind_dir - wind_vane.value_prev;
213 
214  if(wind_dir_delta < -1800) {
215  wind_vane.value_prev += wind_dir_delta + 3600;
216  } else if(wind_dir_delta > 1800) {
217  wind_vane.value_prev += wind_dir_delta - 3600;
218  } else {
219  wind_vane.value_prev += wind_dir_delta;
220  }
221 
222  wind_vane.value_buf_xm += wind_vane.value_prev;
223 
224  /* Calculate the 2 minute average */
225  if(!(anemometer.ticks_avg % WEATHER_METER_AVG_PERIOD)) {
226  PRINTF("\nWeather: calculate the %u averages ***\n", WEATHER_METER_AVG_PERIOD);
227 
228  if(anemometer.value_buf_xm) {
229  anemometer.value_avg_xm = anemometer.value_buf_xm / WEATHER_METER_AVG_PERIOD;
230  anemometer.value_buf_xm = 0;
231  } else {
232  anemometer.value_avg_xm = 0;
233  }
234 
235  if(wind_vane.value_buf_xm >= 0) {
236  wind_vane.value_buf_xm = wind_vane.value_buf_xm / WEATHER_METER_AVG_PERIOD;
237  wind_vane.value_avg_xm = wind_vane.value_buf_xm;
238  } else {
239  wind_vane.value_buf_xm = ABS(wind_vane.value_buf_xm) / WEATHER_METER_AVG_PERIOD;
240  wind_vane.value_avg_xm = wind_vane.value_buf_xm;
241  wind_vane.value_avg_xm = ~wind_vane.value_avg_xm + 1;
242  }
243 
244  if(wind_vane.value_avg_xm >= 3600) {
245  wind_vane.value_avg_xm -= 3600;
246  } else if(wind_vane.value_avg_xm < 0) {
247  wind_vane.value_avg_xm += 3600;
248  }
249 
250  wind_vane.value_buf_xm = 0;
251  wind_vane.value_prev = wind_dir;
252  }
253 
254  /* Check for roll-over */
255  if(!anemometer.ticks_avg) {
256  anemometer.value_avg = 0;
257  }
258 
259  weather_sensors.anemometer.ticks = 0;
260 
261  /* Enable the interrupt again */
262  GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
263  ANEMOMETER_SENSOR_PIN_MASK);
264 
265  ctimer_set(&ct, CLOCK_SECOND, ct_callback, NULL);
266 }
267 /*---------------------------------------------------------------------------*/
268 PROCESS(weather_meter_int_process, "Weather meter interrupt process handler");
269 /*---------------------------------------------------------------------------*/
270 PROCESS_THREAD(weather_meter_int_process, ev, data)
271 {
273  PROCESS_BEGIN();
274 
275  while(1) {
276  PROCESS_YIELD();
277 
278  if((ev == anemometer_int_event) && (weather_sensors.anemometer.int_en)) {
279  if(weather_sensors.anemometer.ticks >=
280  weather_sensors.anemometer.int_thres) {
281  anemometer_int_callback(weather_sensors.anemometer.ticks);
282  }
283  }
284 
285  if((ev == rain_gauge_int_event) && (weather_sensors.rain_gauge.int_en)) {
286  if(weather_sensors.rain_gauge.ticks >=
287  weather_sensors.rain_gauge.int_thres) {
288  rain_gauge_int_callback(weather_sensors.rain_gauge.ticks);
289  }
290  }
291  }
292  PROCESS_END();
293 }
294 /*---------------------------------------------------------------------------*/
295 static void
296 weather_meter_interrupt_handler(uint8_t port, uint8_t pin)
297 {
298  uint32_t aux;
299 
300  /* Prevent bounce events */
301  if(!timer_expired(&debouncetimer)) {
302  return;
303  }
304 
305  timer_set(&debouncetimer, DEBOUNCE_DURATION);
306 
307  /* We make a process_post() to check in the pollhandler any specific threshold
308  * value
309  */
310 
311  if((port == ANEMOMETER_SENSOR_PORT) && (pin == ANEMOMETER_SENSOR_PIN)) {
312  weather_sensors.anemometer.ticks++;
313  process_post(&weather_meter_int_process, anemometer_int_event, NULL);
314  } else if((port == RAIN_GAUGE_SENSOR_PORT) && (pin == RAIN_GAUGE_SENSOR_PIN)) {
315  weather_sensors.rain_gauge.ticks++;
316  aux = weather_sensors.rain_gauge.ticks * WEATHER_METER_AUX_RAIN_MM;
317  aux /= 1000;
318  weather_sensors.rain_gauge.value = (uint16_t)aux;
319  process_post(&weather_meter_int_process, rain_gauge_int_event, NULL);
320  }
321 }
322 /*---------------------------------------------------------------------------*/
323 static int
324 value(int type)
325 {
326  uint64_t aux;
327 
328  if((type != WEATHER_METER_ANEMOMETER) &&
329  (type != WEATHER_METER_RAIN_GAUGE) &&
330  (type != WEATHER_METER_WIND_VANE) &&
331  (type != WEATHER_METER_WIND_VANE_AVG_X) &&
332  (type != WEATHER_METER_ANEMOMETER_AVG) &&
333  (type != WEATHER_METER_ANEMOMETER_AVG_X) &&
334  (type != WEATHER_METER_ANEMOMETER_MAX)) {
335  PRINTF("Weather: requested an invalid sensor value\n");
336  return WEATHER_METER_ERROR;
337  }
338 
339  if(!enabled) {
340  PRINTF("Weather: module is not configured\n");
341  return WEATHER_METER_ERROR;
342  }
343 
344  switch(type) {
345  case WEATHER_METER_WIND_VANE:
346  return weather_meter_get_wind_dir();
347 
348  case WEATHER_METER_WIND_VANE_AVG_X:
349  return wind_vane.value_avg_xm;
350 
351  case WEATHER_METER_ANEMOMETER:
352  return weather_sensors.anemometer.value;
353 
354  case WEATHER_METER_ANEMOMETER_AVG:
355  if(anemometer.value_avg <= 0) {
356  return (uint16_t)anemometer.value_avg;
357  }
358  aux = anemometer.value_avg / anemometer.ticks_avg;
359  return (uint16_t)aux;
360 
361  case WEATHER_METER_ANEMOMETER_AVG_X:
362  return anemometer.value_avg_xm;
363 
364  case WEATHER_METER_ANEMOMETER_MAX:
365  return anemometer.value_max;
366 
367  /* as the default return type is int, we have a lower resolution if returning
368  * the calculated value as it is truncated, an alternative is returning the
369  * ticks and calculating on your own with WEATHER_METER_AUX_RAIN_MM
370  */
371  case WEATHER_METER_RAIN_GAUGE:
372 #if WEATHER_METER_RAIN_RETURN_TICKS
373  return weather_sensors.rain_gauge.ticks;
374 #else
375  return weather_sensors.rain_gauge.value;
376 #endif
377 
378  default:
379  return WEATHER_METER_ERROR;
380  }
381 }
382 /*---------------------------------------------------------------------------*/
383 static int
384 configure(int type, int value)
385 {
386  if((type != WEATHER_METER_ACTIVE) &&
387  (type != WEATHER_METER_ANEMOMETER_INT_OVER) &&
388  (type != WEATHER_METER_RAIN_GAUGE_INT_OVER) &&
389  (type != WEATHER_METER_ANEMOMETER_INT_DIS) &&
390  (type != WEATHER_METER_RAIN_GAUGE_INT_DIS)) {
391  PRINTF("Weather: invalid configuration option\n");
392  return WEATHER_METER_ERROR;
393  }
394 
395  if(type == WEATHER_METER_ACTIVE) {
396 
397  anemometer.value_avg = 0;
398  anemometer.ticks_avg = 0;
399 
400  weather_sensors.anemometer.int_en = 0;
401  weather_sensors.rain_gauge.int_en = 0;
402  weather_sensors.anemometer.ticks = 0;
403  weather_sensors.rain_gauge.ticks = 0;
404  weather_sensors.anemometer.value = 0;
405  weather_sensors.rain_gauge.value = 0;
406 
407  if(!value) {
408  anemometer_int_callback = NULL;
409  rain_gauge_int_callback = NULL;
410  GPIO_DISABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE,
411  ANEMOMETER_SENSOR_PIN_MASK);
412  GPIO_DISABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE,
413  RAIN_GAUGE_SENSOR_PIN_MASK);
414  process_exit(&weather_meter_int_process);
415  enabled = 0;
416  PRINTF("Weather: disabled\n");
417  return WEATHER_METER_SUCCESS;
418  }
419 
420  /* Configure the wind vane */
421  adc_zoul.configure(SENSORS_HW_INIT, WIND_VANE_ADC);
422 
423  /* Configure anemometer interruption */
424  GPIO_SOFTWARE_CONTROL(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
425  GPIO_SET_INPUT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
426  GPIO_DETECT_RISING(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
427  GPIO_TRIGGER_SINGLE_EDGE(ANEMOMETER_SENSOR_PORT_BASE,
428  ANEMOMETER_SENSOR_PIN_MASK);
429  ioc_set_over(ANEMOMETER_SENSOR_PORT, ANEMOMETER_SENSOR_PIN, IOC_OVERRIDE_DIS);
430  gpio_register_callback(weather_meter_interrupt_handler, ANEMOMETER_SENSOR_PORT,
431  ANEMOMETER_SENSOR_PIN);
432 
433  /* Configure rain gauge interruption */
434  GPIO_SOFTWARE_CONTROL(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
435  GPIO_SET_INPUT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
436  GPIO_DETECT_RISING(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
437  GPIO_TRIGGER_SINGLE_EDGE(RAIN_GAUGE_SENSOR_PORT_BASE,
438  RAIN_GAUGE_SENSOR_PIN_MASK);
439  ioc_set_over(RAIN_GAUGE_SENSOR_PORT, RAIN_GAUGE_SENSOR_PIN, IOC_OVERRIDE_DIS);
440  gpio_register_callback(weather_meter_interrupt_handler, RAIN_GAUGE_SENSOR_PORT,
441  RAIN_GAUGE_SENSOR_PIN);
442 
443  process_start(&weather_meter_int_process, NULL);
444 
445  /* Initialize here prior the first second tick */
446  wind_vane.value_prev = weather_meter_get_wind_dir();
447 
448  ctimer_set(&ct, CLOCK_SECOND, ct_callback, NULL);
449 
450  GPIO_ENABLE_INTERRUPT(ANEMOMETER_SENSOR_PORT_BASE, ANEMOMETER_SENSOR_PIN_MASK);
451  GPIO_ENABLE_INTERRUPT(RAIN_GAUGE_SENSOR_PORT_BASE, RAIN_GAUGE_SENSOR_PIN_MASK);
452  nvic_interrupt_enable(ANEMOMETER_SENSOR_VECTOR);
453  nvic_interrupt_enable(RAIN_GAUGE_SENSOR_VECTOR);
454 
455  enabled = 1;
456  PRINTF("Weather: started\n");
457  return WEATHER_METER_SUCCESS;
458  }
459 
460  switch(type) {
461  case WEATHER_METER_ANEMOMETER_INT_OVER:
462  weather_sensors.anemometer.int_en = 1;
463  weather_sensors.anemometer.int_thres = value;
464  PRINTF("Weather: anemometer threshold %u\n", value);
465  break;
466  case WEATHER_METER_RAIN_GAUGE_INT_OVER:
467  weather_sensors.rain_gauge.int_en = 1;
468  weather_sensors.rain_gauge.int_thres = value;
469  PRINTF("Weather: rain gauge threshold %u\n", value);
470  break;
471  case WEATHER_METER_ANEMOMETER_INT_DIS:
472  PRINTF("Weather: anemometer int disabled\n");
473  weather_sensors.anemometer.int_en = 0;
474  break;
475  case WEATHER_METER_RAIN_GAUGE_INT_DIS:
476  PRINTF("Weather: rain gauge int disabled\n");
477  weather_sensors.rain_gauge.int_en = 0;
478  break;
479  default:
480  return WEATHER_METER_ERROR;
481  }
482 
483  return WEATHER_METER_SUCCESS;
484 }
485 /*---------------------------------------------------------------------------*/
486 SENSORS_SENSOR(weather_meter, WEATHER_METER_SENSOR, value, configure, NULL);
487 /*---------------------------------------------------------------------------*/
488 /** @} */
489 
#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:178
#define DEBOUNCE_DURATION
Delay before button state is assumed to be stable.
Definition: button-sensor.c:54
#define GPIO_ENABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Enable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:202
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:93
#define IOC_OVERRIDE_DIS
Override Disabled.
Definition: ioc.h:226
Timer library header file.
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
Header file for the Zoul ADC interface.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: timer.h:86
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
Implementation of a generic module controlling Zoul sensors.
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
#define PROCESS_EXITHANDLER(handler)
Specify an action when a process exits.
Definition: process.h:254
Header file for the callback timer
#define NULL
The null pointer.
Header file with declarations for the I/O Control module.
#define PROCESS_YIELD()
Yield the currently running process.
Definition: process.h:164
#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:259
Header file for the cc2538 System Control driver.
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
#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:186
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void nvic_interrupt_enable(uint32_t intr)
Enables interrupt intr.
Definition: nvic.c:64
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
#define GPIO_DISABLE_INTERRUPT(PORT_BASE, PIN_MASK)
Disable interrupt triggering for pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:210
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
void gpio_register_callback(gpio_callback_t f, uint8_t port, uint8_t pin)
Register GPIO callback.
Definition: gpio.c:56
Weather meter header file.
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:122
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120