/*---------------------------------------------------------------------------*/ static void free_packet(struct neighbor_queue *n, struct rdc_buf_list *p) { if(p != NULL) { /* Remove packet from list and deallocate */ list_remove(n->queued_packet_list, p); queuebuf_free(p->buf); memb_free(&metadata_memb, p->ptr); memb_free(&packet_memb, p); PRINTF("csma: free_queued_packet, queue length %d\n", list_length(n->queued_packet_list)); if(list_head(n->queued_packet_list) != NULL) { /* There is a next packet. We reset current tx information */ n->transmissions = 0; n->collisions = 0; n->deferrals = 0; /* Set a timer for next transmissions */ ctimer_set(&n->transmit_timer, default_timebase(), transmit_packet_list, n); } else { /* This was the last packet in the queue, we free the neighbor */ ctimer_stop(&n->transmit_timer); list_remove(neighbor_list, n); memb_free(&neighbor_memb, n); } } }
/*---------------------------------------------------------------------------*/ static void free_packet(struct neighbor_queue *n, struct rdc_buf_list *p) { if(p != NULL) { //ADILA EDIT 09/02/14 //cc2420_set_channel(list_length(n->queued_packet_list) + 10); //printf("%d BEFORE FREE Q %d\n", cc2420_get_channel(), list_length(n->queued_packet_list)); //------------------- /* Remove packet from list and deallocate */ list_remove(n->queued_packet_list, p); queuebuf_free(p->buf); memb_free(&metadata_memb, p->ptr); memb_free(&packet_memb, p); //ADILA EDIT 09/02/14 if((list_length(n->queued_packet_list)) == 0) { cc2420_set_channel(26); //printf("%d empty Q %d\n", cc2420_get_channel(), list_length(n->queued_packet_list)); } //------------------- PRINTF("csma: free_queued_packet, queue length %d\n", list_length(n->queued_packet_list)); if(list_head(n->queued_packet_list) != NULL) { /* There is a next packet. We reset current tx information */ n->transmissions = 0; n->collisions = 0; n->deferrals = 0; /* Set a timer for next transmissions */ ctimer_set(&n->transmit_timer, default_timebase(), transmit_packet_list, n); } else { /* This was the last packet in the queue, we free the neighbor */ ctimer_stop(&n->transmit_timer); list_remove(neighbor_list, n); memb_free(&neighbor_memb, n); } } }
/*---------------------------------------------------------------------------*/ static void free_queued_packet(void) { struct queued_packet *q; // printf("q %d\n", list_length(queued_packet_list)); q = list_head(queued_packet_list); if(q != NULL) { queuebuf_free(q->buf); list_remove(queued_packet_list, q); memb_free(&packet_memb, q); PRINTF("csma: free_queued_packet, queue length %d\n", list_length(queued_packet_list)); if(list_length(queued_packet_list) > 0) { ctimer_set(&transmit_timer, default_timebase(), transmit_queued_packet, NULL); } } }
/*---------------------------------------------------------------------------*/ static void packet_sent(void *ptr, int status, int num_transmissions) { struct neighbor_queue *n; struct rdc_buf_list *q; struct qbuf_metadata *metadata; clock_time_t time = 0; mac_callback_t sent; void *cptr; int num_tx; int backoff_exponent; int backoff_transmissions; n = ptr; if(n == NULL) { return; } switch(status) { case MAC_TX_OK: case MAC_TX_NOACK: n->transmissions++; break; case MAC_TX_COLLISION: n->collisions++; break; case MAC_TX_DEFERRED: n->deferrals++; break; } for(q = list_head(n->queued_packet_list); q != NULL; q = list_item_next(q)) { if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) == packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) { break; } } if(q != NULL) { metadata = (struct qbuf_metadata *)q->ptr; if(metadata != NULL) { sent = metadata->sent; cptr = metadata->cptr; num_tx = n->transmissions; if(status == MAC_TX_COLLISION || status == MAC_TX_NOACK) { /* If the transmission was not performed because of a collision or noack, we must retransmit the packet. */ switch(status) { case MAC_TX_COLLISION: PRINTF("csma: rexmit collision %d\n", n->transmissions); break; case MAC_TX_NOACK: PRINTF("csma: rexmit noack %d\n", n->transmissions); break; default: PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions); } /* The retransmission time must be proportional to the channel check interval of the underlying radio duty cycling layer. */ time = default_timebase(); /* The retransmission time uses a truncated exponential backoff * so that the interval between the transmissions increase with * each retransmit. */ backoff_exponent = num_tx; /* Truncate the exponent if needed. */ if(backoff_exponent > CSMA_MAX_BACKOFF_EXPONENT) { backoff_exponent = CSMA_MAX_BACKOFF_EXPONENT; } /* Proceed to exponentiation. */ backoff_transmissions = 1 << backoff_exponent; /* Pick a time for next transmission, within the interval: * [time, time + 2^backoff_exponent * time[ */ time = time + (random_rand() % (backoff_transmissions * time)); if(n->transmissions < metadata->max_transmissions) { PRINTF("csma: retransmitting with time %lu %p\n", time, q); ctimer_set(&n->transmit_timer, time, transmit_packet_list, n); /* This is needed to correctly attribute energy that we spent transmitting this packet. */ queuebuf_update_attr_from_packetbuf(q->buf); } else { PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n", status, n->transmissions, n->collisions); free_packet(n, q); mac_call_sent_callback(sent, cptr, status, num_tx); } } else { if(status == MAC_TX_OK) { PRINTF("csma: rexmit ok %d\n", n->transmissions); } else { PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status); } free_packet(n, q); mac_call_sent_callback(sent, cptr, status, num_tx); } } } }
/*---------------------------------------------------------------------------*/ static void packet_sent(void *ptr, int status, int num_transmissions) { struct neighbor_queue *n; struct rdc_buf_list *q; struct qbuf_metadata *metadata; clock_time_t time = 0; mac_callback_t sent; void *cptr; int num_tx; int backoff_transmissions; n = ptr; if(n == NULL) { return; } switch(status) { case MAC_TX_OK: case MAC_TX_NOACK: n->transmissions++; break; case MAC_TX_COLLISION: n->collisions++; break; case MAC_TX_DEFERRED: n->deferrals++; break; } for(q = list_head(n->queued_packet_list); q != NULL; q = list_item_next(q)) { if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) == packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) { break; } } if(q != NULL) { metadata = (struct qbuf_metadata *)q->ptr; if(metadata != NULL) { sent = metadata->sent; cptr = metadata->cptr; #if CSMA_ADVANCED num_tx = n->transmissions + n->collisions/8; #else num_tx = n->transmissions; #endif if(status == MAC_TX_COLLISION || status == MAC_TX_NOACK) { /* If the transmission was not performed because of a collision or noack, we must retransmit the packet. */ switch(status) { case MAC_TX_COLLISION: PRINTF("csma: rexmit collision %d\n", n->transmissions); break; case MAC_TX_NOACK: PRINTF("csma: rexmit noack %d\n", n->transmissions); break; case MAC_TX_DEFERRED: PRINTF("phase deferred\n"); break; default: PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions); } #if CSMA_ADVANCED int i; /* The retransmission time must be proportional to the channel check interval of the underlying radio duty cycling layer. */ time = default_timebase() / 3; /* The retransmission time uses a linear backoff so that the interval between the transmissions increase with each retransmit. */ backoff_transmissions = 1; for(i=0; i<num_tx-1; i++) { backoff_transmissions *= 3; } /* Clamp the number of backoffs so that we don't get a too long timeout here, since that will delay all packets in the queue. */ if(backoff_transmissions > 3 * 3) { backoff_transmissions = 3 * 3; } time = default_timebase() + (random_rand() % (backoff_transmissions * time)); if(num_tx < metadata->max_transmissions) { #else /* The retransmission time must be proportional to the channel check interval of the underlying radio duty cycling layer. */ time = default_timebase(); /* The retransmission time uses a linear backoff so that the interval between the transmissions increase with each retransmit. */ backoff_transmissions = n->transmissions + 1; /* Clamp the number of backoffs so that we don't get a too long timeout here, since that will delay all packets in the queue. */ if(backoff_transmissions > 3) { backoff_transmissions = 3; } time = time + (random_rand() % (backoff_transmissions * time)); if(n->transmissions < metadata->max_transmissions) { #endif PRINTF("csma: retransmitting with time %lu %p\n", time, q); ctimer_set(&n->transmit_timer, time, transmit_packet_list, n); /* This is needed to correctly attribute energy that we spent transmitting this packet. */ queuebuf_update_attr_from_packetbuf(q->buf); } else { if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { LOG_FROM_PACKETBUF("csma: drop with status %d after %d transmissions, %d collisions", status, n->transmissions, n->collisions); } free_packet(n, q); mac_call_sent_callback(sent, cptr, status, num_tx); } } else { if(status == MAC_TX_OK) { if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) { LOG_FROM_PACKETBUF("csma: rexmit ok after %d transmissions, %d collisions", n->transmissions, n->collisions); } } else { //LOG_FROM_PACKETBUF("csma: rexmit failed %d: %d\n", n->transmissions, status); } free_packet(n, q); mac_call_sent_callback(sent, cptr, status, num_tx); } } } } /*---------------------------------------------------------------------------*/ static void send_packet(mac_callback_t sent, void *ptr) { struct rdc_buf_list *q; struct neighbor_queue *n; static uint16_t seqno; const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(seqno == 0) { /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity in framer-802154.c. */ seqno++; } packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++); /* Look for the neighbor entry */ n = neighbor_queue_from_addr(addr); if(n == NULL) { /* Allocate a new neighbor entry */ n = memb_alloc(&neighbor_memb); if(n != NULL) { /* Init neighbor entry */ rimeaddr_copy(&n->addr, addr); n->transmissions = 0; n->collisions = 0; n->deferrals = 0; /* Init packet list for this neighbor */ LIST_STRUCT_INIT(n, queued_packet_list); /* Add neighbor to the list */ list_add(neighbor_list, n); } } if(n != NULL) { /* Add packet to the neighbor's queue */ q = memb_alloc(&packet_memb); if(q != NULL) { q->ptr = memb_alloc(&metadata_memb); if(q->ptr != NULL) { q->buf = queuebuf_new_from_packetbuf(); if(q->buf != NULL) { struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; /* Neighbor and packet successfully allocated */ if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) { /* Use default configuration for max transmissions */ metadata->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS; } else { metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); } metadata->sent = sent; metadata->cptr = ptr; if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) { list_push(n->queued_packet_list, q); } else { list_add(n->queued_packet_list, q); } /* If q is the first packet in the neighbor's queue, send asap */ if(list_head(n->queued_packet_list) == q) { ctimer_set(&n->transmit_timer, 0, transmit_packet_list, n); } return; } memb_free(&metadata_memb, q->ptr); PRINTF("csma: could not allocate queuebuf, dropping packet\n"); } memb_free(&packet_memb, q); PRINTF("csma: could not allocate queuebuf, dropping packet\n"); } /* The packet allocation failed. Remove and free neighbor entry if empty. */ if(list_length(n->queued_packet_list) == 0) { list_remove(neighbor_list, n); memb_free(&neighbor_memb, n); } PRINTF("csma: could not allocate packet, dropping packet\n"); } else { PRINTF("csma: could not allocate neighbor, dropping packet\n"); } mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1); } /*---------------------------------------------------------------------------*/ static void input_packet(void) { NETSTACK_NETWORK.input(); } /*---------------------------------------------------------------------------*/ static int on(void) { return NETSTACK_RDC.on(); } /*---------------------------------------------------------------------------*/ static int off(int keep_radio_on) { return NETSTACK_RDC.off(keep_radio_on); } /*---------------------------------------------------------------------------*/ static unsigned short channel_check_interval(void) { if(NETSTACK_RDC.channel_check_interval) { return NETSTACK_RDC.channel_check_interval(); } return 0; } /*---------------------------------------------------------------------------*/ static void init(void) { memb_init(&packet_memb); memb_init(&metadata_memb); memb_init(&neighbor_memb); }
/*---------------------------------------------------------------------------*/ static void packet_sent(void *ptr, int status, int num_transmissions) { struct neighbor_queue *n = ptr; struct rdc_buf_list *q = list_head(n->queued_packet_list); struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; clock_time_t time = 0; mac_callback_t sent; void *cptr; int num_tx; int backoff_transmissions; switch(status) { case MAC_TX_OK: case MAC_TX_NOACK: n->transmissions++; break; case MAC_TX_COLLISION: n->collisions++; break; case MAC_TX_DEFERRED: n->deferrals++; break; } sent = metadata->sent; cptr = metadata->cptr; num_tx = n->transmissions; if(status == MAC_TX_COLLISION || status == MAC_TX_NOACK) { /* If the transmission was not performed because of a collision or noack, we must retransmit the packet. */ switch(status) { case MAC_TX_COLLISION: PRINTF("csma: rexmit collision %d\n", n->transmissions); break; case MAC_TX_NOACK: PRINTF("csma: rexmit noack %d\n", n->transmissions); break; default: PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions); } /* The retransmission time must be proportional to the channel check interval of the underlying radio duty cycling layer. */ time = default_timebase(); /* The retransmission time uses a linear backoff so that the interval between the transmissions increase with each retransmit. */ backoff_transmissions = n->transmissions + 1; /* Clamp the number of backoffs so that we don't get a too long timeout here, since that will delay all packets in the queue. */ if(backoff_transmissions > 3) { backoff_transmissions = 3; } time = time + (random_rand() % (backoff_transmissions * time)); if(n->transmissions < metadata->max_transmissions) { PRINTF("csma: retransmitting with time %lu %p\n", time, q); ctimer_set(&n->transmit_timer, time, transmit_packet_list, n); /* This is needed to correctly attribute energy that we spent transmitting this packet. */ queuebuf_update_attr_from_packetbuf(q->buf); } else { PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n", status, n->transmissions, n->collisions); free_first_packet(n); mac_call_sent_callback(sent, cptr, status, num_tx); } } else { if(status == MAC_TX_OK) { PRINTF("csma: rexmit ok %d\n", n->transmissions); } else { PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status); } free_first_packet(n); mac_call_sent_callback(sent, cptr, status, num_tx); } }