/**--------------------------------------------------------------- *KTH - The Royal Institute of Technology - STOCKHOLM - Sweden * School of Electrical Engineering * Automatic Control Lab *---------------------------------------------------------------- * Research Project in Mobile Wireless Sensor Networks * Supervisor: Prof. Mikael Johansson * Co-Supervisor: * *---------------------------------------------------------------- * Author: Antonio Gonga - gonga@kth.se * Date Created : June 3rd, 2009 * Revision: Jan 21st, 2010 * Major Revision: Feb 12th, 2010, 04:19:45'AM * Version: 10.7 *---------------------------------------------------------------- *Mobile MAC aims to provide medium access layer mobility to WSN *nodes. This version is aimed to support uIP mobility. *----------------------------------------------------------------*/ #include "contiki.h" #include "net/mac/mobile_mac.h" #include "net/rime/packetbuf.h" #include "sys/rtimer.h" #include "net/rime.h" #include "lib/random.h" #include "dev/leds.h" #include "dev/cc2420.h" #include "node-id.h" #include <string.h> /**-------------------------------------------------------------*/ #define DEBUG 0 #if DEBUG #include <stdio.h> #define PRINTF(...) printf(__VA_ARGS__) #if WITH_UIP6 #define PRINTMACADDR(addr) PRINTF(" fe80:0000:0000:00000:02%02x:%02x%02x:%02x%02x:%02x%02x \n", ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7]) #endif #else #define PRINTF(...) #if WITH_UIP6 #define PRINTMACADDR(addr) #endif #endif /**-------------------------------------------------------------*/ /**GENERAL DECLARATIONS * * */ /**-------------------------------------------------------------*/ #define TIME_DIFF(a,b) ((signed short)((a)-(b)) < 0) #if RIMEADDR_SIZE == 2 const rimeaddr_t sink_node_addr = { { 1, 0 } }; #endif #if RIMEADDR_SIZE == 8 //const rimeaddr_t sink_node_addr ={{0, 18, 116, 0, 17, 125, 68, 149}}; const rimeaddr_t sink_node_addr ={{0, 18, 116, 1, 0, 1, 1, 1}}; #endif #if WITH_UIP6 #ifndef NETWORK_PERFORMANCE #define NETWORK_PERFORMANCE 160 #endif #endif /**WITH_UIP6*/ /**-------------------------------------------------------------*/ #define MAX_CHILDS 8 /*#if NODE_IS_SINK #define MAX_CHILDS 8 #endif*/ /**-------------------------------------------------------------*/ /*#if NODE_IS_ROUTER #define MAX_MOBILES 8 #define MAX_ROUTERS 1 #define MAX_CHILDS (MAX_MOBILES ) #endif*/ /**-------------------------------------------------------------*/ /*#if NODE_IS_MOBILE #define MAX_CHILDS 8 #endif*/ /**-------------------------------------------------------------*/ #define COMMON_CH 26 #ifdef CONF_SINK_CH #define SINK_CH SINK_CONF_CH #else /*SINK_CONF_CH*/ #define SINK_CH 25 #endif /*SINK_CONF_CH*/ /**-------------------------------------------------------------*/ #define ONE_KILO 1024 #define ONE_MSEC (RTIMER_SECOND/ONE_KILO) /*64 clock ticks ~8.0ms*/ #define TS (8*ONE_MSEC) #define HALF_MSEC (ONE_MSEC/2) #define GUARD_TIME (TS/4) /**~2.0ms*/ #if WITH_UIP6 #ifndef NETWORK_HDR_LEN #define NETWORK_HDR_LEN 5 #endif /**NETWORK_HDR_LEN*/ #define UIP_NTWK_PERFORMANCE 100 #endif /**WITH_UIP6*/ /**-------------------------------------------------------------*/ enum{ SINK_DL_TX_TS = (8*TS), /**8TS=62.5ms*/ SINK_UL_RX_TS = (64*TS), /**500ms*/ ROUTER_UL_TX_TS = (32*TS), /**250ms*/ HDVR_TX_TS = (4*TS), ROUTER_DL_TX_TS = (SINK_DL_TX_TS), BW_ROUTER_TS = ((ROUTER_UL_TX_TS/TS) - MAX_CHILDS), /**-------------------------------------------------------------*/ #if CONF_SUPER_FRAME_DURATION SUPER_FRAME_DURATION = (TS*CONF_SUPER_FRAME_DURATION), #else SUPER_FRAME_DURATION = (SINK_DL_TX_TS + SINK_UL_RX_TS + HDVR_TX_TS), #endif /**-------------------------------------------------------------*/ #if NODE_IS_MOBILE MOB_AWAKE_OFFSET_1 = (SINK_UL_RX_TS - GUARD_TIME -TS), MOB_AWAKE_OFFSET_2 = (ROUTER_UL_TX_TS - GUARD_TIME -TS), #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE AWAKE_PERIOD = ( SUPER_FRAME_DURATION - TS), #endif /**-------------------------------------------------------------*/ #if NODE_IS_MOBILE UL_QUEUE_SIZE = 25, #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER #if WITH_UIP6 UL_QUEUE_SIZE = 15, DL_QUEUE_SIZE = 5, #else UL_QUEUE_SIZE = 30, DL_QUEUE_SIZE = 7, #endif #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK DL_QUEUE_SIZE = 30, #endif }; /*end of enumeration*/ /**-------------------------------------------------------------*/ /** * * message types between sensor nodes.*/ enum{ XPTO, SINK_BEACON, /**a sink beacon message*/ ROUTER_BEACON, /**a router beacon message*/ MOBILE_SLOT_REQ, /**a slot request from a mobile node to a router node*/ ROUTER_SLOT_REQ, /**a slot request from a router node to the sink node*/ NODE_SLOT_RELEASE, /**mobile requests slot release... handover in progress*/ NODE_STATUS_UPDATE, /**similar to KEEP alive, sent every 5 frames*/ NODE_UPDATE_ALL, /**upadate list of childs*/ HANDOVER_INFO, /**router special info to mobile nodes*/ DATA_RATE_UPDATE, /**mobile node data rate update*/ }; /**-------------------------------------------------------------*/ enum{ SINK_DATA =100, /*data originated or forwarded by the sink node*/ ROUTER_DATA=101, /*data originated or forarded by a router node*/ MOBILE_DATA=102, /*mobile node data*/ }; enum{ INACTIVE = 0, ACTIVE = 1, }; /**-------------------------------------------------------------*/ typedef enum{ NOTHING, NODE_SLEEP, NODE_TX_DOWNLINK, NODE_TX_UPLINK, NODE_RX_DOWLINK, NODE_RX_UPLINK, NODE_RX_SYNCH, NODE_INFO_TX_RX, NODE_WRITE_BUF, NODE_RX_INFRA, NODE_TX_ADMIN_INFO, NODE_ROUTER_SCHEDULE, }node_state_t; /**-------------------------------------------------------------*/ //typedef u32_t my_clock_t; typedef rtimer_clock_t my_clock_t; #define NORM_CLOCK(a) ((u32_t)a%(65536UL)) static uint8_t beacon_seqno = 0; /**-------------------------------------------------------------*/ static volatile node_state_t node_state = NOTHING; #if NODE_IS_ROUTER || NODE_IS_MOBILE static volatile node_state_t ul_buf_state = NOTHING; #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ #if NODE_IS_SINK || NODE_IS_ROUTER static volatile node_state_t dl_buf_state = NOTHING; #endif /*NODE_IS_SINK || NODE_IS_ROUTER*/ /**-------------------------------------------------------------*/ /**every echanged message, is precedeed by a header. This header gives *the type of message, and consequently how the message will be treated. */ typedef struct{ uint8_t type; ///MSG_TYPE DATA, CTRL_CH1,2,3 OR NOTHING rimeaddr_t src; ///WHERE THE MESSAGE COMES FROM rimeaddr_t dest; ///TO WHICH SENSOR THE MESSAGES IS DESTINATED TO uint8_t pld_len; ///PAYLOAD LENGTH ... }rdc_hdr_t; /**-------------------------------------------------------------*/ /**Synchronization packet(cluster head synchronization packet)*/ typedef struct synch{ uint8_t seqno; /*sequence number*/ uint8_t n_childs; /*n_childs*/ uint8_t free_slots; uint8_t n_routers; /*n_routers*/ uint8_t nr_hops; uint8_t ch_offset; /*router channel offset*/ }synch_msg_t; /*--------------------------------------------------------------*/ typedef struct{ rdc_hdr_t hdr; uint8_t from; /**type of a node where it came from*/ uint8_t hops; /*how many hops to the sink*/ uint8_t n_nodes; /* number of nodes including routers*/ uint8_t ch_id; /*channel id: at which channel this router is operating*/ uint8_t group_id; /*explain later*/ }admin_info_t; /**-------------------------------------------------------------*/ /*each slot request response message contains the requester id *and the respective offset. */ typedef struct slots{ uint8_t ts_offset; /*slot Index/factor 0<= P1 < Num_neighs*/ uint8_t assig_slots; /*assigned slots*/ rimeaddr_t node_id; /*nodeID*/ }slot_dist_t; /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER typedef struct{ uint8_t ttl; uint8_t state; rimeaddr_t node_id; }mobile_state_t; /**-------------------------------------------------------------*/ typedef enum{ INSERT, LOOKUP, REMOVE, }operation_t; #define HDVR_LEN 6 mobile_state_t handoff_list[HDVR_LEN]; /*I hope that all mobiles will not evaporate at the same time :)*/ #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK typedef struct{ uint8_t odd_slots; uint8_t even_slots; uint8_t free_slots; }sink_slot_dist_t; sink_slot_dist_t sink_slots_tbl[] = { { 0, 0, 64}, /*0*/ { 28, 29, 31}, /*1*/ { 29, 29, 8}, /*2*/ { 29, 30, 7}, /*3*/ { 30, 30, 6}, /*4*/ { 30, 31, 5}, /*5*/ { 31, 31, 4}, /*6*/ { 31, 32, 2}, /*7*/ { 32, 32, 0}, /*8*/ }; #endif /*NODE_IS_SINK*/ /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE /*handover table info. Each mobile node keeps this table in order to *select the best candidate to connect to in advent of power drop */ typedef struct{ uint8_t state; uint8_t ch_id; signed char pdbm; #if NODE_IS_ROUTER uint8_t from; /*type of a node where it came from*/ uint8_t hops; /*how many hops to the sink*/ #endif /*end of NODE_IS_ROUTER*/ }neigh_conn_info_t; static neigh_conn_info_t neigh_adv_list[MAX_CHILDS]; #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER /*the child list is used to distribute offsets as well as for routing data */ typedef struct node_list{ uint8_t ttl; uint8_t type; //node type uint8_t state; uint8_t data_rate; //or share uint8_t assign_slots; rimeaddr_t node_id; }node_list_t; static node_list_t node_list[MAX_CHILDS]; #endif /*NODE_IS_SINK || NODE_IS_ROUTER*/ /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER || NODE_IS_MOBILE typedef struct{ u32_t ad_t0; /**admission request time*/ u32_t ad_tn; /**admission response time_n*/ u32_t hv_t0; /**slot_release time_0*/ u32_t hv_tn; /**readimission response time*/ u32_t tx_packets; #if !WITH_UIP6 uint8_t rp_type; uint8_t eff_d_rate; u32_t nc_t0; /**boot time*/ u32_t nc_tn; /**last admission response time*/ u32_t tx_bytes; #endif rimeaddr_t c_router; /**current router: is a router that a mobile node is attached to*/ rimeaddr_t n_router; /**next_router: is a router a mobile node moves, will then become the current router*/ }network_statistics_t; #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ /**-------------------------------------------------------------*/ #define MIN_DATA_RATE 1 #define MAX_SYNCHR_BEACONS 128 #define SLOT_MSG_LEN sizeof(slot_dist_t) #define ADMIN_MSG_LEN sizeof(admin_info_t) #define SYNCH_MSG_LEN sizeof(synch_msg_t) #define RDC_HDR_LEN sizeof(rdc_hdr_t) /**-------------------------------------------------------------*/ typedef struct{ rdc_hdr_t hdr; uint8_t data[PACKETBUF_SIZE - RDC_HDR_LEN]; }rdc_msg_t; /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER #define TH_POWER (-80) #endif #if NODE_IS_MOBILE #define TH_POWER (-80) #endif /**-------------------------------------------------------------*/ /**------------------radio specific-----------------------------*/ static volatile uint8_t radio_on = 0; static volatile uint8_t radio_off = 0; /**-------------------------------------------------------------*/ /**according to cc2420 DataSheet, PdBm = rssi+(-45)*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE /**At this received power, the node starts with the handover procedure. *A new candicate is selected from the handover table. The handover procedure *is similiar to the admission procedure. Once the candidate is selected, the *next step is to send a request slot message, and wait for request response *message. */ static const uint8_t data_channels[] = {25, 13, 18, 21, 20, 15, 22, 17, 12, 19, 14, 11, 16}; int16_t PWR_DBM(){ int16_t recv_rssi = cc2420_last_rssi; return (int16_t) ((recv_rssi > 0x80) ? (recv_rssi - 256 - 45) : (recv_rssi - 45)); } #endif /**-------------------------------------------------------------*/ static volatile uint8_t cluster_size = 0; static struct rtimer generic_timer; /**-------------------------------------------------------------*/ #if NODE_IS_SINK static volatile my_clock_t infra_rx_to; static volatile my_clock_t infra_rx_tn; static volatile my_clock_t synch_tx_to; static volatile uint8_t even_window = 0, odd_window = 0; #endif /*NODE_IS_SINK*/ /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER static volatile my_clock_t infra_rx_to; static volatile my_clock_t infra_rx_tn; static volatile my_clock_t hdvr_tx_to; static volatile my_clock_t ul_tx_sch; /*at which time UL TX will be scheduled*/ static volatile my_clock_t radio_off_to; /*if there is no data to receive*/ //static my_clock_t node_awake_time; /*a very complex paramenter..explained later*/ static volatile uint8_t sum_data_rates= 1; static volatile uint8_t slots_offset = 0; #endif /*NODE_IS_ROUTER*/ /**-------------------------------------------------------------*/ #if NODE_IS_MOBILE static volatile uint8_t n_routers = 0; static volatile uint8_t handover = 0; static volatile uint8_t occupied_ts = 0; /*duty_cycle specific*/ static my_clock_t hdvr_rx_to; #if RATE_CONTROL extern uint8_t node_data_rate; static void (* rate_update_func)( uint8_t len); #endif /*RATE_CONTROL*/ #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE static volatile my_clock_t ref_timer; static my_clock_t radio_clock; static volatile my_clock_t synch_rx_to; /*uplink tx timer specific*/ static volatile my_clock_t ul_tx_to; static volatile my_clock_t ul_tx_tn; /*Evaluation variables */ static volatile my_clock_t ad_t0 = 0; /*admission request time*/ static volatile my_clock_t ad_tn = 0; /*admission response time_n*/ static volatile my_clock_t hv_t0 = 0; /*slot_release time_0*/ static volatile my_clock_t hv_tn = 0; /*readimission response time*/ static volatile my_clock_t nc_t0 = 0; /*boot time*/ static volatile my_clock_t nc_tn = 0; /*last admission response time*/ static uint8_t ass_d_rate = 0; static u32_t n_tx_bytes = 0; static u32_t n_tx_packets = 0; static volatile uint8_t is_there_data = 0; static volatile uint8_t report_type=0; static volatile uint8_t ad_t0_lock = 1; static volatile uint8_t ad_tn_lock = 0; static volatile uint8_t hv_t0_lock = 0; static volatile uint8_t hv_tn_lock = 0; static volatile uint8_t nc_tn_lock = 1; static volatile uint8_t send_stats_pkt = 0; static rimeaddr_t curr_router; static rimeaddr_t next_router; /*admission specific*/ static volatile uint8_t atempts = 0; static volatile uint8_t is_scanning = 0; static volatile uint8_t admitted = 0; static uint8_t data_rate = MIN_DATA_RATE; static volatile uint8_t data_rate_update = 0; static volatile uint8_t is_there_pkt = 0; /*synch packet specific*/ static volatile uint8_t ch_offset = 0; static volatile uint8_t ts_offset = 0; static volatile uint8_t free_slots = 0; static volatile uint8_t assign_slots = 0; static uint8_t nr_hops = 0; static uint8_t num_neighbors = 0; static uint8_t group_id = 0; /**radio channel specific*/ static volatile uint8_t uplink_ch = 0; /*uplink data buffer operations specific*/ static volatile uint8_t ul_b_full = 0; static volatile uint8_t next_to_send_ul = 0; static volatile uint8_t last_queued_ul = 0; static rdc_msg_t *ul_queue[UL_QUEUE_SIZE]; static rdc_msg_t ul_queue_bufs[UL_QUEUE_SIZE]; #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER static volatile my_clock_t dl_tx_to; /*downlink time to*/ static volatile my_clock_t dl_tx_tn; /*downlink time tn. tn-to =AT= AS*/ /*downlink buffers specific*/ static volatile uint8_t dl_b_full = 0; static volatile uint8_t next_to_send_dl = 0; static volatile uint8_t last_queued_dl = 0; static rdc_msg_t *dl_queue[DL_QUEUE_SIZE]; static rdc_msg_t dl_queue_bufs[DL_QUEUE_SIZE]; #endif /*NODE_IS_SINK || NODE_IS_ROUTER*/ /**-------------------------------------------------------------*/ static const struct radio_driver *radio; static void (* receiver_callback)(const struct mac_driver *); /*---------------------------------------------------------------------------*/ static void (*inpacket_callback )(rimeaddr_t *, void* data, uint8_t len); /*---------------------------------------------------------------------------*/ #if WITH_UIP6 static void(*uip_callback_func)(rimeaddr_t *, rimeaddr_t *, void* data, uint8_t len); #endif /**-------------------------------------------------------------*/ static int turn_radio_off(); static int turn_radio_on(); /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE static char uplink_transmitter(struct rtimer *t, void* ptr); static char slot_request(struct rtimer *t, void* ptr); #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER static char tx_admin_info(struct rtimer *t, void* ptr); static char downlink_transmitter(struct rtimer *t, void* ptr); #endif /**-------------------------------------------------------------*/ #if NODE_IS_MOBILE static char mobile_power_cycle(struct rtimer *t, void* ptr); #endif #if NODE_IS_ROUTER static char router_power_cycle(struct rtimer *t, void* ptr); static uint8_t mobile_has_left(rimeaddr_t *addr, operation_t operation); #endif #if NODE_IS_SINK static char sink_power_cycle(struct rtimer *t, void* ptr); #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE inline static void get_node_statistics(void *ptr){ network_statistics_t *stat = (network_statistics_t*)ptr; #if !WITH_UIP6 stat->rp_type = report_type; stat->nc_t0 = nc_t0; stat->nc_tn = nc_tn; stat->tx_bytes = n_tx_bytes; stat->eff_d_rate = ass_d_rate; #endif stat->ad_t0 = ad_t0; stat->ad_tn = ad_tn; stat->hv_t0 = hv_t0; stat->hv_tn = hv_tn; stat->tx_packets = n_tx_packets; /*we also count the stats packet..*/ rimeaddr_copy(&stat->c_router, &curr_router); rimeaddr_copy(&stat->n_router, &next_router); } #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ /**-------------------------------------------------------------*/ void set_hdr_type(rdc_hdr_t *hdr, uint8_t type){ hdr->type = type; } /**-------------------------------------------------------------*/ uint8_t get_hdr_type(rdc_hdr_t *hdr){ return hdr->type; } /**-------------------------------------------------------------*/ /*turns the radio on*/ static void on(void) { if (radio_on == 0) { radio_on = 1; radio->on(); } } /**-------------------------------------------------------------*/ /*turns the radio off*/ static void off(void) { if (radio_on != 0) { radio_on = 0; radio->off(); } } /**-------------------------------------------------------------*/ /*initializes the data buffers*/ void data_buffers_init() { uint8_t k; #if NODE_IS_SINK || NODE_IS_ROUTER for (k = 0; k < DL_QUEUE_SIZE; k++) { dl_queue[k] = &dl_queue_bufs[k]; } #endif #if NODE_IS_MOBILE || NODE_IS_ROUTER for (k = 0; k < UL_QUEUE_SIZE; k++) { ul_queue[k] = &ul_queue_bufs[k]; } #endif } /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER /*initializes the child list*/ static inline void init_child_list() { uint8_t k; node_list_t *info; for(k = 0; k < MAX_CHILDS; k++){ info = &node_list[k]; memset(info, 0, sizeof(node_list_t)); } } #endif /**-------------------------------------------------------------*/ /*returts the childs list length*/ #if NODE_IS_SINK || NODE_IS_ROUTER static uint8_t child_list_len() { uint8_t k, len = 0; node_list_t *l_ptr; for(k = 0; k < MAX_CHILDS; k++){ l_ptr = &node_list[k]; if(l_ptr->state == ACTIVE){ len = len+1; } } return len; } #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER /*adds a new entry to the childs list*/ inline static void child_add(rimeaddr_t *addr, uint8_t rate, uint8_t type) { uint8_t k, exists = 0; uint8_t pos = MAX_CHILDS; node_list_t *nodes; for (k = 0; k < MAX_CHILDS; k++) { nodes = &node_list[k]; if(nodes->state == ACTIVE){ if(rimeaddr_cmp(&nodes->node_id, addr)){ nodes->ttl = 0; exists = 1; //PRINTF("FOUND node %d.%d at pos:%d\n",addr->u8[0], addr->u8[1], k); return; } }else{ pos = k; } } if(exists == 0 && pos < MAX_CHILDS){ node_list[pos].ttl = 0; node_list[pos].type = type; node_list[pos].state = ACTIVE; node_list[pos].data_rate = rate; rimeaddr_copy(&node_list[pos].node_id, addr); cluster_size = cluster_size + 1; //PRINTF("adding %d.%d at pos:%d\n",addr->u8[0], addr->u8[1], pos); #if NODE_IS_ROUTER data_rate_update = 1; #endif } } /**-------------------------------------------------------------*/ /*adds a new entry to the childs list*/ inline static uint8_t is_there_packet_to(rimeaddr_t *addr){ uint8_t k = 0, data_len = 0; rdc_msg_t *dlb; #if NODE_IS_ROUTER uint8_t count = 0; k = next_to_send_dl ; #endif for( ; k < DL_QUEUE_SIZE; k++){ dlb = dl_queue[k]; data_len = dlb->hdr.pld_len; if(data_len){ #if NODE_IS_SINK /*let the routers filter the packet.*/ return 1; #endif #if NODE_IS_ROUTER count++; if(rimeaddr_cmp(addr, &dlb->hdr.dest) || rimeaddr_cmp(&dlb->hdr.dest, &rimeaddr_null)){ return 1; } if(count >= 16){ return 0; } #endif data_len = 0; } if((k + 1) == last_queued_dl){ return 0; } } return 0; } #endif /*NODE_IS_SINK || NODE_IS_ROUTER*/ /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE /**-------------------------------------------------------------*/ /*initializes the handover table*/ inline void neigh_adv_list_init() { uint8_t k; neigh_conn_info_t *info_init; for(k = 0; k < MAX_CHILDS; k++){ info_init = &neigh_adv_list[k]; memset(info_init, 0, sizeof(neigh_conn_info_t)); } } /**-------------------------------------------------------------*/ /*returns the handover table size/length*/ static uint8_t neigh_adv_list_len() { uint8_t k, len = 0; neigh_conn_info_t *info; for(k = 0; k < MAX_CHILDS; k++){ info = &neigh_adv_list[k]; if(info->state == ACTIVE){ len = len +1; } } return len; } /**-------------------------------------------------------------*/ inline static void neigh_adv_list_best(){ uint8_t k; uint8_t new_ch_id = 0, exist = 0; uint8_t best_hops = 100; signed char power=TH_POWER; neigh_conn_info_t *best; #if NODE_IS_ROUTER new_ch_id = neigh_adv_list[0].ch_id; //neigh_adv_list[0].ch_id; uplink_ch = data_channels[new_ch_id]; return; #endif #if NODE_IS_MOBILE for(k = 0; k < MAX_CHILDS; k++){ best = &neigh_adv_list[k]; if(best->state == ACTIVE){ if(TIME_DIFF(power, best->pdbm)){ new_ch_id = best->ch_id; power = best->pdbm; best->pdbm=-94; exist = 1; } } } if(exist){ uplink_ch = data_channels[new_ch_id]; ch_offset = new_ch_id; PRINTF("ch_offset_gonga: %d\n", ch_offset); } #endif } /**-------------------------------------------------------------*/ /*add a new entry to the handover table*/ static void parents_add(admin_info_t *adv_msg) { uint8_t exists = 0, k; uint8_t pos = MAX_CHILDS; signed char pdbm = PWR_DBM(); neigh_conn_info_t *info; #if NODE_IS_ROUTER /*in this short version, am only interested to connect routers to the sink*/ if(adv_msg->hops == 0){ neigh_adv_list[0].state = ACTIVE; neigh_adv_list[0].ch_id = adv_msg->ch_id; neigh_adv_list[0].pdbm = pdbm; neigh_adv_list[0].from = adv_msg->from; neigh_adv_list[0].hops = adv_msg->hops; /*closer router */ return; } #endif #if NODE_IS_MOBILE if(adv_msg->hops == 0){ return; } for (k = 0; k < MAX_CHILDS; k++) { info = &neigh_adv_list[k]; if(info->state == ACTIVE){ if (info->ch_id == adv_msg->ch_id){ if ((adv_msg->n_nodes < MAX_CHILDS) && TIME_DIFF(TH_POWER, pdbm)) { info->pdbm = pdbm; //update }else{ info->ch_id = 0; info->state = INACTIVE; //remove } exists = 1; return; } }else{ pos = k; } } if (exists == 0 && pos < MAX_CHILDS) { if (TIME_DIFF(TH_POWER, pdbm) && (adv_msg->n_nodes < MAX_CHILDS)) { neigh_adv_list[pos].state = ACTIVE; neigh_adv_list[pos].ch_id = adv_msg->ch_id; neigh_adv_list[pos].pdbm = pdbm; //PRINTF("...adding ch_id: %d. power:%d pos: %d\n", ch_id, pdbm, pos); } } #endif /*NODE_IS_MOBILE*/ } #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER /*a mobile node is about to initiate handover, so a slot release message is *received at the parent router node to remove thde node from the childs list */ static uint8_t child_remove(rimeaddr_t *addr) { uint8_t k; node_list_t *rm_ptr; for (k = 0; k < MAX_CHILDS; k++) { rm_ptr = &node_list[k]; if (rm_ptr->state == ACTIVE) { if (rimeaddr_cmp(&rm_ptr->node_id, addr)) { rm_ptr->state = INACTIVE; rm_ptr->data_rate = 0; return 1; } } } return 0; } #endif /**-------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER inline static void child_data_rates(){ node_list_t *child_list; #if NODE_IS_SINK uint8_t k, idx = 0; even_window = odd_window = 0; #endif #if NODE_IS_ROUTER uint8_t k, rates=0; uint8_t childs_len = 0; uint8_t available_slots = 0; sum_data_rates = data_rate; #endif for (k = 0; k < MAX_CHILDS; k++) { child_list = &node_list[k]; if (child_list->state == ACTIVE){ #if NODE_IS_ROUTER rates = rates + child_list->data_rate; sum_data_rates = sum_data_rates + rates; childs_len = childs_len + 1; #endif #if NODE_IS_SINK if(idx % 2 == 0){ even_window = even_window + child_list->data_rate; }else{ odd_window = odd_window + child_list->data_rate; } idx = idx + 1; #endif } } #if NODE_IS_ROUTER slots_offset = 0; //cluster_size = childs_len; available_slots = (BW_ROUTER_TS-(MAX_CHILDS/2 - childs_len/2)); for (k = 0; k < MAX_CHILDS; k++) { child_list = &node_list[k]; if (child_list->state == ACTIVE){ uint8_t slots_per_node = 0; #if WITH_UIP6 slots_per_node = (uint8_t)((59375*child_list->data_rate*available_slots)/(100000 *sum_data_rates)); #else slots_per_node = (uint8_t)((child_list->data_rate*available_slots)/(sum_data_rates)); #endif /**if the proportional chunk is higher than the requested data rate *fix the chuck to the data rate.*/ if(slots_per_node >= child_list->data_rate){ slots_per_node = (child_list->data_rate/2) + (child_list->data_rate % 2 == 1 ? 1 : 0); } if((slots_per_node == 0) ||(child_list->data_rate == MIN_DATA_RATE)){ slots_per_node = MIN_DATA_RATE; } child_list->assign_slots = slots_per_node; slots_offset = slots_offset + slots_per_node; } } #endif } #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER /*used to check if a specific node exists in our childs list. */ static uint8_t child_exist(rimeaddr_t *addr){ uint8_t k; node_list_t *ex_ptr; for (k = 0; k < MAX_CHILDS; k++) { ex_ptr = &node_list[k]; if (ex_ptr->state == ACTIVE){ if( rimeaddr_cmp(&ex_ptr->node_id, addr)) { ex_ptr->ttl = 0; return 1; } } } return 0; } #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER /**used to check if a specific node exists in our childs list*/ static uint8_t mobile_has_left(rimeaddr_t *addr, operation_t operation){ uint8_t k; mobile_state_t *mob_list; uint8_t exist = 0, pos = HDVR_LEN; for(k = 0; k < HDVR_LEN; k++){ mob_list = &handoff_list[k]; if(mob_list->state == ACTIVE){ mob_list->ttl = mob_list->ttl + 1; if(mob_list->ttl >= 4 && operation == REMOVE){ mob_list->ttl = 0; mob_list->state = INACTIVE; return 1; } if(rimeaddr_cmp(&mob_list->node_id, addr)){ exist = 1; if(operation == LOOKUP){ return 1; } } }else{ pos = k; } } if((operation == INSERT) && (exist == 0 ) && (pos < HDVR_LEN)){ handoff_list[pos].state = ACTIVE; handoff_list[pos].ttl = 0; rimeaddr_copy(&handoff_list[pos].node_id, addr); return 1; } //PRINTF("there is no such mobile node \n"); return 0; } #endif /**-------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_SINK void child_set_state(rimeaddr_t *addr, uint8_t state, uint8_t rate) { uint8_t k; node_list_t *c_elem; for (k = 0; k < MAX_CHILDS; k++ ) { c_elem = &node_list[k]; if(c_elem->state == ACTIVE){ //the node still alive, then update it if(state == NODE_STATUS_UPDATE && rimeaddr_cmp(&c_elem->node_id, addr)) { c_elem->ttl = 0; c_elem->data_rate = rate; } if(state == DATA_RATE_UPDATE && rimeaddr_cmp(&c_elem->node_id, addr)) { c_elem->ttl = 0; c_elem->data_rate = rate; #if NODE_IS_ROUTER data_rate_update = 1; //newx round, send update data rate #endif } if(state == NODE_UPDATE_ALL ){ c_elem->ttl = c_elem->ttl + 1; if(c_elem->ttl >= 7) { c_elem->state = INACTIVE; /**if we have not heard from the node for 3 beacon periods, purge it*/ } } } /**end of state == ACTIVE*/ } /**end of the for loop*/ } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_MOBILE /**Core procedure used for scanning the medium. It's mostly used by mobile sensor *nodes when accessing the network, or when performing the handover procedure. *This the procedure that sets the new candidate up. i.e, the new best router. */ static char mobile_chead_selection(struct rtimer *t, void *ptr){ uint8_t ret; neigh_adv_list_best(); if (uplink_ch >= 11 && uplink_ch < 26) { //PRINTF("Setting cc2420 Channel ID:%d\n", uplink_ch); cc2420_set_channel(uplink_ch); is_scanning = 0; /**a new router has been selected, we can now turn the radio off till we request the admission*/ off(); /**get the starting point of the admission rerquest phase*/ if(ad_t0_lock){ ad_t0 = RTIMER_NOW(); ad_t0_lock = 0; ad_tn_lock = 1; //PRINTF("mobile ad_t0: %2u \n", ad_t0); } synch_rx_to = RTIMER_NOW() + ROUTER_DL_TX_TS+2*GUARD_TIME; if (ch_offset %2 == 1) { synch_rx_to = synch_rx_to + ROUTER_UL_TX_TS; } synch_rx_to = NORM_CLOCK(synch_rx_to); node_state = NODE_RX_SYNCH; ret = rtimer_set(&generic_timer, synch_rx_to, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { //PRINTF("error _1:%d\n", ret); } return 1; } if(is_scanning){ if(handover){ off(); node_state = NODE_SLEEP; hdvr_rx_to = NORM_CLOCK(hdvr_rx_to + (SUPER_FRAME_DURATION - HDVR_TX_TS));; ret = rtimer_set(&generic_timer, hdvr_rx_to, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); }else{ ret = rtimer_set(&generic_timer, RTIMER_NOW() + SUPER_FRAME_DURATION, 1, (void (*)(struct rtimer *, void *))mobile_chead_selection, NULL); } if (ret) { //PRINTF("error starting mobile entry: %u\n", RTIMER_NOW()); } } return 1; } /**---------------------------------------------------------------------------*/ /**One of the core procedures. Mobile part invoke this procedure recursivelly to *turn the radio on/off depending on next operation to be executed. */ static char mobile_power_cycle(struct rtimer *t, void* ptr) { int ret; if(node_state == NODE_RX_UPLINK){ if(is_there_data && TIME_DIFF((RTIMER_NOW()+2*GUARD_TIME), ul_tx_to)){ is_there_data = 0; node_state = NODE_RX_UPLINK; /**we still have data to receive, so that we keep on waiting for more data to arrive*/ ret = rtimer_set(&generic_timer, RTIMER_NOW()+TS, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { PRINTF("mobile_power_cycle_error_there is data_1:%d\n", ret); } }else{ node_state = NODE_TX_UPLINK; off(); PRINTF("scheduling uplink Tx..\n"); ret = rtimer_set(&generic_timer, ul_tx_to, 1, (void (*)(struct rtimer *, void *))uplink_transmitter, NULL); if (ret) { PRINTF("mobile_power_cycle_error_there is data_2:%d\n", ret); } } return 1; } if(node_state == NODE_SLEEP){ if (handover){ /**a power drop has been detected, then a node should enter in the handover mode. Swicth the channel to 26 to listen to the nearby routers*/ on(); cc2420_set_channel(COMMON_CH); hdvr_rx_to = RTIMER_NOW(); if(hv_t0_lock){ /*collect some statistics*/ hv_t0_lock = 0; hv_tn_lock = 1; ad_t0_lock = 1; ad_tn_lock = 1; /**enables gathering the readmission time*/ hv_t0 = RTIMER_NOW(); } /**we have to go select the new chanel after listening 4TS*/ ret = rtimer_set(&generic_timer, RTIMER_NOW() + HDVR_TX_TS, 1, (void (*)(struct rtimer *, void *))mobile_chead_selection, NULL); if (ret) { PRINTF("error T_TX_RX_OFF:%d\n", ret); } }else{ /**if a node does not perform handover, then it should perform the normal duty-cycling*/ if(cc2420_get_channel() != data_channels[ch_offset]){ cc2420_set_channel(data_channels[ch_offset]); } node_state = NODE_RX_SYNCH; /**after NODE_SLEEPing, we should awake the node to resynchronize to its cluster head*/ ret = rtimer_set(&generic_timer, synch_rx_to, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { //PRINTF("Mobile_error awake_on:%d\n", ret); } } return 1; } if(node_state == NODE_RX_SYNCH){ //awake if (handover) { /**Whenever we finish one Schedule, we are not admitted, therefore, if there's not info about us, we should request admission again.**/ admitted = 0; is_scanning = 1; handover = 0; } on(); node_state = NODE_RX_UPLINK; PRINTF("synch...\n"); } return 1; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_SINK || NODE_IS_ROUTER static char tx_admin_info(struct rtimer *t, void* ptr){ int ret; admin_info_t info; node_state = NODE_TX_ADMIN_INFO; //PRINTF("NODE_TX_ADMIN_INFO \n"); /**we must switch to the common channel so as nodes in the admission phase can listen to us*/ if(cc2420_get_channel() != COMMON_CH){ cc2420_set_channel((uint8_t)COMMON_CH); } /**we set the type of message so that receivers can interprect it correctly*/ set_hdr_type(&info.hdr, HANDOVER_INFO); /**we also send our address*/ rimeaddr_copy(&info.hdr.src, &rimeaddr_node_addr); #if NODE_IS_SINK info.from = 0; info.hops = 0; /**how many hops (sink = root => hops = 0)*/ info.ch_id = 0; /**we inform in which channel_index the sink operates*/ #else /**if a router had the radio shut, then turn it back on*/ on(); info.from = 1; /**the advertisement is coming from a router node*/ info.hops = (nr_hops+1); /**how many hops are we far to the sink*/ info.ch_id = ch_offset; /**we inform in which channel we operate*/ #endif /**we inform how many routers are already attached to the sink*/ info.n_nodes = child_list_len(); /**we send this info to allow routers to connect to the sink node as well as mobile nodes to find the correct parent.*/ radio->send(&info, ADMIN_MSG_LEN); /**we make sure that we will wake up on the right channel*/ cc2420_set_channel((uint8_t)SINK_CH); /**we change our state to NODE_TX_DOWNLINK to synchronize our cluster*/ #if NODE_IS_SINK off(); /**We turn the radio off because it is not necessary by now.*/ node_state = NODE_TX_DOWNLINK; /**we go synchronize the cluster*/ ret = rtimer_set(&generic_timer, synch_tx_to, 1, (void (*)(struct rtimer *, void *))downlink_transmitter, NULL); if (ret) { //PRINTF("error scheduling tx_infra to dl_tx:%d\n", ret); } #endif #if NODE_IS_ROUTER /**For router nodes, any ms of radio off is useful, so we NODE_SLEEP again*/ if(TIME_DIFF((RTIMER_NOW()+2*GUARD_TIME), synch_rx_to)){ off(); } node_state = NODE_RX_SYNCH; /**we go synchronize to the cluster*/ ret = rtimer_set(&generic_timer, synch_rx_to, 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error scheduling tx_infra to dl_tx:%d\n", ret); } #endif return 1; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_SINK static char sink_power_cycle(struct rtimer *t, void* ptr){ int ret; if(node_state == NODE_TX_DOWNLINK){ node_state = NODE_RX_INFRA; /**we turn the radio on to listen for incoming messages during (NODE_RX_INFRA_tn - NODE_RX_INFRA_to)*/ on(); /**we schedule when to send the advertisement message on the common channel*/ ret = rtimer_set(&generic_timer, infra_rx_tn, 1, (void (*)(struct rtimer *, void *))tx_admin_info, NULL); if (ret) { //PRINTF("error scheduling tx_dl to NODE_RX_INFRA:%d\n", ret); } } return 1; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_ROUTER static char router_power_cycle(struct rtimer *t, void* ptr){ int ret; if(node_state == NODE_RX_UPLINK){ if(is_there_data && TIME_DIFF((RTIMER_NOW()+GUARD_TIME), radio_off_to)){ is_there_data = 0; /**we still have data to receive, so that we keep on waiting for more data to arrive*/ ret = rtimer_set(&generic_timer, (RTIMER_NOW()+TS/2), 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if(ret) { //PRINTF("router_power_cycle_error_there is data:%d\n", ret); } return 1; }else{ /**we should schedule the router node inmediately*/ off(); if((ch_offset % 2) == 1){ //PRINTF("scheduling UL_TX ch_off:%d\n", ch_offset); node_state = NODE_TX_UPLINK; ret = rtimer_set(&generic_timer, ul_tx_to, 1, (void (*)(struct rtimer *, void *))uplink_transmitter, NULL); if (ret) { //PRINTF("router_power_cycle_error_NODE_TX_UPLINK:%d\n", ret); } }else{ //node_state = NODE_TX_DOWNLINK; cc2420_set_channel(data_channels[ch_offset]); ret = rtimer_set(&generic_timer, dl_tx_to, 1, (void (*)(struct rtimer *, void *))downlink_transmitter, NULL); if (ret) { //PRINTF("router_power_cycle_error_NODE_TX_DOWNLINK:%d\n", ret); } } } /**end of MTIMER_*/ return 1; } /**end of node_state == NODE_RX_UPLINK*/ if(node_state == NODE_TX_DOWNLINK){ on(); node_state = NODE_RX_INFRA; //PRINTF("TX_DL to NODE_RX_INFRA\n"); ret = rtimer_set(&generic_timer, infra_rx_tn, 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("router_power_cycle_error_tx_dl_to_NODE_RX_INFRA:%d\n", ret); } return 1; } if(node_state == NODE_RX_INFRA){ /**we turn the radio off again*/ off(); /**if the router is even-synchronized, do the uplink tx*/ if (ch_offset % 2 == 0) { node_state = NODE_TX_UPLINK; ret = rtimer_set(&generic_timer, ul_tx_sch, 1, (void (*)(struct rtimer *, void *))uplink_transmitter, NULL); if (ret) { //PRINTF("error infra_to_uplink_tx:%d\n", ret); } //PRINTF("ROUTER: scheduling uplink_tx:%d \n",ret); }else{ /**if the router is odd-synchronized, do Handover TX_INFO */ node_state = NODE_TX_ADMIN_INFO; ret = rtimer_set(&generic_timer, hdvr_tx_to, 1, (void (*)(struct rtimer *, void *))tx_admin_info, NULL); if (ret) { //PRINTF("error infra_rx_to_NODE_TX_ADMIN_INFO: %d\n", ret); } } return 1; } /**end of node_state == NODE_RX_INFRA*/ if(node_state == NODE_RX_SYNCH){ node_state = NODE_RX_UPLINK; /**we set the channel where th cluster head is operating in *and consequently, we turn the radio on to listen to*/ on(); /**update bandwidth*/ child_data_rates(); //make sure that sum(rate[i]) is computed before return 1; } /*end of node_state == NODE_RX_UPLINK*/ if(node_state == NOTHING){ /**we have boot quite recently, and therefore, we must select a parent*/ neigh_adv_list_best(); if((uplink_ch >= 11) && (uplink_ch <= 26)){ /*we have found a parent node. First we change our state*/ node_state = NODE_RX_SYNCH; cc2420_set_channel(uplink_ch); /*we set our channel to the parent channel*/ /*any ms of saved energy is useful :)*/ off(); } ret = rtimer_set(&generic_timer, ((node_state == NODE_RX_SYNCH) ? RTIMER_NOW(): RTIMER_NOW()+ROUTER_DL_TX_TS), 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error scheduling tx_infra to dl_tx:%d\n", ret); } } /*end of node_state == NOTHING*/ return 1; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE uint8_t mobile_node_data_rate(void){ return data_rate; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE static char slot_request(struct rtimer *t, void* ptr) { uint8_t ret; rdc_hdr_t hdr; //PRINTF(" slot request\n"); #if NODE_IS_ROUTER set_hdr_type(&hdr, ROUTER_SLOT_REQ); hdr.pld_len = data_rate; //MIN_DATA_RATE; ad_t0 = RTIMER_NOW(); ad_t0_lock = 0; ad_tn_lock = 1; //PRINTF("router ad_t0: %2u \n", ad_t0); #endif #if NODE_IS_MOBILE set_hdr_type(&hdr, MOBILE_SLOT_REQ); hdr.pld_len = data_rate; #endif rimeaddr_copy(&hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&hdr.dest, &rimeaddr_null); radio->send(&hdr, RDC_HDR_LEN); #if NODE_IS_MOBILE node_state = NODE_RX_SYNCH; ret = rtimer_set(&generic_timer, (synch_rx_to-TS/2), 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { //PRINTF("error MOB_AWAKE_OFFSET_1:%d\n", ret); } #endif #if NODE_IS_ROUTER node_state = NODE_RX_SYNCH; ret = rtimer_set(&generic_timer, synch_rx_to-GUARD_TIME, 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error MOB_AWAKE_OFFSET_1:%d\n", ret); } #endif off(); return 1; } #endif /*-----------------------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE /*Generic Uplink TX function. This function is Is used by routers and mobile * nodes to send data upstream. This function is also part of the duty-cycling*/ static char uplink_transmitter(struct rtimer *t, void* ptr) { uint8_t ret; if (TIME_DIFF((RTIMER_NOW()), ul_tx_to)) { off(); node_state = NODE_SLEEP; ret = rtimer_set(&generic_timer, ul_tx_to, 1, (void (*)(struct rtimer *, void *))uplink_transmitter, NULL); if (ret) { //PRINTF("TX_UL_error awake_on:%d\n", ret); } return 1; } on(); node_state = NODE_TX_UPLINK; #if NODE_IS_MOBILE PRINTF("transmitting UL\n"); if (handover) { rdc_hdr_t c_hdr; c_hdr.pld_len = 0; set_hdr_type(&c_hdr, NODE_SLOT_RELEASE); rimeaddr_copy(&c_hdr.src, &rimeaddr_node_addr); /*if(hv_t0_lock){ //collect some statistics hv_t0_lock = 0; hv_tn_lock = 1; ad_t0_lock = 1; ad_tn_lock = 1; //enables gathering the readmission time hv_t0 = RTIMER_NOW(); }*/ radio->send(&c_hdr, RDC_HDR_LEN); } else { if(data_rate_update){ rdc_hdr_t c_hdr; data_rate_update = 0; c_hdr.pld_len = data_rate; set_hdr_type(&c_hdr, DATA_RATE_UPDATE); rimeaddr_copy(&c_hdr.src, &rimeaddr_node_addr); radio->send(&c_hdr, RDC_HDR_LEN); }else{ /*a kind of keep-alive message :)*/ if (beacon_seqno % 5 == 0) { rdc_hdr_t c_hdr; c_hdr.pld_len = data_rate; set_hdr_type(&c_hdr, NODE_STATUS_UPDATE); rimeaddr_copy(&c_hdr.src, &rimeaddr_node_addr); radio->send(&c_hdr, RDC_HDR_LEN); } } } #endif #if NODE_IS_ROUTER if (uplink_ch != SINK_CH || (cc2420_get_channel() != SINK_CH)) { cc2420_set_channel((uint8_t)SINK_CH); uplink_ch = SINK_CH; } if(data_rate_update) { child_data_rates(); /*bandwidth update ...*/ rdc_hdr_t c_hdr; c_hdr.pld_len = /**data_rate +*/ sum_data_rates; data_rate_update = 0; set_hdr_type(&c_hdr, DATA_RATE_UPDATE); rimeaddr_copy(&c_hdr.src, &rimeaddr_node_addr); radio->send(&c_hdr, RDC_HDR_LEN); } #endif #if NODE_IS_ROUTER || NODE_IS_MOBILE if(send_stats_pkt){ uint8_t dlen = 0; rdc_msg_t pack; send_stats_pkt = 0; rimeaddr_copy(&pack.hdr.dest, &sink_node_addr); rimeaddr_copy(&pack.hdr.src, &rimeaddr_node_addr); /**we increment the number of packets originated on this node.*/ #if NODE_IS_MOBILE set_hdr_type(&pack.hdr, MOBILE_DATA); #else set_hdr_type(&pack.hdr, ROUTER_DATA); #endif #if !WITH_UIP6 network_hdr_t n_hdr; /*5 refers to the info header*/ dlen = (5 + sizeof(network_statistics_t)); pack.hdr.pld_len = dlen; n_hdr.seqno = 0; n_hdr.hops = 1; n_hdr.pack_type = NETWORK_PERFORMANCE; /*network performance*/ #if NODE_IS_MOBILE n_hdr.node_type = MOBILE_NODE; #else n_hdr.node_type = ROUTER_NODE; #endif memcpy((void*)&pack.data[0], (void*)&n_hdr, NETWORK_HDR_LEN); n_tx_bytes += (dlen + RDC_HDR_LEN); /*number of bytes*/ /*we need to collect some results, so we ask the mac to do so*/ get_node_statistics((void*)&pack.data[NETWORK_HDR_LEN]); /*we ask the radio driver to send the packet*/ radio->send((void*)&pack, (dlen + RDC_HDR_LEN)); #else PRINTF("sending statistics packet...TO:"); PRINTMACADDR(&sink_node_addr); pack.data[0] = UIP_NTWK_PERFORMANCE; dlen = (1 + sizeof(network_statistics_t)); pack.hdr.pld_len = dlen; get_node_statistics((void*)&pack.data[1]); /*we ask the radio driver to send the packet*/ radio->send((void*)&pack, (dlen + RDC_HDR_LEN)); #endif /**WITH_UIP6*/ } #endif while (((next_to_send_ul != last_queued_ul) && (ul_b_full == 0)) && TIME_DIFF((RTIMER_NOW() + GUARD_TIME), ul_tx_tn)) { uint8_t pkt_len = ul_queue[next_to_send_ul]->hdr.pld_len; if(pkt_len){ /**We ask the radio driver to send the packet, and we free the packet only when we have succeeded on transmitting that packet*/ radio->send((void*)ul_queue[next_to_send_ul], (pkt_len + RDC_HDR_LEN)); //RADIO_TX_OK ul_queue[next_to_send_ul]->hdr.pld_len = 0; /*if(radio->send((void*)ul_queue[next_to_send_ul], (pkt_len + RDC_HDR_LEN)) == RADIO_TX_OK){ ul_queue[next_to_send_ul]->hdr.pld_len = 0; }*/ } if(++next_to_send_ul >= UL_QUEUE_SIZE){ next_to_send_ul = 0; } if(ul_b_full){ ul_b_full = 0; } } /**end of the while loop*/ if(ul_b_full){ ul_b_full = 0; } #if NODE_IS_MOBILE off(); PRINTF("tx_ul_finished, back mob_pc\n"); node_state = NODE_SLEEP; ret = rtimer_set(&generic_timer, hdvr_rx_to, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { PRINTF("error NODE_TX_UPLINK_MOB_AWAKE_OFFSET_1:%d\n", ret); } #endif #if NODE_IS_ROUTER if(TIME_DIFF((RTIMER_NOW()), hdvr_tx_to)){ off(); } if (ch_offset % 2 == 1) { node_state = NODE_TX_DOWNLINK; ret = rtimer_set(&generic_timer, dl_tx_to, 1, (void (*)(struct rtimer *, void *))downlink_transmitter, NULL); if (ret) { //PRINTF("error downlink_tx:%d\n", ret); } }else{ node_state = NODE_TX_ADMIN_INFO; ret = rtimer_set(&generic_timer, hdvr_tx_to, 1, (void (*)(struct rtimer *, void *))tx_admin_info, NULL); if (ret) { //PRINTF("error shceduling hdvr_tx: %d\n", ret); } } #endif return 1; } #endif /** NODE_IS_ROUTER || NODE_IS_MOBILE init*/ /*-----------------------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_SINK static char downlink_transmitter(struct rtimer *t, void *ptr) { uint8_t* b_ptr; uint8_t ret; uint8_t cluster_len = 0; uint8_t ass_slots = 0; uint8_t admin_slots = 0; rdc_msg_t packet; synch_msg_t beacon; uint8_t data_len, k, idx=0; node_state = NODE_TX_DOWNLINK; //set the state we are //PRINTF("DL-Transmitter Radio is on, and state is NODE_TX_DOWNLINK\n"); #if NODE_IS_ROUTER uint8_t nodes_tx_offset = 0; uint8_t available_slots; //total available slots during round i #endif #if NODE_IS_SINK my_clock_t ref_to = RTIMER_NOW(); synch_tx_to = NORM_CLOCK(ref_to + SUPER_FRAME_DURATION); /*to+76TS*/ infra_rx_to = NORM_CLOCK(ref_to + (SINK_DL_TX_TS)); /*to+8TS*/ infra_rx_tn = NORM_CLOCK(ref_to + SINK_DL_TX_TS + SINK_UL_RX_TS); /*to+8TS+64TS*/ dl_tx_tn = infra_rx_to; uint8_t odd_slots; //odd_part slots uint8_t even_slots; //even_part slots uint8_t odd_offset = 0; //offset between neighbors uint8_t even_offset = 0; //offset between neighbors #endif node_list_t *nodes; on(); //cluster_size = 0; cluster_len = child_list_len(); //cluster_size = cluster_len; //PRINTF("Cluster size: %d\n", cluster_size); /**set the source address*/ rimeaddr_copy(&packet.hdr.src, &rimeaddr_node_addr); /**set the destination address(broadcast)*/ rimeaddr_copy(&packet.hdr.dest, &rimeaddr_null); /**send the sequence number and number of neighbors.*/ beacon.n_childs = cluster_len; beacon.seqno = beacon_seqno; #if NODE_IS_SINK set_hdr_type(&packet.hdr, SINK_BEACON); child_data_rates(); //make sure that sum(BW[i]) is computed before admin_slots = sink_slots_tbl[cluster_len].free_slots; odd_slots = sink_slots_tbl[cluster_len].odd_slots; even_slots = sink_slots_tbl[cluster_len].even_slots; beacon.nr_hops = 0; /*the root must advertise 0 hops!*/ #endif #if NODE_IS_ROUTER /**switch RF channel*/ if((beacon_seqno % 13 == 0) && (cluster_size != 0)){ child_set_state(NULL, NODE_UPDATE_ALL, 0); } /*a Mobile nodes that has left our cluster will still be able to receive data for a short while*/ mobile_has_left(&rimeaddr_node_addr, REMOVE); /*we turn the radio on*/ /*we make sure that we are on the right channel*/ cc2420_set_channel(data_channels[ch_offset]); /*we make sure that we send the right message*/ set_hdr_type(&packet.hdr, ROUTER_BEACON); beacon.n_routers = num_neighbors; beacon.ch_offset = ch_offset; beacon.nr_hops = (nr_hops +1); PRINTF("ch_offset: %d, ch_len: %d\n", ch_offset, cluster_size); admin_slots = (MAX_CHILDS/4 - cluster_size/4); available_slots = (BW_ROUTER_TS - admin_slots); #endif beacon.free_slots = admin_slots; packet.hdr.pld_len = SYNCH_MSG_LEN + cluster_len*SLOT_MSG_LEN; beacon_seqno++; /**copy the cluster info into the synchronization packet*/ memcpy(&packet.data[0], &beacon, SYNCH_MSG_LEN); //PRINTF("Cluster_size: %d\n", cluster_size); /*fill the payload, but first acquire the first byte of the payload*/ b_ptr = (uint8_t*)&packet.data[SYNCH_MSG_LEN]; //PRINTF("cluster len:%d\n",cluster_len); /**fill the node's schdeule into the synchronization packet*/ for (k = 0, idx = 0; k < MAX_CHILDS ; k++) { nodes = &node_list[k]; if (nodes->state == ACTIVE) { slot_dist_t *msg = (slot_dist_t*) (b_ptr + idx * SLOT_MSG_LEN); #if NODE_IS_SINK uint8_t flag = 0; uint8_t mask = 0; ass_slots = MIN_DATA_RATE; /*set default data rate*/ if(idx % 2 == 0){ if((even_window != 0) && nodes->data_rate != MIN_DATA_RATE){ ass_slots = (nodes->data_rate*even_slots)/even_window; } mask = (mask | (even_offset & 0x1F)); mask = (mask | ((idx+1) << 5)); /*channel ID*/ msg->ts_offset = mask; mask = 0; flag = is_there_packet_to(&nodes->node_id); mask = (mask | ( ass_slots & 0x1F)); mask = (mask | ((flag & 0x01) << 5)); msg->assig_slots = mask; even_offset = even_offset + ass_slots; rimeaddr_copy(&msg->node_id, &nodes->node_id); idx++; }else{ if((odd_window != 0) && nodes->data_rate != MIN_DATA_RATE){ ass_slots = (nodes->data_rate*odd_slots)/odd_window; } mask = (mask | (odd_offset & 0x1F)); mask = (mask | ((idx+1) << 5)); /*channel ID*/ //mask = (mask | ((MAX_CHILDS-k) << 5)); /*channel ID*/ msg->ts_offset = mask; mask = 0; //flag = is_there_packet_to(&nodes->node_id); mask = (mask | ( ass_slots & 0x1F)); mask = (mask | ((flag & 0x01) << 5)); msg->assig_slots = mask; //msg->assig_slots = ass_slots; odd_offset = odd_offset + ass_slots; rimeaddr_copy(&msg->node_id, &nodes->node_id); idx++; } #endif #if NODE_IS_ROUTER uint8_t flag = 0; uint8_t mask = 0; ass_slots = MIN_DATA_RATE; //flag = is_there_packet_to(&nodes->node_id); /**compute the share for each mobile node based on the rate/weight */ mask = (mask | (nodes_tx_offset & 0x1F)); mask = (mask | ((flag & 0x01) << 5)); /*packet tag*/ msg->ts_offset = mask; msg->assig_slots = nodes->assign_slots; rimeaddr_copy(&msg->node_id, &nodes->node_id); nodes_tx_offset = nodes_tx_offset + nodes->assign_slots; idx++; #endif } } #if NODE_IS_ROUTER //PRINTF("nodes_tx_offset: %d\n", nodes_tx_offset); #endif /*calculate how big is the synchronization packet*/ data_len = RDC_HDR_LEN + packet.hdr.pld_len; /**send synchronization packet.*/ radio->send((void*)&packet, data_len); //PRINTF("Beacon transmitted\n"); data_len = 0; /**Flush data downstream as fast as possible, and terminate when the buffer is empty of the downlink time has finished*/ while ((next_to_send_dl != last_queued_dl) && TIME_DIFF(RTIMER_NOW()+GUARD_TIME, dl_tx_tn)){ data_len = dl_queue[next_to_send_dl]->hdr.pld_len; if(data_len){ /*ask the radio driver to send the packet */ radio->send((void*)dl_queue[next_to_send_dl], (data_len + RDC_HDR_LEN)); dl_queue[next_to_send_dl]->hdr.pld_len = 0; }else{ break; } /*we loop to the next packet*/ next_to_send_dl = (next_to_send_dl + 1) % DL_QUEUE_SIZE; /*if the buffer was locked, unlock it so that it can accept data from the application layer*/ if(dl_b_full){ dl_b_full = 0; } } /*if the buffer was locked, unlock it so that it can accept <gonga> data from the application layer*/ if(dl_b_full){ dl_b_full = 0; } if(TIME_DIFF(RTIMER_NOW(), dl_tx_tn)){ off(); //PRINTF("radio is off\n"); } #if NODE_IS_SINK /*the sink enters in the recption mode, and schedule a new synch packed*/ node_state = NODE_TX_DOWNLINK; ret = rtimer_set(&generic_timer, infra_rx_to, 1, (void (*)(struct rtimer *, void *))sink_power_cycle, NULL); if (ret) { //PRINTF("send periodic beacon error #2: %d\n", ret); } #endif #if NODE_IS_ROUTER node_state = NODE_TX_DOWNLINK; //set the state we are node_state = NODE_RX_INFRA; ret = rtimer_set(&generic_timer, infra_rx_to, 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error_tx_dl_to_infra_rx:%d\n", ret); } #endif return 1; } #endif /**---------------------------------------------------------------------------*/ inline static void create_rdc_packet(rdc_msg_t* msg, rimeaddr_t *dest, u8_t uplink, u8_t data_len, u8_t type){ if(uplink){ #if NODE_IS_ROUTER || NODE_IS_MOBILE msg = ul_queue[last_queued_ul]; #endif }else{ #if NODE_IS_ROUTER || NODE_IS_SINK msg = dl_queue[last_queued_dl]; #endif } msg->hdr.type = type; msg->hdr.pld_len = data_len; rimeaddr_copy(&msg->hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&msg->hdr.dest, dest); memcpy((char*)msg->data, packetbuf_dataptr(), msg->hdr.pld_len); if(uplink){ #if NODE_IS_ROUTER || NODE_IS_MOBILE last_queued_ul = (last_queued_ul + 1) % UL_QUEUE_SIZE; if(last_queued_ul == next_to_send_ul){ ul_b_full = 1; } #endif }else{ #if NODE_IS_ROUTER || NODE_IS_SINK last_queued_dl = (last_queued_dl + 1) % DL_QUEUE_SIZE; if(last_queued_dl == next_to_send_dl){ dl_b_full = 1; } #endif } } /**---------------------------------------------------------------------------*/ static int packet_out(void) { uint8_t data_len; rimeaddr_t dest; rdc_msg_t *msg; data_len = packetbuf_datalen(); rimeaddr_copy(&dest, packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); #if !WITH_UIP6 #if NODE_IS_ROUTER || NODE_IS_MOBILE n_tx_packets++; /*The number of packets originated on this node*/ n_tx_bytes += (data_len + RDC_HDR_LEN); /*number of bytes*/ if(n_tx_packets % 100 == 0){ report_type = 3; send_stats_pkt = 1; } #endif #endif /*!WITH_UIP6*/ #if NODE_IS_ROUTER if (rimeaddr_cmp(&dest, &rimeaddr_null) || child_exist(&dest)) { if (dl_b_full == 0 && (dl_buf_state != NODE_WRITE_BUF)) { dl_buf_state = NODE_WRITE_BUF; msg = (rdc_msg_t*)dl_queue[last_queued_dl]; msg->hdr.type = ROUTER_DATA; msg->hdr.pld_len = data_len; rimeaddr_copy(&msg->hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&msg->hdr.dest, &dest); memcpy(msg->data, packetbuf_dataptr(), msg->hdr.pld_len); last_queued_dl = (last_queued_dl + 1) % DL_QUEUE_SIZE; if(last_queued_dl == next_to_send_dl){ dl_b_full = 1; } //create_rdc_packet(msg, &dest, 0, data_len, ROUTER_DATA); dl_buf_state = NOTHING; } } if (rimeaddr_cmp(&dest, &rimeaddr_null) || (child_exist(&dest) == 0)) { if (ul_b_full == 0 && (ul_buf_state != NODE_WRITE_BUF)) { ul_buf_state = NODE_WRITE_BUF; msg = ul_queue[last_queued_ul]; msg->hdr.type = ROUTER_DATA; msg->hdr.pld_len = data_len; rimeaddr_copy(&msg->hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&msg->hdr.dest, &dest); memcpy((char*)msg->data, packetbuf_dataptr(), msg->hdr.pld_len); last_queued_ul = (last_queued_ul + 1) % UL_QUEUE_SIZE; if(last_queued_ul == next_to_send_ul){ ul_b_full = 1; } //create_rdc_packet(msg, &dest, 0, data_len, ROUTER_DATA); ul_buf_state = NOTHING; } } #endif #if NODE_IS_MOBILE if (ul_b_full == 0){ msg = ul_queue[last_queued_ul]; msg->hdr.type = MOBILE_DATA; msg->hdr.pld_len = data_len; rimeaddr_copy(&msg->hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&msg->hdr.dest, &dest); memcpy((void*)msg->data, packetbuf_dataptr(), msg->hdr.pld_len); last_queued_ul = (last_queued_ul + 1) % UL_QUEUE_SIZE; if(last_queued_ul == next_to_send_ul){ ul_b_full = 1; } //create_rdc_packet(msg, &dest, 1, data_len, MOBILE_DATA); //PRINTF("dest: %d.%d.%d.%d\n", dest.u8[4], dest.u8[5], dest.u8[6], dest.u8[7]); } #endif #if NODE_IS_SINK if ((dl_buf_state != NODE_WRITE_BUF) && dl_b_full == 0) { dl_buf_state = NODE_WRITE_BUF; msg = dl_queue[last_queued_dl]; msg->hdr.type = SINK_DATA; msg->hdr.pld_len = data_len; rimeaddr_copy(&msg->hdr.src, &rimeaddr_node_addr); rimeaddr_copy(&msg->hdr.dest, &dest); memcpy((void*)msg->data, packetbuf_dataptr(), msg->hdr.pld_len); last_queued_dl = (last_queued_dl + 1) % DL_QUEUE_SIZE; if(last_queued_dl == next_to_send_dl){ dl_b_full = 1; } //create_rdc_packet(msg, &dest, 0, data_len, SINK_DATA); dl_buf_state = NOTHING; //PRINTF("dest: %d.%d.%d.%d\n", dest.u8[4], dest.u8[5], dest.u8[6], dest.u8[7]); } #endif return 1; } /*----------------------------------------------------------------------------- *when a synch packet is received, each node sets up its reference time to the *time at which the synch packet was received. In this way, we expect to synchronize * the mobile nodes. */ static int packet_in(void) { uint8_t len; static rdc_hdr_t hdr; static rdc_msg_t msg; len = radio->read((void*) & msg, PACKETBUF_SIZE); if (len > 0) { memcpy((char*) & hdr, (char*) & msg, RDC_HDR_LEN); #if NODE_IS_MOBILE PRINTF("packet_type: %d\n", hdr.type); #endif #if NODE_IS_SINK if (hdr.type == ROUTER_SLOT_REQ) { /**process request localy*/ if (child_list_len() < MAX_CHILDS) { /*the 'pld_len' in this case contains the number of childs *attached to that router. */ child_add(&hdr.src, hdr.pld_len, 1); } return 1; } /*update data rate*/ if (hdr.type == DATA_RATE_UPDATE) { child_set_state(&hdr.src, hdr.type, hdr.pld_len); //data_rate_update = 1; return 1; } if (hdr.type == ROUTER_DATA) { /**data packet received, signal upper layers*/ uint8_t dlen = hdr.pld_len; if (!rimeaddr_cmp(&(hdr.src), &rimeaddr_node_addr) && (rimeaddr_cmp(&(hdr.dest), &rimeaddr_node_addr) || rimeaddr_cmp(&(hdr.dest), &rimeaddr_null))) { #if WITH_UIP6 if ((msg.data[0] == UIP_NTWK_PERFORMANCE) && (dlen == (sizeof (network_statistics_t) + 1))) { if (inpacket_callback != NULL) { //PRINTF("network performance packet...from: "); PRINTMACADDR(&hdr.src); inpacket_callback(&hdr.src, (void*) & msg.data[1], hdr.pld_len); } } else { if (uip_callback_func != NULL) { /*PRINTF("packet received from: "); PRINTAMACDDR(&hdr.src);*/ uip_callback_func(&hdr.src, &hdr.dest, (void*) & msg.data[0], hdr.pld_len); } } #else if (inpacket_callback != NULL) { inpacket_callback(&hdr.src, (void*) & msg.data[0], hdr.pld_len); } #endif } else { /*get the number of hops and increment it*/ if ((dl_buf_state != NODE_WRITE_BUF) && (dl_b_full == 0)) { dl_buf_state = NODE_WRITE_BUF; //leds_toggle(LEDS_BLUE); #if !WITH_UIP6 uint8_t *hops = (uint8_t*) (&msg.data[2]); *hops = *hops + 1; #endif set_hdr_type(&msg.hdr, SINK_DATA); memcpy(dl_queue[last_queued_dl], &msg, sizeof (rdc_msg_t)); last_queued_dl = (last_queued_dl + 1) % DL_QUEUE_SIZE; if (last_queued_dl == next_to_send_dl) { dl_b_full = 1; } dl_buf_state = NOTHING; } } //end of else } #endif #if NODE_IS_ROUTER if (hdr.type == MOBILE_SLOT_REQ) { /**process request localy*/ if (child_list_len() < MAX_CHILDS) { /*the 'pld_len' paramenter is the mobile node data rate*/ child_add(&hdr.src, hdr.pld_len, 3); } return 1; } /*update child status including data rate*/ if (hdr.type == NODE_STATUS_UPDATE) { child_set_state(&hdr.src, hdr.type, hdr.pld_len); } /*release a slot, node is in handover mode*/ if (hdr.type == NODE_SLOT_RELEASE) { if (child_remove(&hdr.src)) { data_rate_update = 1; mobile_has_left(&hdr.src, INSERT); cluster_size = (cluster_size > 0) ? (cluster_size - 1) : 0; } return 1; } /*update data rate*/ if (hdr.type == DATA_RATE_UPDATE) { child_set_state(&hdr.src, hdr.type, hdr.pld_len); data_rate_update = 1; return 1; } if (hdr.type == SINK_DATA || hdr.type == MOBILE_DATA) { /**data packet received, signal upper layers*/ uint8_t dlen = hdr.pld_len; is_there_data = 1; /*we have received data, so we must keep on waiting for more 1TS before we go NODE_SLEEP*/ /*this is a data addressed to a mobile node or is a local-broadcast*/ if ((!rimeaddr_cmp(&(hdr.src), &rimeaddr_node_addr)) && (rimeaddr_cmp(&(hdr.dest), &rimeaddr_node_addr) || rimeaddr_cmp(&(hdr.dest), &rimeaddr_null))) { /*this trick is necessary to allow cluster broadcast*/ static rdc_msg_t msg_cpy; memcpy(&msg_cpy, &msg, (RDC_HDR_LEN + hdr.pld_len)); #if WITH_UIP6 if (uip_callback_func != NULL) { uip_callback_func(&msg_cpy.hdr.src, &msg_cpy.hdr.dest, (void*) & msg_cpy.data[0], dlen); } #else if (inpacket_callback != NULL) { inpacket_callback(&msg_cpy.hdr.src, (void*) & msg_cpy.data[0], dlen); } #endif } if (child_exist(&hdr.dest) || (rimeaddr_cmp(&hdr.dest, &rimeaddr_null) && hdr.type == MOBILE_DATA)) { if ((dl_buf_state != NODE_WRITE_BUF) && (dl_b_full == 0)) { dl_buf_state = NODE_WRITE_BUF; set_hdr_type(&msg.hdr, ROUTER_DATA); //get the number of hops and increment it #if !WITH_UIP6 uint8_t *hops = (uint8_t*) (&msg.data[2]); *hops = *hops + 1; #endif memcpy((void*) dl_queue[last_queued_dl], (void*) & msg, (RDC_HDR_LEN + hdr.pld_len)); last_queued_dl = (last_queued_dl + 1) % DL_QUEUE_SIZE; if (last_queued_dl == next_to_send_dl) { dl_b_full = 1; } dl_buf_state = NOTHING; leds_toggle(LEDS_BLUE); #if WITH_UIP6 PRINTF("Routing DL: dst"); PRINTMACADDR(&hdr.dest); PRINTF("src: "); PRINTMACADDR(&hdr.src); #endif } /**dl_buf_state*/ } else { /*the destination was not found in the router's list, if the data is from a mobile node this should be forwarded upstream*/ if (((!rimeaddr_cmp(&hdr.dest, &rimeaddr_node_addr)) && (child_exist(&hdr.dest) == 0) && hdr.type == MOBILE_DATA) || mobile_has_left(&hdr.dest, LOOKUP)) { if ((ul_b_full == 0) && (ul_buf_state != NODE_WRITE_BUF)) { ul_buf_state = NODE_WRITE_BUF; set_hdr_type(&msg.hdr, ROUTER_DATA); //get the number of hops and increment it #if !WITH_UIP6 uint8_t *hops = (uint8_t*) (&msg.data[2]); *hops = *hops + 1; #endif memcpy((void*) ul_queue[last_queued_ul], (void*) & msg, (RDC_HDR_LEN + hdr.pld_len)); last_queued_ul = (last_queued_ul + 1) % UL_QUEUE_SIZE; if (last_queued_ul == next_to_send_ul) { ul_b_full = 1; } ul_buf_state = NOTHING; leds_toggle(LEDS_BLUE); #if WITH_UIP6 PRINTF("Routing UL: dst"); PRINTMACADDR(&hdr.dest); PRINTF("src: "); PRINTMACADDR(&hdr.src); #endif } } /**end of child_exist(&hdr.dest)) && hdr.type == MOBILE_DATA) */ } } /*end of hdr.type == SINK_DATA || hdr.type == MOBILE_DATA*/ #endif #if NODE_IS_ROUTER || NODE_IS_MOBILE if (hdr.type == HANDOVER_INFO) { admin_info_t adv; memcpy(&adv, &msg, ADMIN_MSG_LEN); #if NODE_IS_MOBILE /*MOBILE NODEs connect only to routers, so we must skip the sink msg*/ if (adv.hops != 0) { parents_add(&adv); } #else /*a router can also add other routers*/ parents_add(&adv); #endif return 1; } #endif /*NODE_IS_ROUTER || NODE_IS_MOBILE*/ #if NODE_IS_MOBILE if ((!is_scanning) && (hdr.type == ROUTER_DATA)) { /**data packet received, signal upper layers*/ uint8_t dlen = hdr.pld_len; /*we have received data, so we must keep on waiting for more 1TS before we go NODE_SLEEP*/ is_there_data = 1; /* PRINTF("data received: dst"); PRINTMACADDR(&hdr.dest); PRINTF("src: "); PRINTMACADDR(&hdr.src); */ if ((rimeaddr_cmp(&hdr.src, &rimeaddr_node_addr) == 0) && (rimeaddr_cmp(&hdr.dest, &rimeaddr_node_addr) || rimeaddr_cmp(&hdr.dest, &rimeaddr_null))) { #if WITH_UIP6 if (uip_callback_func != NULL) { uip_callback_func(&msg.hdr.src, &msg.hdr.dest, (void*) & msg.data[0], dlen); } #else if (inpacket_callback != NULL) { inpacket_callback(&hdr.src, (void*) & msg.data[0], dlen); } #endif } return 1; } #endif /*NODE_IS_MOBILE hdr.type == ROUTER_DATA */ #if NODE_IS_MOBILE || NODE_IS_ROUTER uint8_t ret; ref_timer = RTIMER_NOW(); //reference timer if (hdr.type == SINK_BEACON || hdr.type == ROUTER_BEACON) { /**don't signal upper layers, synchronize*/ synch_msg_t beacon; uint8_t k, schedule_len = hdr.pld_len - SYNCH_MSG_LEN; memcpy((char*) & beacon, (char*) & msg.data[0], sizeof (synch_msg_t)); #if NODE_IS_ROUTER if (hdr.type == ROUTER_BEACON) { return 1; //skip router beacons } num_neighbors = beacon.n_childs; free_slots = beacon.free_slots; beacon_seqno = beacon.seqno; nr_hops = beacon.nr_hops; #endif #if NODE_IS_MOBILE signed char base_rssi; occupied_ts = 0; if (hdr.type == SINK_BEACON) { return 1; //skip sink beacons } base_rssi = PWR_DBM(); free_slots = beacon.free_slots; beacon_seqno = beacon.seqno; num_neighbors = beacon.n_childs; ch_offset = beacon.ch_offset; nr_hops = beacon.nr_hops; uplink_ch = data_channels[ch_offset]; /**the received power has dropped to an unacceptable level, we instruct the mobile node to start handover*/ if (admitted) { if (TIME_DIFF(base_rssi, TH_POWER)) { if (neigh_adv_list_len()) { handover = 1; hv_t0_lock = 1; } } } PRINTF("sched_len: %d\n", schedule_len); #endif //NODE_IS_MOBILE if (hdr.pld_len > SYNCH_MSG_LEN) { uint8_t* b_ptr; b_ptr = &msg.data[SYNCH_MSG_LEN]; schedule_len = hdr.pld_len - SYNCH_MSG_LEN; #if NODE_IS_MOBILE #endif for (k = 0; k < schedule_len; k += SLOT_MSG_LEN) { slot_dist_t* slot = (slot_dist_t*) (b_ptr + k); /*we must count how many occupied slots exist on the cluster head*/ #if NODE_IS_MOBILE occupied_ts = occupied_ts + slot->assig_slots; #endif if (rimeaddr_cmp(&slot->node_id, &rimeaddr_node_addr)) { #if NODE_IS_ROUTER is_there_pkt = 1; ts_offset = (slot->ts_offset & 0x1F); /*we add one because the channel offset cannot be zero *to avoid having the same channel with the sink node*/ ch_offset = (1 + (slot->ts_offset >> 5)); PRINTF("router_ch_offset: %d\n", ch_offset); //uplink_ch = data_channels[ch_offset]; //is_there_pkt = (slot->assig_slots >> 5); assign_slots = (slot->assig_slots & 0x1F); #endif #if NODE_IS_MOBILE is_there_pkt = 0; ts_offset = (slot->ts_offset & 0x1F); is_there_pkt = (slot->ts_offset >> 5); assign_slots = slot->assig_slots; PRINTF("ch_off/ass_slots:%d/%d\n", ch_offset, assign_slots); #endif admitted = 1; is_scanning = 0; /*statistics data*/ ass_d_rate = assign_slots; #if NODE_IS_MOBILE & RATE_CONTROL if (rate_update_func != NULL) { if (node_data_rate != assign_slots) { rate_update_func(ass_d_rate); } } #endif /*get admission time*/ if (ad_tn_lock) { ad_tn_lock = 0; ad_tn = RTIMER_NOW(); /*we enable this info to reach the sink*/ send_stats_pkt = 1; if (nc_tn_lock) { nc_tn_lock = 0; nc_tn = ad_tn; /**The node was admitted for the first time. then take the current router as the cluster head*/ rimeaddr_copy(&curr_router, &hdr.src); rimeaddr_copy(&next_router, &hdr.src); } //PRINTF("ad_tn: %2u \n",ad_tn); if (hv_tn_lock) { hv_tn = ad_tn; report_type = 2; /** The nodes has finished handover, get the next*/ rimeaddr_copy(&curr_router, &next_router); rimeaddr_copy(&next_router, &hdr.src); } } /*end of ad_tn_lock*/ } /* end of rimeaddr_cmp(&slot->node_id, &rimeaddr_node_addr)*/ } //end of for } /*end of if (hdr.pld_len > 0)*/ if (admitted == 0) { uint8_t idx; #if NODE_IS_MOBILE signed char base_rssi = PWR_DBM(); if ((TIME_DIFF(base_rssi, TH_POWER) || (num_neighbors == MAX_CHILDS)) || (atempts >= 4 || free_slots == 0)) { atempts = 0; uplink_ch = 0; is_scanning = 1; handover = 1; node_state = NODE_SLEEP; if (ch_offset % 2 == 0) { //Depending on the cluster synchronization, we should fall in the HDVR_SLOTS hdvr_rx_to = NORM_CLOCK(ref_timer + MOB_AWAKE_OFFSET_1); }else{ //Depending on the cluster synchronization, we should fall in the HDVR_SLOTS hdvr_rx_to = NORM_CLOCK(ref_timer + MOB_AWAKE_OFFSET_2); } off(); ret = rtimer_set(&generic_timer, hdvr_rx_to, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { //PRINTF("ERROR_MOBILE_admission: %d %u\n",r, RTIMER_NOW()); } return 1; } /**end of TIME_DIFF(base_rssi, TH_POWER)*/ #endif atempts++; node_state = NODE_RX_SYNCH; if (free_slots != 0) { idx = (uint8_t) (random_rand() % free_slots); } else { idx = 0; } #if NODE_IS_MOBILE radio_clock = 0; uint8_t rand_offset = 0; if(idx != 0){ rand_offset = (uint8_t) (random_rand() % (2*idx)); }else{ rand_offset = 1; } radio_clock = NORM_CLOCK(ref_timer + ROUTER_DL_TX_TS + occupied_ts * TS + rand_offset * (TS / 2)); /*and offset is added to the*/ synch_rx_to = NORM_CLOCK(ref_timer + AWAKE_PERIOD); //SUPER_FRAME_DURATION; off(); PRINTF("mobile node not admitted...Requesting admission\n"); /**If a node is requesting */ ret = rtimer_set(&generic_timer, radio_clock, 1, (void (*)(struct rtimer *, void *))slot_request, NULL); if (ret) { //PRINTF("err_ send_slot_req:%d free_slots/idx:%d/%d\n", ret, free_slots, idx); } #endif /**NODE_IS_MOBILE*/ #if NODE_IS_ROUTER if (num_neighbors == 0) { //idx = idx % 63; radio_clock = ref_timer + (ROUTER_DL_TX_TS + (random_rand() % 63) * TS); } else { if (num_neighbors == 1) { radio_clock = ref_timer + ROUTER_DL_TX_TS + (ROUTER_UL_TX_TS - idx * TS); } else if (num_neighbors >= 2 && num_neighbors != 7) { radio_clock = ref_timer + ROUTER_DL_TX_TS + (1 + idx % 2) * ROUTER_UL_TX_TS - (idx / 2) * TS; } else if (num_neighbors == 7) { radio_clock = ref_timer + (ROUTER_DL_TX_TS + ROUTER_UL_TX_TS - TS); } } radio_clock = NORM_CLOCK(radio_clock); ret = rtimer_set(&generic_timer, radio_clock, 1, (void (*)(struct rtimer *, void *))slot_request, NULL); if (ret) { //PRINTF("err_ send_slot_req:%d free_slots/idx:%d/%d\n", ret, free_slots, idx); } off(); synch_rx_to = NORM_CLOCK(ref_timer + AWAKE_PERIOD); PRINTF("router node tot admitted...Requesting admission\n"); #endif } else { /**adtmitted == 1*/ /*the node was admitted... calculate some parameters*/ //PRINTF("Admitted....\n"); node_state = NODE_RX_UPLINK; #if NODE_IS_MOBILE /*--INIT OF schedule mobile node transmission------*/ /**The time when to start transmitting upstreams*/ ul_tx_to = NORM_CLOCK(ref_timer + ROUTER_DL_TX_TS + (ts_offset * TS)); /**The time when to finish transmitting upstreams. Note that we also subtract the GUARD_TIME*/ ul_tx_tn = NORM_CLOCK(ul_tx_to + (assign_slots * TS - GUARD_TIME)); if (ch_offset % 2 == 0) { /**Depending on the cluster synchronization, we should fall in the HDVR_SLOTS*/ hdvr_rx_to = NORM_CLOCK(ref_timer + MOB_AWAKE_OFFSET_1); /**If no handover occurs, synchronize the back to the CH at this time*/ synch_rx_to = ref_timer + MOB_AWAKE_OFFSET_1 + (HDVR_TX_TS + ROUTER_DL_TX_TS + 2 * GUARD_TIME); } else { /**Depending on the cluster synchronization, we should fall in the HDVR_SLOTS*/ hdvr_rx_to = NORM_CLOCK(ref_timer + MOB_AWAKE_OFFSET_2); /**If no handover occurs, synchronize the back to the CH at this time*/ synch_rx_to = ref_timer + MOB_AWAKE_OFFSET_2 + (HDVR_TX_TS + ROUTER_DL_TX_TS + ROUTER_UL_TX_TS + 2 * GUARD_TIME); } synch_rx_to = NORM_CLOCK(synch_rx_to); //ref_timer + TS PRINTF("synch_time: %li/%li\n", synch_rx_to, ref_timer); //off(); /*OBS: seting this flag to zero means that no downlink data will be received*/ is_there_data = 0; ret = rtimer_set(&generic_timer, RTIMER_NOW()+1 /*ref_timer + TS*/, 1, (void (*)(struct rtimer *, void *))mobile_power_cycle, NULL); if (ret) { PRINTF("mobile error power_cycle:%d\n", ret); } /*---END OF schedule mobile node transmission-----*/ #endif /*NODE_IS_MOBILE*/ #if NODE_IS_ROUTER /*---INIT OF schedule router node transmission-----*/ if (ch_offset % 2 == 1) { /*we get the time when to start and end transmitting upstream*/ ul_tx_to = NORM_CLOCK(ref_timer + ROUTER_DL_TX_TS + (ts_offset * TS)); ul_tx_tn = NORM_CLOCK(ul_tx_to + assign_slots*TS); /*we schedule when the dl_tx should occur*/ dl_tx_to = NORM_CLOCK(ref_timer + SINK_DL_TX_TS + ROUTER_UL_TX_TS); dl_tx_tn = NORM_CLOCK(dl_tx_to + ROUTER_DL_TX_TS); radio_clock = NORM_CLOCK(ref_timer + TS / 2); radio_off_to = NORM_CLOCK(ref_timer + (ROUTER_DL_TX_TS - TS)); infra_rx_to = dl_tx_tn; infra_rx_tn = NORM_CLOCK(dl_tx_tn + ((MAX_CHILDS / 3 - cluster_size / 3) + slots_offset) * TS); } else { /*--INIT schedule downlink Tx and Rx---*/ dl_tx_to = NORM_CLOCK(ref_timer + SINK_DL_TX_TS); dl_tx_tn = NORM_CLOCK(dl_tx_to + ROUTER_DL_TX_TS); /*we get the time when to start and end transmitting upstream*/ ul_tx_to = NORM_CLOCK(ref_timer + ROUTER_DL_TX_TS + ROUTER_UL_TX_TS + (ts_offset * TS)); ul_tx_tn = NORM_CLOCK(ul_tx_to + assign_slots*TS); ul_tx_sch = NORM_CLOCK(ref_timer + ROUTER_DL_TX_TS + ROUTER_UL_TX_TS); radio_clock = NORM_CLOCK(ref_timer + TS / 2); infra_rx_to = dl_tx_tn; infra_rx_tn = NORM_CLOCK(dl_tx_tn + ((MAX_CHILDS / 3 - cluster_size / 3) + slots_offset) * TS); //here is the nightmare :) radio_off_to = NORM_CLOCK(ref_timer + (ROUTER_DL_TX_TS - TS)); } hdvr_tx_to = ref_timer + (SINK_DL_TX_TS + SINK_UL_RX_TS) + (ch_offset * 2*ONE_MSEC); synch_rx_to = ref_timer + (AWAKE_PERIOD); hdvr_tx_to = NORM_CLOCK(hdvr_tx_to); synch_rx_to = NORM_CLOCK(synch_rx_to); /*OBS: seting this flag to zero means that no downlink data will be received*/ is_there_data = 0; ret = rtimer_set(&generic_timer, NORM_CLOCK(ref_timer + TS), 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error scheduling router power_cycle:%d\n", ret); } /*---END OF schedule router node transmission-----*/ #endif /*---END OF NODE_IS_ROUTER----*/ } /*---END OF ELSE(admitted==0)---*/ } /*---END of if (hdr.type == SINK_BEACON || hdr.type == ROUTER_BEACON)---*/ #endif /*--END OF NODE_IS_MOBILE || NODE_IS_ROUTER--*/ } else { PRINTF("Received packet length not valid\n"); } return 0; } /**---------------------------------------------------------------------------*/ void mobile_set_recv_callback(void (* func)(rimeaddr_t *sd, void* data, uint8_t len)) { inpacket_callback = func; /*we need to pass the data directly to the application layer*/ } /**---------------------------------------------------------------------------*/ #if WITH_UIP6 void mobile_uip_set_recv_func(void (* func)(rimeaddr_t *src, rimeaddr_t *dest, void* data, uint8_t len)){ uip_callback_func = func; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_ROUTER || NODE_IS_MOBILE void mobile_set_data_rate(uint8_t new_rate){ if(data_rate == new_rate || new_rate == 0){ return; //no update needed } if(new_rate < MIN_DATA_RATE){ data_rate = MIN_DATA_RATE; }else{ data_rate = new_rate; } data_rate_update = 1; } #endif /**---------------------------------------------------------------------------*/ #if NODE_IS_MOBILE & RATE_CONTROL void mobile_set_rate_update_func(void (* rfunc)( uint8_t len)) { rate_update_func = rfunc; } #endif /**---------------------------------------------------------------------------*/ static int turn_radio_on() { if (!radio_on) { radio_on = 1; radio_off = 0; return radio->on(); } return 0; } /**---------------------------------------------------------------------------*/ static int turn_radio_off() { if (radio_on) { radio_on = 0; radio_off = 1; return radio->off(); } return 0; } /**---------------------------------------------------------------------------*/ static void input_packet(const struct radio_driver *d) { if(receiver_callback) { receiver_callback(&mobile_driver); } } /**---------------------------------------------------------------------------*/ static void set_receive_function(void (* recv)(const struct mac_driver *)) { receiver_callback = recv; } /*---------------------------------------------------------------------------*/ static unsigned short channel_check_interval(void) { return 0; } /**---------------------------------------------------------------------------*/ const struct mac_driver *mobile_mac_init(const struct radio_driver *radio_dr) { uint8_t ret; data_buffers_init(); /**Initialize the data buffers*/ radio = radio_dr; radio->set_receive_function(input_packet); turn_radio_on(); #if NODE_IS_SINK init_child_list(); node_state = NODE_TX_DOWNLINK; ret = rtimer_set(&generic_timer, RTIMER_NOW() + ROUTER_DL_TX_TS, 1, (void (*)(struct rtimer *, void *))downlink_transmitter, NULL); if (ret) { //PRINTF("error starting periodic beacon at: %u\n", RTIMER_NOW()); } #endif #if NODE_IS_ROUTER node_state = NOTHING; init_child_list(); neigh_adv_list_init(); ret = rtimer_set(&generic_timer, RTIMER_NOW() + ROUTER_DL_TX_TS/2, 1, (void (*)(struct rtimer *, void *))router_power_cycle, NULL); if (ret) { //PRINTF("error starting mobile entry: %u\n", RTIMER_NOW()); } #endif #if NODE_IS_MOBILE /**when starting as mobile node, first scan the medium to locate router *nodes.initialize list of routers in the vicinity*/ node_state = NOTHING; neigh_adv_list_init(); is_scanning = 1; ret = rtimer_set(&generic_timer, RTIMER_NOW() + ROUTER_DL_TX_TS, 1, (void (*)(struct rtimer *, void *))mobile_chead_selection, NULL); if (ret) { PRINTF("error starting mobile entry: %u\n", RTIMER_NOW()); } #endif #if NODE_IS_ROUTER || NODE_IS_MOBILE report_type = 1; ad_t0_lock = 1; /*enable getting admission time t0*/ nc_t0 = RTIMER_NOW(); #endif return &mobile_driver; } /**---------------------------------------------------------------------------*/ const struct mac_driver mobile_driver = { "mobisenseMAC", mobile_mac_init, packet_out, packet_in, set_receive_function, turn_radio_on, turn_radio_off, channel_check_interval, }; /**---------------------------------------------------------------------------*/ ///MAKEFILES MOBILE MAKEFILE CONTIKI_PROJECT = mobile ifndef TARGET TARGET=sky endif all: $(CONTIKI_PROJECT) DEFINES=WITH_MOBILEMAC NODE_IS_MOBILE RATE_CONTROL #TDMA_OPTIMIZED CONTIKI = ../../.. include $(CONTIKI)/Makefile.include /**---------------------------------------------------------------------------*/ ///MAKEFILES SINK MAKEFILE CONTIKI_PROJECT = sink ifndef TARGET TARGET=sky endif all: $(CONTIKI_PROJECT) DEFINES=WITH_MOBILEMAC NODE_IS_SINK SINK_SERIAL #TDMA_OPTIMIZED CONTIKI = ../../.. include $(CONTIKI)/Makefile.include /**---------------------------------------------------------------------------*/ ///MAKEFILES ROUTER MAKEFILE CONTIKI_PROJECT = router ifndef TARGET TARGET=sky endif all: $(CONTIKI_PROJECT) DEFINES=WITH_MOBILEMAC NODE_IS_ROUTER #WITH_NULLMAC #TDMA_OPTIMIZED CONTIKI = ../../.. include $(CONTIKI)/Makefile.include /**---------------------------------------------------------------------------*/