45 #include "sys/clock.h"
47 #include "lib/random.h"
61 #define PRINTF(...) printf(__VA_ARGS__)
69 #ifdef CSMA_CONF_MIN_BE
70 #define CSMA_MIN_BE CSMA_CONF_MIN_BE
76 #ifdef CSMA_CONF_MAX_BE
77 #define CSMA_MAX_BE CSMA_CONF_MAX_BE
83 #ifdef CSMA_CONF_MAX_BACKOFF
84 #define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
86 #define CSMA_MAX_BACKOFF 5
90 #ifdef CSMA_CONF_MAX_FRAME_RETRIES
91 #define CSMA_MAX_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
93 #define CSMA_MAX_MAX_FRAME_RETRIES 7
97 struct qbuf_metadata {
100 uint8_t max_transmissions;
104 struct neighbor_queue {
105 struct neighbor_queue *next;
107 struct ctimer transmit_timer;
108 uint8_t transmissions;
114 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
115 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
117 #define CSMA_MAX_NEIGHBOR_QUEUES 2
121 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
122 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
124 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
127 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM
128 MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
129 MEMB(packet_memb,
struct rdc_buf_list, MAX_QUEUED_PACKETS);
130 MEMB(metadata_memb,
struct qbuf_metadata, MAX_QUEUED_PACKETS);
133 static void packet_sent(
void *ptr,
int status,
int num_transmissions);
134 static void transmit_packet_list(
void *ptr);
136 static struct neighbor_queue *
137 neighbor_queue_from_addr(
const linkaddr_t *
addr)
139 struct neighbor_queue *n =
list_head(neighbor_list);
155 time = NETSTACK_RDC.channel_check_interval();
167 transmit_packet_list(
void *ptr)
169 struct neighbor_queue *n = ptr;
171 struct rdc_buf_list *q =
list_head(n->queued_packet_list);
173 PRINTF(
"csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
182 schedule_transmission(
struct neighbor_queue *n)
185 int backoff_exponent;
187 backoff_exponent = MIN(n->collisions, CSMA_MAX_BE);
190 delay = ((1 << backoff_exponent) - 1) * backoff_period();
196 PRINTF(
"csma: scheduling transmission in %u ticks, NB=%u, BE=%u\n",
197 (
unsigned)delay, n->collisions, backoff_exponent);
198 ctimer_set(&n->transmit_timer, delay, transmit_packet_list, n);
202 free_packet(
struct neighbor_queue *n,
struct rdc_buf_list *p,
int status)
208 queuebuf_free(p->buf);
211 PRINTF(
"csma: free_queued_packet, queue length %d, free packets %d\n",
212 list_length(n->queued_packet_list), memb_numfree(&packet_memb));
215 n->transmissions = 0;
216 n->collisions = CSMA_MIN_BE;
218 schedule_transmission(n);
229 tx_done(
int status,
struct rdc_buf_list *q,
struct neighbor_queue *n)
232 struct qbuf_metadata *metadata;
235 metadata = (
struct qbuf_metadata *)q->ptr;
236 sent = metadata->sent;
237 cptr = metadata->cptr;
241 PRINTF(
"csma: rexmit ok %d\n", n->transmissions);
245 PRINTF(
"csma: drop with status %d after %d transmissions, %d collisions\n",
246 status, n->transmissions, n->collisions);
249 PRINTF(
"csma: rexmit failed %d: %d\n", n->transmissions, status);
253 free_packet(n, q, status);
254 mac_call_sent_callback(sent, cptr, status, n->transmissions);
258 rexmit(
struct rdc_buf_list *q,
struct neighbor_queue *n)
260 schedule_transmission(n);
263 queuebuf_update_attr_from_packetbuf(q->buf);
267 collision(
struct rdc_buf_list *q,
struct neighbor_queue *n,
268 int num_transmissions)
270 struct qbuf_metadata *metadata;
272 metadata = (
struct qbuf_metadata *)q->ptr;
274 n->collisions += num_transmissions;
276 if(n->collisions > CSMA_MAX_BACKOFF) {
277 n->collisions = CSMA_MIN_BE;
282 if(n->transmissions >= metadata->max_transmissions) {
285 PRINTF(
"csma: rexmit collision %d\n", n->transmissions);
291 noack(
struct rdc_buf_list *q,
struct neighbor_queue *n,
int num_transmissions)
293 struct qbuf_metadata *metadata;
295 metadata = (
struct qbuf_metadata *)q->ptr;
297 n->collisions = CSMA_MIN_BE;
298 n->transmissions += num_transmissions;
300 if(n->transmissions >= metadata->max_transmissions) {
303 PRINTF(
"csma: rexmit noack %d\n", n->transmissions);
309 tx_ok(
struct rdc_buf_list *q,
struct neighbor_queue *n,
int num_transmissions)
311 n->collisions = CSMA_MIN_BE;
312 n->transmissions += num_transmissions;
317 packet_sent(
void *ptr,
int status,
int num_transmissions)
319 struct neighbor_queue *n;
320 struct rdc_buf_list *q;
328 for(q =
list_head(n->queued_packet_list);
330 if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
331 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
337 PRINTF(
"csma: seqno %d not found\n",
338 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
340 }
else if(q->ptr ==
NULL) {
341 PRINTF(
"csma: no metadata\n");
347 tx_ok(q, n, num_transmissions);
350 noack(q, n, num_transmissions);
353 collision(q, n, num_transmissions);
358 tx_done(status, q, n);
364 send_packet(mac_callback_t sent,
void *ptr)
366 struct rdc_buf_list *q;
367 struct neighbor_queue *n;
368 static uint8_t initialized = 0;
369 static uint16_t seqno;
370 const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
383 packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
386 n = neighbor_queue_from_addr(addr);
393 n->transmissions = 0;
394 n->collisions = CSMA_MIN_BE;
404 if(
list_length(n->queued_packet_list) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
409 q->buf = queuebuf_new_from_packetbuf();
411 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
413 if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
415 metadata->max_transmissions = CSMA_MAX_MAX_FRAME_RETRIES + 1;
417 metadata->max_transmissions =
418 packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
420 metadata->sent = sent;
421 metadata->cptr = ptr;
422 #if PACKETBUF_WITH_PACKET_TYPE
423 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
424 PACKETBUF_ATTR_PACKET_TYPE_ACK) {
432 PRINTF(
"csma: send_packet, queue length %d, free packets %d\n",
433 list_length(n->queued_packet_list), memb_numfree(&packet_memb));
435 if(
list_head(n->queued_packet_list) == q) {
436 schedule_transmission(n);
441 PRINTF(
"csma: could not allocate queuebuf, dropping packet\n");
444 PRINTF(
"csma: could not allocate queuebuf, dropping packet\n");
452 PRINTF(
"csma: Neighbor queue full\n");
454 PRINTF(
"csma: could not allocate packet, dropping packet\n");
456 PRINTF(
"csma: could not allocate neighbor, dropping packet\n");
458 mac_call_sent_callback(sent, ptr,
MAC_TX_ERR, 1);
464 NETSTACK_LLSEC.input();
470 return NETSTACK_RDC.on();
474 off(
int keep_radio_on)
476 return NETSTACK_RDC.off(keep_radio_on);
479 static unsigned short
480 channel_check_interval(
void)
482 if(NETSTACK_RDC.channel_check_interval) {
483 return NETSTACK_RDC.channel_check_interval();
void list_remove(list_t list, void *item)
Remove a specific element from a list.
The MAC layer deferred the transmission for a later time.
The MAC layer did not get an acknowledgement for the packet.
#define LIST(name)
Declare a linked list.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
#define MEMB(name, structure, num)
Declare a memory block.
void * list_item_next(void *item)
Get the next item following this item.
Header file for the Rime buffer (packetbuf) management
int(* off)(int keep_radio_on)
Turn the MAC layer off.
The MAC layer transmission could not be performed because of a fatal error.
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
The MAC layer transmission could not be performed because of an error.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
void * list_head(list_t list)
Get a pointer to the first element of a list.
The MAC layer transmission was OK.
Header file for the callback timer
#define NULL
The null pointer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
The structure of a MAC protocol driver in Contiki.
void list_add(list_t list, void *item)
Add an item at the end of a list.
#define CLOCK_SECOND
A second, measured in system clock time.
Linked list manipulation routines.
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
void(* init)(void)
Initialize the MAC driver.
Memory block allocation routines.
Header file for the Rime queue buffer management
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
int(* on)(void)
Turn the MAC layer on.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
int list_length(list_t list)
Get the length of a list.
A MAC stack protocol that performs retransmissions when the underlying MAC layer has problems...
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Include file for the Contiki low-layer network stack (NETSTACK)
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
void list_push(list_t list, void *item)
Add an item to the start of the list.