/**---------------------------------------------------------------
 *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
/**---------------------------------------------------------------------------*/