1 /* -*- Mode: C; tab-width:4 -*- */
2 /* ex: set ts=4 shiftwidth=4 softtabstop=4 cindent: */
4 * "Copyright (c) 2000-2003 The Regents of the University of California.
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.
33 * @brief Uncertainty-Driven BMAC (UBMAC) module
34 * @author Ilias Tsigkogiannis {ilias@ucla.edu}
40 #include <CC1000Const.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
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
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
75 } __attribute__ ((packed
)) ubmac_transmit_t
;
77 typedef struct ubmac_data
81 int32_t untranslated_wakeup_time
;
82 uint8_t is_wakeup_time_valid
; //boolean variable
85 uint8_t timesync_mod_id
;
86 uint32_t sync_precision
;
87 struct ubmac_data
*next
;
91 * Module can define its own state
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
= {
120 .state_size
= sizeof(app_state_t
),
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
;
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
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
);
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
;
161 s
->timer_counter
= NORMAL_TRANSMISSION_INTERVAL
;
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);
178 case TPSN_TIMESYNC_PID
:
187 post_net(s
->pid
, s
->pid
, MSG_REQUEST_INFO
, 0, NULL
, 0, ubmac_init_ptr
->node_id
);
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
);
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
);
202 case MSG_TIMESYNC_REPLY
:
204 update_translated_time(s
, msg
->sid
, msg
->data
);
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);
218 ker_timer_stop(s
->pid
, UBMAC_TID
);
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
;
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
;
263 if(ubmac_data_ptr
->next
!= NULL
)
264 ubmac_data_ptr
= ubmac_data_ptr
->next
;
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
;
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
)
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
;
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);
327 if(ubmac_data_ptr
->next
!= NULL
)
328 ubmac_data_ptr
= ubmac_data_ptr
->next
;
333 // Case 3: Entry not found
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
350 case TPSN_TIMESYNC_PID
:
352 tpsn_ptr
= (tpsn_t
*)data
;
353 node_id
= tpsn_ptr
->node_id
;
361 // Case 1: Empty list
362 if(s
->dest_info
== NULL
)
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
378 case TPSN_TIMESYNC_PID
:
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
;
394 if(ubmac_data_ptr
->next
!= NULL
)
395 ubmac_data_ptr
= ubmac_data_ptr
->next
;
400 // Case 3: Entry not found
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)
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
;
426 ubmac_previous_ptr
->next
= ubmac_data_ptr
->next
;
428 ubmac_delete_ptr
= ubmac_data_ptr
;
429 ubmac_data_ptr
= ubmac_data_ptr
->next
;
432 ker_free( ubmac_delete_ptr
);
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
);
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
;
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
)
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
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
);
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
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
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
);
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
;
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
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
)
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
;
568 mod_header_ptr
ubmac_get_header()
570 return sos_get_header_address(mod_header
);