Added SHT11 driver for TMote.
[sos-2x.git] / drivers / ubmac / ubmac.c
blobeec28b1a35f209250ba06439d81a1c061f94cedc
1 /* -*- Mode: C; tab-width:4 -*- */
2 /* ex: set ts=4 shiftwidth=4 softtabstop=4 cindent: */
3 /* tab:4
4 * "Copyright (c) 2000-2003 The Regents of the University of California.
5 * All rights reserved.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation for any purpose, without fee, and without written agreement is
9 * hereby granted, provided that the above copyright notice, the following
10 * two paragraphs and the author appear in all copies of this software.
12 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
14 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
15 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
20 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
21 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23 * Copyright (c) 2002-2003 Intel Corporation
24 * All rights reserved.
26 * This file is distributed under the terms in the attached INTEL-LICENSE
27 * file. If you do not find these files, copies can be found by writing to
28 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA,
29 * 94704. Attention: Intel License Inquiry.
32 /**
33 * @brief Uncertainty-Driven BMAC (UBMAC) module
34 * @author Ilias Tsigkogiannis {ilias@ucla.edu}
37 #include <module.h>
38 //#define LED_DEBUG
39 #include <led_dbg.h>
40 #include <CC1000Const.h>
41 #include <cc1k.h>
42 #include <cc1k_lpl.h>
43 #include <timesync/rats/rats.h>
44 #include <timesync/tpsn/tpsn.h>
45 #include "include/ubmac.h"
47 #define UBMAC_TIMER_INTERVAL 61440L // 1 minute
48 #define UBMAC_TID 0
49 #define INITIAL_TRANSMISSION_INTERVAL 1 // minute
50 #define NORMAL_TRANSMISSION_INTERVAL 10 //minutes
51 #define LEARNING_PERIOD_TOTAL_TIME 5 //minutes
53 #define MSG_RECEIVE_INFO (MOD_MSG_START + 2)
54 #define MSG_REQUEST_INFO (MOD_MSG_START + 3)
55 #define MSG_TIMESYNC_REPLY (MOD_MSG_START + 4)
57 #define MINIMUM_TIMER_RETURN_TIME 1152 //clock ticks (10 msec)
60 #define CLOCK_TICK_IN_8MHZ_CLK 8.682F
61 #define TIMER_TICK_IN_MICROSEC 976.5625F
63 #define TIMER_TO_CLOCK_CONVERSION 113.439F
65 #define ALWAYS_ON 1
67 // We define leverage terms to take into account unpredictability of sleeping and waking up
68 // These leverages are defined from the perspective of the sender side
69 #define LEVERAGE_PREAMBLE 24 // bytes
71 typedef struct
73 uint32_t wakeup_time;
74 uint32_t period;
75 } __attribute__ ((packed)) ubmac_transmit_t;
77 typedef struct ubmac_data
79 uint16_t node_id;
80 int32_t wakeup_time;
81 int32_t untranslated_wakeup_time;
82 uint8_t is_wakeup_time_valid; //boolean variable
83 uint32_t period;
84 uint8_t ref_count;
85 uint8_t timesync_mod_id;
86 uint32_t sync_precision;
87 struct ubmac_data *next;
88 }ubmac_data_t;
90 /**
91 * Module can define its own state
93 typedef struct
95 uint8_t pid;
96 ubmac_transmit_t my_info;
97 ubmac_data_t *dest_info;
98 uint16_t timer_counter;
99 uint16_t learning_interval_counter;
100 } __attribute__ ((packed)) app_state_t;
102 static uint8_t add_info(app_state_t *s, ubmac_init_t * ubmac_init_ptr);
103 static void update_info(app_state_t *s, uint16_t node_id, ubmac_transmit_t *ubmac_transmit_ptr);
104 static ubmac_data_t * get_info(app_state_t *s, uint16_t node_id);
105 static void update_translated_time(app_state_t *s, uint8_t timesync_mod_id, void *data);
106 static uint8_t remove_info(app_state_t *s, uint16_t node_id);
109 * All modules should included a handler for MSG_INIT to initialize module
110 * state, and a handler for MSG_FINAL to release module resources.
113 static int8_t ubmac_msg_handler(void *start, Message *e);
116 * This is the only global variable one can have.
118 static mod_header_t mod_header SOS_MODULE_HEADER = {
119 .mod_id = UBMAC_PID,
120 .state_size = sizeof(app_state_t),
121 .num_timers = 1,
122 .num_sub_func = 0,
123 .num_prov_func = 0,
124 .platform_type = HW_TYPE /* or PLATFORM_ANY */,
125 .processor_type = MCU_TYPE,
126 .code_id = ehtons(UBMAC_PID),
127 .module_handler = ubmac_msg_handler,
131 static int8_t ubmac_msg_handler(void *state, Message *msg)
133 app_state_t *s = (app_state_t*)state;
134 switch (msg->type)
136 case MSG_INIT:
138 s->pid = msg->did;
140 s->my_info.wakeup_time = 0;
141 s->my_info.period = ALWAYS_ON; //it will remain ALWAYS_ON, even if notifyUbmac is never called
143 s->dest_info = NULL;
144 s->timer_counter = INITIAL_TRANSMISSION_INTERVAL;
145 s->learning_interval_counter = LEARNING_PERIOD_TOTAL_TIME;
146 ker_timer_init(s->pid, UBMAC_TID, TIMER_REPEAT);
147 ker_timer_start(s->pid, UBMAC_TID, UBMAC_TIMER_INTERVAL);
148 break;
150 case MSG_TIMER_TIMEOUT:
152 if(--s->timer_counter == 0)
154 post_net(s->pid, s->pid, MSG_RECEIVE_INFO, sizeof(ubmac_transmit_t), &s->my_info, 0, BCAST_ADDRESS);
155 if(s->learning_interval_counter > 0)
157 s->learning_interval_counter--;
158 s->timer_counter = INITIAL_TRANSMISSION_INTERVAL;
160 else
161 s->timer_counter = NORMAL_TRANSMISSION_INTERVAL;
163 break;
165 case MSG_START_TIMESYNC:
167 ubmac_init_t * ubmac_init_ptr = (ubmac_init_t *)msg->data;
169 if(add_info(s, ubmac_init_ptr) == TRUE)
171 switch(ubmac_init_ptr->timesync_mod_id)
173 case RATS_TIMESYNC_PID:
175 post_short(RATS_TIMESYNC_PID, s->pid, MSG_RATS_CLIENT_START, ubmac_init_ptr->sync_precision, ubmac_init_ptr->node_id, 0);
176 break;
178 case TPSN_TIMESYNC_PID:
180 break;
182 default:
184 break;
187 post_net(s->pid, s->pid, MSG_REQUEST_INFO, 0, NULL, 0, ubmac_init_ptr->node_id);
189 break;
191 case MSG_REQUEST_INFO:
193 post_net(s->pid, s->pid, MSG_RECEIVE_INFO, sizeof(ubmac_transmit_t), &s->my_info, 0, msg->saddr);
194 break;
196 case MSG_RECEIVE_INFO:
198 ubmac_transmit_t *ubmac_transmit_ptr = (ubmac_transmit_t *)msg->data;
199 update_info(s, msg->saddr, ubmac_transmit_ptr);
200 break;
202 case MSG_TIMESYNC_REPLY:
204 update_translated_time(s, msg->sid, msg->data);
205 break;
207 case MSG_STOP_TIMESYNC:
209 MsgParam *p = (MsgParam *)msg->data;
210 if(remove_info(s, p->word) == TRUE)
212 post_short(RATS_TIMESYNC_PID, s->pid, MSG_RATS_CLIENT_STOP, 0, p->word, 0);
214 break;
216 case MSG_FINAL:
218 ker_timer_stop(s->pid, UBMAC_TID);
219 break;
221 default:
222 return -EINVAL;
225 return SOS_OK;
228 //Returns TRUE if new entry is created or sync precision is updated
229 static uint8_t add_info(app_state_t *s, ubmac_init_t * ubmac_init_ptr)
231 ubmac_data_t *ubmac_data_ptr;
233 // Case 1: Empty list
234 if(s->dest_info == NULL)
236 s->dest_info = (ubmac_data_t *)ker_malloc(sizeof(ubmac_data_t), s->pid);
237 s->dest_info->node_id = ubmac_init_ptr->node_id;
238 s->dest_info->wakeup_time = 0;
239 s->dest_info->is_wakeup_time_valid = FALSE;
240 s->dest_info->period = 0;
241 s->dest_info->ref_count = 1;
242 s->dest_info->sync_precision = ubmac_init_ptr->sync_precision;
243 s->dest_info->timesync_mod_id = ubmac_init_ptr->timesync_mod_id;
244 s->dest_info->next = NULL;
245 return TRUE;
248 // Case 2: Entry found
249 ubmac_data_ptr = s->dest_info;
250 while(ubmac_data_ptr)
252 if(ubmac_data_ptr->node_id == ubmac_init_ptr->node_id)
254 ubmac_data_ptr->ref_count++;
255 if(ubmac_data_ptr->sync_precision > ubmac_init_ptr->sync_precision)
257 ubmac_data_ptr->sync_precision = ubmac_init_ptr->sync_precision;
258 return TRUE;
260 return FALSE;
263 if(ubmac_data_ptr->next != NULL)
264 ubmac_data_ptr = ubmac_data_ptr->next;
265 else
266 break;
269 // Case 3: Entry not found
270 ubmac_data_ptr->next = (ubmac_data_t *)ker_malloc(sizeof(ubmac_data_t), s->pid);
271 ubmac_data_ptr->next->node_id = ubmac_init_ptr->node_id;
272 ubmac_data_ptr->next->wakeup_time = 0;
273 ubmac_data_ptr->next->is_wakeup_time_valid = FALSE;
274 ubmac_data_ptr->next->period = 0;
275 ubmac_data_ptr->next->ref_count = 1;
276 ubmac_data_ptr->next->sync_precision = ubmac_init_ptr->sync_precision;
277 ubmac_data_ptr->next->timesync_mod_id = ubmac_init_ptr->timesync_mod_id;
278 ubmac_data_ptr->next->next = NULL;
279 return TRUE;
282 static void update_info(app_state_t *s, uint16_t node_id, ubmac_transmit_t *ubmac_transmit_ptr)
284 ubmac_data_t *ubmac_data_ptr;
286 // Case 1: Empty list
287 if(s->dest_info == NULL)
288 return;
290 // Case 2: Entry found
291 ubmac_data_ptr = s->dest_info;
292 while(ubmac_data_ptr)
294 if(ubmac_data_ptr->node_id == node_id)
296 ubmac_data_ptr->period = ubmac_transmit_ptr->period;
297 switch(ubmac_data_ptr->timesync_mod_id)
299 case RATS_TIMESYNC_PID:
301 //In case of RATS, we only need to store the untranslated value
302 ubmac_data_ptr->untranslated_wakeup_time = ubmac_transmit_ptr->wakeup_time;
303 ubmac_data_ptr->is_wakeup_time_valid = TRUE;
304 break;
306 case TPSN_TIMESYNC_PID:
308 ubmac_data_ptr->untranslated_wakeup_time = ubmac_transmit_ptr->wakeup_time;
310 //Ask TPSN to do the translation (find the offset)
311 tpsn_t *tpsn_ptr = (tpsn_t *)ker_malloc(sizeof(tpsn_t), s->pid);
312 tpsn_ptr->mod_id = s->pid;
313 tpsn_ptr->msg_type = MSG_TIMESYNC_REPLY;
314 tpsn_ptr->node_id = node_id;
316 post_long(TPSN_TIMESYNC_PID, s->pid, MSG_GET_INSTANT_TIMESYNC, sizeof(tpsn_t), tpsn_ptr, 0);
317 break;
319 default:
321 break;
324 return;
327 if(ubmac_data_ptr->next != NULL)
328 ubmac_data_ptr = ubmac_data_ptr->next;
329 else
330 break;
333 // Case 3: Entry not found
334 return;
337 static void update_translated_time(app_state_t *s, uint8_t timesync_mod_id, void *data)
339 ubmac_data_t *ubmac_data_ptr;
340 tpsn_t * tpsn_ptr = NULL;
341 uint16_t node_id = 0;
343 switch(timesync_mod_id)
345 case RATS_TIMESYNC_PID:
347 //We should never come here
348 return;
350 case TPSN_TIMESYNC_PID:
352 tpsn_ptr = (tpsn_t *)data;
353 node_id = tpsn_ptr->node_id;
354 break;
356 default:
357 return;
361 // Case 1: Empty list
362 if(s->dest_info == NULL)
363 return;
365 // Case 2: Entry found
366 ubmac_data_ptr = s->dest_info;
367 while(ubmac_data_ptr)
369 if(ubmac_data_ptr->node_id == node_id)
371 switch(ubmac_data_ptr->timesync_mod_id)
373 case RATS_TIMESYNC_PID:
375 //We should never come here
376 return;
378 case TPSN_TIMESYNC_PID:
380 //Sanity check
381 if(tpsn_ptr == NULL)
382 return;
384 ubmac_data_ptr->wakeup_time = ubmac_data_ptr->untranslated_wakeup_time - tpsn_ptr->clock_drift;
385 ubmac_data_ptr->is_wakeup_time_valid = TRUE;
386 ker_free(tpsn_ptr);
387 return;
389 default:
390 break;
394 if(ubmac_data_ptr->next != NULL)
395 ubmac_data_ptr = ubmac_data_ptr->next;
396 else
397 break;
400 // Case 3: Entry not found
401 return;
404 static uint8_t remove_info(app_state_t *s, uint16_t node_id)
406 ubmac_data_t *ubmac_data_ptr = s->dest_info;
407 ubmac_data_t *ubmac_delete_ptr;
408 ubmac_data_t *ubmac_previous_ptr = s->dest_info;
410 /* Loop until we've reached the end of the list */
411 while( ubmac_data_ptr != NULL )
413 if(ubmac_data_ptr->node_id == node_id)
415 if(--ubmac_data_ptr->ref_count > 0)
416 return FALSE;
418 DEBUG("UBMAC: Removing node %d from list\n", node_id);
420 /* Found the item to be deleted,
421 re-link the list around it */
422 if( ubmac_data_ptr == s->dest_info )
423 /* We're deleting the head */
424 s->dest_info = ubmac_data_ptr->next;
425 else
426 ubmac_previous_ptr->next = ubmac_data_ptr->next;
428 ubmac_delete_ptr = ubmac_data_ptr;
429 ubmac_data_ptr = ubmac_data_ptr->next;
431 /* Free the node */
432 ker_free( ubmac_delete_ptr );
434 return TRUE;
436 ubmac_previous_ptr = ubmac_data_ptr;
437 ubmac_data_ptr = ubmac_data_ptr->next;
440 DEBUG("UBMAC: Node %d was not found in list\n", node_id);
442 return FALSE;
445 static ubmac_data_t * get_info(app_state_t *s, uint16_t node_id)
447 ubmac_data_t *ubmac_data_ptr = s->dest_info;
448 while(ubmac_data_ptr)
450 if(ubmac_data_ptr->node_id == node_id)
451 return ubmac_data_ptr;
452 ubmac_data_ptr = ubmac_data_ptr->next;
455 return NULL;
458 uint16_t ubmacGetTime(uint16_t node_id)
460 app_state_t *s = (app_state_t *)ker_get_module_state(UBMAC_PID);
461 ubmac_data_t * ubmac_data_ptr = get_info(s, node_id);
462 if(ubmac_data_ptr == NULL)
463 return 0;
465 if(ubmac_data_ptr->period == ALWAYS_ON)
466 return TIMER_MIN_INTERVAL; //set timer with small timeout
468 if(ubmac_data_ptr->period == 0) //period not set
469 return 0;
471 //Time is untranslated (ask for node's wakeup time,
472 //in case the initial request was lost)
473 if(ubmac_data_ptr->is_wakeup_time_valid == FALSE)
475 post_net(s->pid, s->pid, MSG_REQUEST_INFO, 0, NULL, 0, node_id);
476 return 0;
479 if(ubmac_data_ptr->timesync_mod_id == RATS_TIMESYNC_PID) // RATS
481 //Find current time of target node
482 float current_time_of_other_node = convert_from_mine_to_parent_time(ker_systime32(), node_id);
484 if(current_time_of_other_node == 0) //learning state
485 return 0;
487 float untranslated_wakeup_time = (float)ubmac_data_ptr->untranslated_wakeup_time;
489 //Take care of overflow in target node's current time
490 if( (untranslated_wakeup_time > 3*(INT_MAX_GTIME/4)) && (current_time_of_other_node < (INT_MAX_GTIME/4)) )
492 current_time_of_other_node += INT_MAX_GTIME;
495 //Find next wakeup time of target node (expressed in the target node's clock)
496 while( (untranslated_wakeup_time - (CSMA_TIMEOUT + MINIMUM_TIMER_RETURN_TIME) < current_time_of_other_node ) )
497 untranslated_wakeup_time += ubmac_data_ptr->period;
499 //Convert target node's wakeup time to local time
500 uint32_t transmission_time = convert_from_parent_to_my_time(untranslated_wakeup_time, node_id);
502 if(transmission_time == 0) // learning state
503 return 0;
505 //Take care of overflow in wakeup time
506 if(untranslated_wakeup_time > INT_MAX_GTIME)
507 untranslated_wakeup_time -= INT_MAX_GTIME;
509 ubmac_data_ptr->untranslated_wakeup_time = untranslated_wakeup_time;
511 //Take care of overflow in transmission time
512 if( (transmission_time < (INT_MAX_GTIME/4)) && (ker_systime32() > 3*(INT_MAX_GTIME/4)) )
514 transmission_time += INT_MAX_GTIME;
517 //If final result is valid, send with UBMAC, otherwise send with BMAC
518 if((uint16_t)((transmission_time - ker_systime32() - CSMA_TIMEOUT)/TIMER_TO_CLOCK_CONVERSION) > TIMER_MIN_INTERVAL)
519 return (uint16_t)((transmission_time - ker_systime32() - CSMA_TIMEOUT)/TIMER_TO_CLOCK_CONVERSION);
520 else
521 return 0;
523 else if(ubmac_data_ptr->timesync_mod_id == TPSN_TIMESYNC_PID) //TPSN
525 uint32_t wakeup_time = ubmac_data_ptr->wakeup_time;
526 uint32_t current_time = ker_systime32();
528 //Take care of overflow in current time
529 if( (wakeup_time > 3*(INT_MAX_GTIME/4)) && (current_time < (INT_MAX_GTIME/4)) )
530 current_time += INT_MAX_GTIME;
532 while(wakeup_time - (CSMA_TIMEOUT + MINIMUM_TIMER_RETURN_TIME) < current_time )
533 wakeup_time += ubmac_data_ptr->period;
535 //Take care of overflow
536 if(wakeup_time >= INT_MAX_GTIME)
537 ubmac_data_ptr->wakeup_time = wakeup_time - INT_MAX_GTIME;
538 else
539 ubmac_data_ptr->wakeup_time = wakeup_time;
541 return (uint16_t)((wakeup_time - current_time - CSMA_TIMEOUT)/TIMER_TO_CLOCK_CONVERSION);
544 //Default return value: send with BMAC
545 return 0;
549 uint32_t ubmacGetPreamble(uint16_t node_id)
551 app_state_t *s = (app_state_t *)ker_get_module_state(UBMAC_PID);
552 ubmac_data_t * ubmac_data_ptr = get_info(s, node_id);
553 if(ubmac_data_ptr == NULL)
554 return 0;
556 //4 + (uint32_t)(1000*(2*node_precision_in_milisec)/416)
557 return (4+(uint32_t)(1000*((2*ubmac_data_ptr->sync_precision))/416)+LEVERAGE_PREAMBLE);
560 void notifyUbmac(uint32_t wakeup_time)
562 app_state_t *s = (app_state_t *)ker_get_module_state(UBMAC_PID);
563 s->my_info.period = wakeup_time - s->my_info.wakeup_time;
564 s->my_info.wakeup_time = wakeup_time;
567 #ifndef _MODULE_
568 mod_header_ptr ubmac_get_header()
570 return sos_get_header_address(mod_header);
572 #endif