45 #include "dev/watchdog.h" 47 #include "sys/clock.h" 48 #include "lib/random.h" 55 #define LOG_MODULE "CSMA" 56 #define LOG_LEVEL LOG_LEVEL_MAC 61 #ifdef CSMA_CONF_MIN_BE 62 #define CSMA_MIN_BE CSMA_CONF_MIN_BE 68 #ifdef CSMA_CONF_MAX_BE 69 #define CSMA_MAX_BE CSMA_CONF_MAX_BE 75 #ifdef CSMA_CONF_MAX_BACKOFF 76 #define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF 78 #define CSMA_MAX_BACKOFF 5 82 #ifdef CSMA_CONF_MAX_FRAME_RETRIES 83 #define CSMA_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES 85 #define CSMA_MAX_FRAME_RETRIES 7 89 struct qbuf_metadata {
92 uint8_t max_transmissions;
96 struct neighbor_queue {
97 struct neighbor_queue *next;
99 struct ctimer transmit_timer;
100 uint8_t transmissions;
106 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES 107 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES 109 #define CSMA_MAX_NEIGHBOR_QUEUES 2 113 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR 114 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR 116 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS 119 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM 122 struct packet_queue {
123 struct packet_queue *next;
124 struct queuebuf *buf;
128 MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
129 MEMB(packet_memb,
struct packet_queue, 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_from_queue(
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);
152 #if CONTIKI_TARGET_COOJA 164 send_one_packet(
void *ptr)
167 int last_sent_ok = 0;
170 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
172 if(NETSTACK_FRAMER.create() < 0) {
174 LOG_ERR(
"failed to create packet\n");
175 ret = MAC_TX_ERR_FATAL;
185 if(NETSTACK_RADIO.receiving_packet() ||
186 (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
205 if(NETSTACK_RADIO.receiving_packet() ||
206 NETSTACK_RADIO.pending_packet() ||
207 NETSTACK_RADIO.channel_clear() == 0) {
209 uint8_t ackbuf[CSMA_ACK_LEN];
214 if(NETSTACK_RADIO.pending_packet()) {
215 len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
216 if(len == CSMA_ACK_LEN && ackbuf[2] == dsn) {
227 case RADIO_TX_COLLISION:
245 transmit_from_queue(
void *ptr)
247 struct neighbor_queue *n = ptr;
249 struct packet_queue *q =
list_head(n->packet_queue);
251 LOG_INFO(
"preparing packet for ");
252 LOG_INFO_LLADDR(&n->addr);
253 LOG_INFO_(
", seqno %u, tx %u, queue %d\n",
254 queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO),
257 queuebuf_to_packetbuf(q->buf);
264 schedule_transmission(
struct neighbor_queue *n)
267 int backoff_exponent;
269 backoff_exponent = MIN(n->collisions + CSMA_MIN_BE, CSMA_MAX_BE);
272 delay = ((1 << backoff_exponent) - 1) * backoff_period();
278 LOG_DBG(
"scheduling transmission in %u ticks, NB=%u, BE=%u\n",
279 (
unsigned)delay, n->collisions, backoff_exponent);
280 ctimer_set(&n->transmit_timer, delay, transmit_from_queue, n);
284 free_packet(
struct neighbor_queue *n,
struct packet_queue *p,
int status)
290 queuebuf_free(p->buf);
293 LOG_DBG(
"free_queued_packet, queue length %d, free packets %d\n",
294 list_length(n->packet_queue), memb_numfree(&packet_memb));
297 n->transmissions = 0;
300 schedule_transmission(n);
311 tx_done(
int status,
struct packet_queue *q,
struct neighbor_queue *n)
314 struct qbuf_metadata *metadata;
318 metadata = (
struct qbuf_metadata *)q->ptr;
319 sent = metadata->sent;
320 cptr = metadata->cptr;
321 ntx = n->transmissions;
323 LOG_INFO(
"packet sent to ");
324 LOG_INFO_LLADDR(&n->addr);
325 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
326 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
327 status, n->transmissions, n->collisions);
329 free_packet(n, q, status);
330 mac_call_sent_callback(sent, cptr, status, ntx);
334 rexmit(
struct packet_queue *q,
struct neighbor_queue *n)
336 schedule_transmission(n);
339 queuebuf_update_attr_from_packetbuf(q->buf);
343 collision(
struct packet_queue *q,
struct neighbor_queue *n,
344 int num_transmissions)
346 struct qbuf_metadata *metadata;
348 metadata = (
struct qbuf_metadata *)q->ptr;
350 n->collisions += num_transmissions;
352 if(n->collisions > CSMA_MAX_BACKOFF) {
358 if(n->transmissions >= metadata->max_transmissions) {
366 noack(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
368 struct qbuf_metadata *metadata;
370 metadata = (
struct qbuf_metadata *)q->ptr;
373 n->transmissions += num_transmissions;
375 if(n->transmissions >= metadata->max_transmissions) {
383 tx_ok(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
386 n->transmissions += num_transmissions;
391 packet_sent(
void *ptr,
int status,
int num_transmissions)
393 struct neighbor_queue *n;
394 struct packet_queue *q;
404 if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
405 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
411 LOG_WARN(
"packet sent: seqno %u not found\n",
412 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
414 }
else if(q->ptr == NULL) {
415 LOG_WARN(
"packet sent: no metadata\n");
420 LOG_INFO_LLADDR(&n->addr);
421 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
422 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
423 status, n->transmissions, n->collisions);
427 tx_ok(q, n, num_transmissions);
430 noack(q, n, num_transmissions);
433 collision(q, n, num_transmissions);
438 tx_done(status, q, n);
444 csma_output_packet(mac_callback_t sent,
void *ptr)
446 struct packet_queue *q;
447 struct neighbor_queue *n;
448 static uint8_t initialized = 0;
449 static uint8_t seqno;
450 const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
463 packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
464 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
467 n = neighbor_queue_from_addr(addr);
474 n->transmissions = 0;
485 if(
list_length(n->packet_queue) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
490 q->buf = queuebuf_new_from_packetbuf();
492 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
494 metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
495 if(metadata->max_transmissions == 0) {
497 metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1;
499 metadata->sent = sent;
500 metadata->cptr = ptr;
503 LOG_INFO(
"sending to ");
504 LOG_INFO_LLADDR(addr);
505 LOG_INFO_(
", len %u, seqno %u, queue length %d, free packets %d\n",
507 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
508 list_length(n->packet_queue), memb_numfree(&packet_memb));
511 schedule_transmission(n);
516 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
519 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
527 LOG_WARN(
"Neighbor queue full\n");
529 LOG_WARN(
"could not allocate packet, dropping packet\n");
531 LOG_WARN(
"could not allocate neighbor, dropping packet\n");
533 mac_call_sent_callback(sent, ptr,
MAC_TX_ERR, 1);
537 csma_output_init(
void)
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
The MAC layer transmission could not be performed because of a fatal error.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
#define CLOCK_SECOND
A second, measured in system clock time.
Header file for the callback timer
Header file for the Packet queue buffer management
Linked list manipulation routines.
The MAC layer did not get an acknowledgement for the packet.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
void * list_head(list_t list)
Get a pointer to the first element of a list.
The MAC layer transmission was OK.
The MAC layer transmission could not be performed because of an error.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
int packetbuf_holds_broadcast(void)
Checks whether the current packet is a broadcast.
Memory block allocation routines.
The MAC layer deferred the transmission for a later time.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
void list_add(list_t list, void *item)
Add an item at the end of a list.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
#define LIST(name)
Declare a linked list.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Header file for the logging system
void list_remove(list_t list, void *item)
Remove a specific element from a list.
void * list_item_next(void *item)
Get the next item following this item.
#define MEMB(name, structure, num)
Declare a memory block.
int list_length(list_t list)
Get the length of a list.