45 #include "sys/clock.h"
47 #include "lib/random.h"
61 #define PRINTF(...) printf(__VA_ARGS__)
66 #ifndef CSMA_MAX_BACKOFF_EXPONENT
67 #ifdef CSMA_CONF_MAX_BACKOFF_EXPONENT
68 #define CSMA_MAX_BACKOFF_EXPONENT CSMA_CONF_MAX_BACKOFF_EXPONENT
70 #define CSMA_MAX_BACKOFF_EXPONENT 3
74 #ifndef CSMA_MAX_MAC_TRANSMISSIONS
75 #ifdef CSMA_CONF_MAX_MAC_TRANSMISSIONS
76 #define CSMA_MAX_MAC_TRANSMISSIONS CSMA_CONF_MAX_MAC_TRANSMISSIONS
78 #define CSMA_MAX_MAC_TRANSMISSIONS 3
82 #if CSMA_MAX_MAC_TRANSMISSIONS < 1
83 #error CSMA_CONF_MAX_MAC_TRANSMISSIONS must be at least 1.
84 #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
88 struct qbuf_metadata {
91 uint8_t max_transmissions;
95 struct neighbor_queue {
96 struct neighbor_queue *next;
98 struct ctimer transmit_timer;
99 uint8_t transmissions;
100 uint8_t collisions, deferrals;
105 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
106 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
108 #define CSMA_MAX_NEIGHBOR_QUEUES 2
112 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
113 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
115 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
118 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM
119 MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
120 MEMB(packet_memb,
struct rdc_buf_list, MAX_QUEUED_PACKETS);
121 MEMB(metadata_memb,
struct qbuf_metadata, MAX_QUEUED_PACKETS);
124 static void packet_sent(
void *ptr,
int status,
int num_transmissions);
125 static void transmit_packet_list(
void *ptr);
128 static struct neighbor_queue *
129 neighbor_queue_from_addr(
const linkaddr_t *addr)
131 struct neighbor_queue *n =
list_head(neighbor_list);
142 default_timebase(
void)
147 time = NETSTACK_RDC.channel_check_interval();
159 transmit_packet_list(
void *ptr)
161 struct neighbor_queue *n = ptr;
163 struct rdc_buf_list *q =
list_head(n->queued_packet_list);
165 PRINTF(
"csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
168 NETSTACK_RDC.send_list(packet_sent, n, q);
174 free_packet(
struct neighbor_queue *n,
struct rdc_buf_list *p)
180 queuebuf_free(p->buf);
183 PRINTF(
"csma: free_queued_packet, queue length %d, free packets %d\n",
184 list_length(n->queued_packet_list), memb_numfree(&packet_memb));
187 n->transmissions = 0;
191 ctimer_set(&n->transmit_timer, default_timebase(),
192 transmit_packet_list, n);
203 packet_sent(
void *ptr,
int status,
int num_transmissions)
205 struct neighbor_queue *n;
206 struct rdc_buf_list *q;
207 struct qbuf_metadata *metadata;
208 clock_time_t time = 0;
212 int backoff_exponent;
213 int backoff_transmissions;
222 n->transmissions += num_transmissions;
225 n->collisions += num_transmissions;
228 n->deferrals += num_transmissions;
233 for(q =
list_head(n->queued_packet_list);
235 if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
236 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
242 metadata = (
struct qbuf_metadata *)q->ptr;
244 if(metadata !=
NULL) {
245 sent = metadata->sent;
246 cptr = metadata->cptr;
247 num_tx = n->transmissions;
256 PRINTF(
"csma: rexmit collision %d\n", n->transmissions);
259 PRINTF(
"csma: rexmit noack %d\n", n->transmissions);
262 PRINTF(
"csma: rexmit err %d, %d\n", status, n->transmissions);
267 time = default_timebase();
272 backoff_exponent = num_tx;
275 if(backoff_exponent > CSMA_MAX_BACKOFF_EXPONENT) {
276 backoff_exponent = CSMA_MAX_BACKOFF_EXPONENT;
280 backoff_transmissions = 1 << backoff_exponent;
284 time = time + (
random_rand() % (backoff_transmissions * time));
286 if(n->transmissions < metadata->max_transmissions) {
287 PRINTF(
"csma: retransmitting with time %lu %p\n", time, q);
289 transmit_packet_list, n);
292 queuebuf_update_attr_from_packetbuf(q->buf);
294 PRINTF(
"csma: drop with status %d after %d transmissions, %d collisions\n",
295 status, n->transmissions, n->collisions);
297 mac_call_sent_callback(sent, cptr, status, num_tx);
301 PRINTF(
"csma: rexmit ok %d\n", n->transmissions);
303 PRINTF(
"csma: rexmit failed %d: %d\n", n->transmissions, status);
306 mac_call_sent_callback(sent, cptr, status, num_tx);
309 PRINTF(
"csma: no metadata\n");
312 PRINTF(
"csma: seqno %d not found\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
317 send_packet(mac_callback_t sent,
void *ptr)
319 struct rdc_buf_list *q;
320 struct neighbor_queue *n;
321 static uint8_t initialized = 0;
322 static uint16_t seqno;
323 const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
336 packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
339 n = neighbor_queue_from_addr(addr);
346 n->transmissions = 0;
358 if(
list_length(n->queued_packet_list) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
363 q->buf = queuebuf_new_from_packetbuf();
365 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
367 if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
369 metadata->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
371 metadata->max_transmissions =
372 packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
374 metadata->sent = sent;
375 metadata->cptr = ptr;
377 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
378 PACKETBUF_ATTR_PACKET_TYPE_ACK) {
384 PRINTF(
"csma: send_packet, queue length %d, free packets %d\n",
385 list_length(n->queued_packet_list), memb_numfree(&packet_memb));
387 if(
list_head(n->queued_packet_list) == q) {
388 ctimer_set(&n->transmit_timer, 0, transmit_packet_list, n);
393 PRINTF(
"csma: could not allocate queuebuf, dropping packet\n");
396 PRINTF(
"csma: could not allocate queuebuf, dropping packet\n");
404 PRINTF(
"csma: Neighbor queue full\n");
406 PRINTF(
"csma: could not allocate packet, dropping packet\n");
408 PRINTF(
"csma: could not allocate neighbor, dropping packet\n");
410 mac_call_sent_callback(sent, ptr,
MAC_TX_ERR, 1);
416 NETSTACK_LLSEC.input();
422 return NETSTACK_RDC.on();
426 off(
int keep_radio_on)
428 return NETSTACK_RDC.off(keep_radio_on);
431 static unsigned short
432 channel_check_interval(
void)
434 if(NETSTACK_RDC.channel_check_interval) {
435 return NETSTACK_RDC.channel_check_interval();
Linked list manipulation routines.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
void list_push(list_t list, void *item)
Add an item to the start of the list.
The MAC layer deferred the transmission for a later time.
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
void * list_item_next(void *item)
Get the next item following this item.
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Header file for the Rime buffer (packetbuf) management
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
#define NULL
The null pointer.
int(* off)(int keep_radio_on)
Turn the MAC layer off.
The MAC layer transmission could not be performed because of a fatal error.
A MAC stack protocol that performs retransmissions when the underlying MAC layer has problems...
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
int list_length(list_t list)
Get the length of a list.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
int(* on)(void)
Turn the MAC layer on.
void * list_head(list_t list)
Get a pointer to the first element of a list.
#define MEMB(name, structure, num)
Declare a memory block.
Header file for the Rime queue buffer management
void list_add(list_t list, void *item)
Add an item at the end of a list.
#define LIST(name)
Declare a linked list.
void(* init)(void)
Initialize the MAC driver.
Header file for the callback timer
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
The MAC layer transmission was OK.
The structure of a MAC protocol driver in Contiki.
The MAC layer transmission could not be performed because of an error.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
The MAC layer did not get an acknowledgement for the packet.
Memory block allocation routines.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
unsigned short random_rand(void)
Generate the next state and return the upper part of it.
Include file for the Contiki low-layer network stack (NETSTACK)
#define CLOCK_SECOND
A second, measured in system clock time.