48#include "dev/watchdog.h"
55#include "lib/assert.h"
59#define LOG_MODULE "CSMA"
60#define LOG_LEVEL LOG_LEVEL_MAC
65#ifdef CSMA_CONF_MIN_BE
66#define CSMA_MIN_BE CSMA_CONF_MIN_BE
72#ifdef CSMA_CONF_MAX_BE
73#define CSMA_MAX_BE CSMA_CONF_MAX_BE
79#ifdef CSMA_CONF_MAX_BACKOFF
80#define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
82#define CSMA_MAX_BACKOFF 5
86#ifdef CSMA_CONF_MAX_FRAME_RETRIES
87#define CSMA_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
89#define CSMA_MAX_FRAME_RETRIES 7
96 uint8_t max_transmissions;
100struct neighbor_queue {
101 struct neighbor_queue *next;
103 struct ctimer transmit_timer;
104 uint8_t transmissions;
110#ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
111#define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
113#define CSMA_MAX_NEIGHBOR_QUEUES 2
117#ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
118#define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
120#define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
123#define MAX_QUEUED_PACKETS QUEUEBUF_NUM
127 struct packet_queue *next;
128 struct queuebuf *buf;
132MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
133MEMB(packet_memb,
struct packet_queue, MAX_QUEUED_PACKETS);
134MEMB(metadata_memb,
struct qbuf_metadata, MAX_QUEUED_PACKETS);
138 struct packet_queue *q,
140 int num_transmissions);
141static void transmit_from_queue(
void *ptr);
143static struct neighbor_queue *
144neighbor_queue_from_addr(
const linkaddr_t *
addr)
146 struct neighbor_queue *n =
list_head(neighbor_list);
159#if CONTIKI_TARGET_COOJA
171send_one_packet(
struct neighbor_queue *n,
struct packet_queue *q)
174 int last_sent_ok = 0;
177 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
179#if LLSEC802154_ENABLED
180#if LLSEC802154_USES_EXPLICIT_KEYS
182 packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, CSMA_LLSEC_KEY_ID_MODE);
186 if(CSMA_FRAMER.create() < 0) {
188 LOG_ERR(
"failed to create packet, seqno: %d\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
199 if(NETSTACK_RADIO.receiving_packet() ||
200 (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
212 }
else if(CSMA_USE_RADIO_ACK) {
221 if(NETSTACK_RADIO.receiving_packet() ||
222 NETSTACK_RADIO.pending_packet() ||
223 NETSTACK_RADIO.channel_clear() == 0) {
225 uint8_t ackbuf[CSMA_ACK_LEN];
230 if(NETSTACK_RADIO.pending_packet()) {
231 len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
232 if(len == CSMA_ACK_LEN && ackbuf[2] == dsn) {
259 packet_sent(n, q, ret, 1);
264transmit_from_queue(
void *ptr)
266 struct neighbor_queue *n = ptr;
268 struct packet_queue *q =
list_head(n->packet_queue);
270 LOG_INFO(
"preparing packet for ");
271 LOG_INFO_LLADDR(&n->addr);
272 LOG_INFO_(
", seqno %u, tx %u, queue %d\n",
273 queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO),
276 queuebuf_to_packetbuf(q->buf);
277 send_one_packet(n, q);
283schedule_transmission(
struct neighbor_queue *n)
286 int backoff_exponent;
288 backoff_exponent = MIN(n->collisions + CSMA_MIN_BE, CSMA_MAX_BE);
291 delay = ((1 << backoff_exponent) - 1) * backoff_period();
294 delay = random_rand() % delay;
297 LOG_DBG(
"scheduling transmission in %u ticks, NB=%u, BE=%u\n",
298 (
unsigned)delay, n->collisions, backoff_exponent);
299 ctimer_set(&n->transmit_timer, delay, transmit_from_queue, n);
303free_packet(
struct neighbor_queue *n,
struct packet_queue *p,
int status)
309 queuebuf_free(p->buf);
312 LOG_DBG(
"free_queued_packet, queue length %d, free packets %zu\n",
316 n->transmissions = 0;
319 schedule_transmission(n);
330tx_done(
int status,
struct packet_queue *q,
struct neighbor_queue *n)
333 struct qbuf_metadata *metadata;
337 metadata = (
struct qbuf_metadata *)q->ptr;
338 sent = metadata->sent;
339 cptr = metadata->cptr;
340 ntx = n->transmissions;
342 LOG_INFO(
"packet sent to ");
343 LOG_INFO_LLADDR(&n->addr);
344 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
345 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
346 status, n->transmissions, n->collisions);
348 free_packet(n, q, status);
349 mac_call_sent_callback(sent, cptr, status, ntx);
353rexmit(
struct packet_queue *q,
struct neighbor_queue *n)
355 schedule_transmission(n);
358 queuebuf_update_attr_from_packetbuf(q->buf);
362collision(
struct packet_queue *q,
struct neighbor_queue *n,
363 int num_transmissions)
365 struct qbuf_metadata *metadata;
367 metadata = (
struct qbuf_metadata *)q->ptr;
369 n->collisions += num_transmissions;
371 if(n->collisions > CSMA_MAX_BACKOFF) {
377 if(n->transmissions >= metadata->max_transmissions) {
385noack(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
387 struct qbuf_metadata *metadata;
389 metadata = (
struct qbuf_metadata *)q->ptr;
392 n->transmissions += num_transmissions;
394 if(n->transmissions >= metadata->max_transmissions) {
402tx_ok(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
405 n->transmissions += num_transmissions;
410packet_sent(
struct neighbor_queue *n,
411 struct packet_queue *q,
413 int num_transmissions)
419 LOG_WARN(
"packet sent: no metadata\n");
424 LOG_INFO_LLADDR(&n->addr);
425 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
426 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
427 status, n->transmissions, n->collisions);
431 tx_ok(q, n, num_transmissions);
434 noack(q, n, num_transmissions);
437 collision(q, n, num_transmissions);
442 tx_done(status, q, n);
448csma_output_packet(mac_callback_t sent,
void *ptr)
450 struct packet_queue *q;
451 struct neighbor_queue *n;
452 const linkaddr_t *
addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
455 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
458 n = neighbor_queue_from_addr(
addr);
465 n->transmissions = 0;
476 if(
list_length(n->packet_queue) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
481 q->buf = queuebuf_new_from_packetbuf();
483 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
485 metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
486 if(metadata->max_transmissions == 0) {
488 metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1;
490 metadata->sent = sent;
491 metadata->cptr = ptr;
494 LOG_INFO(
"sending to ");
495 LOG_INFO_LLADDR(
addr);
496 LOG_INFO_(
", len %u, seqno %u, queue length %d, free packets %zu\n",
498 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
502 schedule_transmission(n);
507 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
510 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
518 LOG_WARN(
"Neighbor queue full\n");
520 LOG_WARN(
"could not allocate packet, dropping packet\n");
522 LOG_WARN(
"could not allocate neighbor, dropping packet\n");
524 mac_call_sent_callback(sent, ptr, MAC_TX_QUEUE_FULL, 1);
528csma_output_init(
void)
LLSEC802154 Security related configuration.
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
Header file for the callback timer.
802.15.4 frame creation and parsing functions
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
#define LIST(name)
Declare a linked list.
static void * list_item_next(const void *item)
Get the next item following this item.
int list_length(const_list_t list)
Get the length of a list.
void list_add(list_t list, void *item)
Add an item at the end of a list.
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
size_t memb_numfree(struct memb *m)
Count free memory blocks.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
#define MEMB(name, structure, num)
Declare a memory block.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
bool packetbuf_holds_broadcast(void)
Checks whether the current packet is a broadcast.
@ RADIO_TX_NOACK
A unicast frame was sent OK but an ACK was not received.
@ RADIO_TX_COLLISION
TX failed due to a collision.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
Linked list manipulation routines.
Header file for the logging system.
void mac_sequence_set_dsn(void)
Sets and increments the destination sequence number.
Header file for MAC sequence numbers management.
@ MAC_TX_COLLISION
The MAC layer did not get an acknowledgement for the packet.
@ MAC_TX_DEFERRED
The MAC layer transmission could not be performed because of an error.
@ MAC_TX_OK
The MAC layer transmission was OK.
@ MAC_TX_NOACK
The MAC layer deferred the transmission for a later time.
@ MAC_TX_ERR_FATAL
The MAC layer transmission could not be performed because of insufficient queue space,...
@ MAC_TX_ERR
The MAC layer transmission could not be performed because of a fatal error.
Memory block allocation routines.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the Packet queue buffer management.
Header file for generating non-cryptographic random numbers.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.