Contiki 3.x
sampler.c
1 #include <stdbool.h>
2 #include <inttypes.h>
3 #include <stdio.h>
4 
5 #include "sampler.h"
6 
7 #include "contiki-conf.h"
8 #include "contiki.h"
9 
10 #include "store.h"
11 #include "ms-io.h"
12 #include "dev/avr-handler.h"
13 #include "pb_decode.h"
15 #include "settings.pb.h"
16 #include "readings.pb.h"
17 #include "power.pb.h"
18 #include "net/rpl/rpl.h"
19 
20 #define DEBUG_ON
21 #include "debug.h"
22 
23 PROCESS(sample_process, "Sample Process");
24 
25 /**
26  * Event sent to the sampler when the current sample is done,
27  * and needs to be saved.
28  */
29 #define SAMPLER_EVENT_SAVE_SAMPLE 1
30 
31 /**
32  * Event sent to the sampler when the configuration
33  * should be reloaded from Flash.
34  */
35 #define SAMPLER_EVENT_RELOAD_CONFIG 2
36 
37 /**
38  * Minimum sampling interval allowed in a config, in seconds.
39  */
40 #define CONFIG_MIN_INTERVAL 2
41 
42 /**
43  * Delay required for the AVR to reply over RS485 after booting
44  */
45 #define AVR_ACTIVATE_DELAY (RTIMER_SECOND / 10)
46 
47 /**
48  * The current sensor config being used.
49  */
50 static SensorConfig config;
51 
52 /**
53  * The current sample we're working on.
54  */
55 static Sample sample;
56 
57 /**
58  * True if the AVRs have been handled and we should do the PowerBoards now, False otherwise.
59  */
60 static bool is_avr_complete;
61 
62 /**
63  * Buffer to store incomming Power board data.
64  * We can't use the Sample struct directly, as we need to decode the incomming data.
65  */
66 static uint8_t power_data[PowerInfo_size];
67 
68 /**
69  * Length (not size) use of the power_data buffer.
70  */
71 static uint8_t power_len;
72 
73 /**
74  * Struct used to get data from an AVR
75  */
76 static struct avr_data data;
77 
78 /**
79  * Callback invoked by the avr-handler.
80  * @param isSuccess True if data was succesfully received, false otherwise.
81  */
82 static void avr_callback(bool isSuccess);
83 
84 /**
85  * Start receiving data from an AVR.
86  * @return True if the get-data operation was succesfully initiated, false otherwise.
87  */
88 static bool start_avr(void);
89 
90 /**
91  * Finalize our state when we are done receiving data from an AVR.
92  * @param isSuccess True if data was succesfully received, false otherwise.
93  */
94 static void end_avr(bool isSuccess);
95 
96 /**
97  * Start receiving data from a power board.
98  * @return True if the get-data operation was succesfully initiated, false otherwise.
99  */
100 static bool start_power(void);
101 
102 /**
103  * Finalize our state when we are done receiving data from a power board.
104  * @param isSuccess True if data was succesfully received, false otherwise.
105  */
106 static void end_power(bool isSuccess);
107 
108 /**
109  * Instruct us to turn sense off,
110  * and save the current sample we're working on (ie we're done with it).
111  */
112 static void save_sample(void);
113 
114 /**
115  * Get and set the latest config from the Store.
116  * If no config exists, set it to DEFAULT_CONFIG.
117  */
118 static void refresh_config(void);
119 
120 /**
121  * Print the sensor config for debugging.
122  */
123 static void print_config(SensorConfig *conf);
124 
125 PROCESS_THREAD(sample_process, ev, data) {
126  static struct etimer sample_timer;
127 
128  PROCESS_BEGIN();
129 
130  refresh_config();
131 
132  ms_init();
133 
134  // Set the AVR callback
135  avr_set_callback(&avr_callback);
136 
137  while(true) {
138 
139  // New scope to avoid having time always on the stack - maybe?
140  {
141  uint32_t time;
142  ms_get_time(&time);
143  etimer_set(&sample_timer, CLOCK_SECOND * (config.interval - (time % config.interval)));
144  }
145 
147 
148  // If it's time to sample
149  if (ev == PROCESS_EVENT_TIMER && etimer_expired(&sample_timer)) {
150 
151  DEBUG("Sampling\n");
152 
153  // Clear the previous sample, as it may have leftover things set we don't anticipate
154  memset(&sample, 0, sizeof(sample));
155 
156  ms_sense_on();
157 
158  ms_get_time(&sample.time);
159 
160  sample.has_temp = ms_get_temp(&sample.temp);
161 
162  sample.has_humid = ms_get_humid(&sample.humid);
163 
164  if (config.hasADC1) {
165  sample.has_ADC1 = ms_get_adc1(&sample.ADC1);
166  }
167 
168  if (config.hasADC2) {
169  sample.has_ADC2 = ms_get_adc2(&sample.ADC2);
170  }
171 
172  if (config.hasRain) {
173  sample.has_rain = ms_get_rain(&sample.rain);
174  }
175 
176  sample.has_accX = sample.has_accY = sample.has_accZ = ms_get_acc(&sample.accX, &sample.accY, &sample.accZ);
177 
178  // If we don't have a power board, use good old batt volts
179  if (!config.has_powerID && ms_get_batt(&sample.batt)) {
180  sample.which_battery = Sample_batt_tag;
181  }
182 
183  // If we have no AVR, consider it done
184  is_avr_complete = !config.has_avrID;
185 
186  // No avr
187  if (is_avr_complete) {
188  // If we have a power board, and it has been queud successfully for getting data, wait for that
189  if (config.has_powerID && start_power()) {
190  continue;
191  }
192 
193  // Otherwise we're done
194  save_sample();
195  continue;
196  }
197 
198  // If we have an AVR, and it has been queud successfully for getting data, wait for that
199  // Let the sampler know we'll call it back
200  if (config.has_avrID && start_avr()) {
201  continue;
202  }
203 
204  // Otherwise we're done
205  save_sample();
206 
207  } else if (ev == SAMPLER_EVENT_SAVE_SAMPLE) {
208  ms_sense_off();
209 
210  int16_t id = store_save_sample(&sample);
211 
212  if (id) {
213  DEBUG("Sample saved with id %d\n", id);
214  } else {
215  DEBUG("Failed to save sample!\n");
216  }
217 
218  } else if (ev == SAMPLER_EVENT_RELOAD_CONFIG) {
219  refresh_config();
220 
221  DEBUG("Refreshed Sensor config to:\n");
222  print_config(&config);
223  }
224  }
225  PROCESS_END();
226 }
227 
228 static void refresh_config(void) {
229  if (!store_get_config(&config)) {
230  // Config file does not exist! Use default and set file
231  DEBUG("No Sensor config found\n");
232  config = SENSOR_DEFAULT_CONFIG;
233  store_save_config(&config);
234  } else {
235  DEBUG("Sensor config loaded\n");
236  }
237 
238  // Set the RPL mode. Doesn't really belong here, but oh well
239  DEBUG("Setting RPL mode to %d\n", config.routingMode);
240  rpl_set_mode(config.routingMode);
241 }
242 
243 void print_config(SensorConfig *conf) {
244  DEBUG("\tInterval = %d\n", (unsigned int)conf->interval);
245 
246  DEBUG("\tADC1: %s\n", conf->hasADC1 ? "yes" : "no");
247  DEBUG("\tADC2: %s\n", conf->hasADC2 ? "yes" : "no");
248  DEBUG("\tRain: %s\n", conf->hasRain ? "yes" : "no");
249 
250  if (conf->has_avrID) {
251  DEBUG("\tAVR: %02X\n", conf->avrID);
252  }
253 
254  if (conf->has_powerID) {
255  DEBUG("\tPower: %02X\n", conf->powerID);
256  }
257 
258  DEBUG("\tRoutingMode: %d\n", conf->routingMode);
259 }
260 
262  DEBUG("Config marked for refresh!\n");
263  process_post(&sample_process, SAMPLER_EVENT_RELOAD_CONFIG, NULL);
264 }
265 
266 bool sampler_check_config(SensorConfig *config) {
267  return config->interval >= CONFIG_MIN_INTERVAL;
268 }
269 
270 void save_sample(void) {
271  process_post(&sample_process, SAMPLER_EVENT_SAVE_SAMPLE, NULL);
272 }
273 
274 void avr_callback(bool isSuccess) {
275  // If the avr isn't done yet, this must be the end of it
276  if (!is_avr_complete) {
277  end_avr(isSuccess);
278  is_avr_complete = true;
279 
280  // If we have a power board and we've succesfully queued a get data, wait until we get called again
281  if (config.has_powerID && start_power()) {
282  return;
283  }
284 
285  // Otherwise it must be the end of the power board
286  } else {
287  end_power(isSuccess);
288  }
289 
290  save_sample();
291 }
292 
293 bool start_avr(void) {
294  // Wait for the AVR to fully power on
295  rtimer_clock_t end = RTIMER_NOW() + AVR_ACTIVATE_DELAY;
296  while (RTIMER_CLOCK_LT(RTIMER_NOW(), end));
297 
298  // Use the buffer in the sample directly
299  data.data = sample.AVR.bytes;
300  data.len = &sample.AVR.size;
301  data.id = config.avrID;
302  // Size of the buffer is the size of the buffer in the Sample
303  data.size = sizeof(sample.AVR.bytes);
304 
305  DEBUG("Getting data from avr 0x%02X\n", config.avrID);
306 
307  return avr_get_data(&data);
308 }
309 
310 void end_avr(bool isSuccess) {
311  DEBUG("Sampled from avr. Success: %d\n", isSuccess);
312  sample.has_AVR = isSuccess;
313 }
314 
315 bool start_power(void) {
316  // Use the power_data buffer
317  data.data = power_data;
318  data.len = &power_len;
319  data.id = config.powerID;
320  data.size = sizeof(power_data);
321 
322  DEBUG("Getting data from power 0x%02X\n", config.powerID);
323 
324  return avr_get_data(&data);
325 }
326 
327 void end_power(bool isSuccess) {
328  DEBUG("Sampled from power board. Success: %d\n", isSuccess);
329 
330  if (!isSuccess) {
331  return;
332  }
333 
334  pb_istream_t istream = pb_istream_from_buffer(data.data, *data.len);
335  if (!pb_decode(&istream, PowerInfo_fields, &sample.power)) {
336  return;
337  }
338 
339  sample.which_battery = Sample_power_tag;
340  return;
341 }
bool store_save_config(SensorConfig *config)
Save the configuration to flash.
Definition: store.c:220
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
uint8_t * data
The data.
Definition: avr-handler.h:28
bool store_get_config(SensorConfig *config)
Get the configuration from the flash.
Definition: store.c:249
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: etimer.h:76
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
SensorConfig SENSOR_DEFAULT_CONFIG
Default configuration to use when no configuration is curently defined.
uint16_t store_save_sample(Sample *sample)
Store a sample in the flash.
Definition: store.c:100
bool sampler_check_config(SensorConfig *config)
Check a config for sanity.
Definition: sampler.c:266
#define NULL
The null pointer.
Convenience layer for storing readings and the config.
enum rpl_mode rpl_set_mode(enum rpl_mode m)
Set the RPL mode.
Definition: rpl.c:72
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void sampler_refresh_config(void)
Get the Sampler to reload it's config from flash.
Definition: sampler.c:261
A struct used to request data from an AVR.
Definition: avr-handler.h:13
Process that periodically takes samples from onboard sensors and stores them in flash.
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Definitions of the default configurations to use.