Added bursts support in CSMA/ContikiMAC, and CFS-swapping in

queuebuf. Exemplified in examples/udp-stream.
This commit is contained in:
simonduq 2011-09-27 16:05:30 +02:00
parent 5b1d9617c4
commit dd8576830e
19 changed files with 1197 additions and 285 deletions

View File

@ -58,9 +58,6 @@
#ifndef WITH_PHASE_OPTIMIZATION
#define WITH_PHASE_OPTIMIZATION 1
#endif
#ifndef WITH_STREAMING
#define WITH_STREAMING 0
#endif
#ifdef CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER
#define WITH_CONTIKIMAC_HEADER CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER
#else
@ -90,6 +87,14 @@ struct hdr {
#define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE)
#endif
/* Are we currently receiving a burst? */
static int we_are_receiving_burst = 0;
/* Has the receiver been awoken by a burst we're sending? */
static int is_receiver_awake = 0;
/* BURST_RECV_TIME is the maximum time a receiver waits for the
next packet of a burst when FRAME_PENDING is set. */
#define INTER_PACKET_DEADLINE CLOCK_SECOND / 32
/* ContikiMAC performs periodic channel checks. Each channel check
consists of two or more CCA checks. CCA_COUNT_MAX is the number of
@ -97,6 +102,10 @@ struct hdr {
two.*/
#define CCA_COUNT_MAX 2
/* Before starting a transmission, Contikimac checks the availability
of the channel with CCA_COUNT_MAX_TX consecutive CCAs */
#define CCA_COUNT_MAX_TX 6
/* CCA_CHECK_TIME is the time it takes to perform a CCA check. */
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192
@ -107,6 +116,10 @@ struct hdr {
CCAs. */
#define CHECK_TIME (CCA_COUNT_MAX * (CCA_CHECK_TIME + CCA_SLEEP_TIME))
/* CHECK_TIME_TX is the total time it takes to perform CCA_COUNT_MAX_TX
CCAs. */
#define CHECK_TIME_TX (CCA_COUNT_MAX_TX * (CCA_CHECK_TIME + CCA_SLEEP_TIME))
/* LISTEN_TIME_AFTER_PACKET_DETECTED is the time that we keep checking
for activity after a potential packet has been detected by a CCA
check. */
@ -130,7 +143,7 @@ struct hdr {
/* GUARD_TIME is the time before the expected phase of a neighbor that
a transmitted should begin transmitting packets. */
#define GUARD_TIME 11 * CHECK_TIME
#define GUARD_TIME 10 * CHECK_TIME + CHECK_TIME_TX
/* INTER_PACKET_INTERVAL is the interval between two successive packet transmissions */
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
@ -174,10 +187,6 @@ static volatile unsigned char radio_is_on = 0;
#define PRINTDEBUG(...)
#endif
/* Flag that is used to keep track of whether or not we are snooping
for announcements from neighbors. */
static volatile uint8_t is_snooping;
#if CONTIKIMAC_CONF_COMPOWER
static struct compower_activity current_packet;
#endif /* CONTIKIMAC_CONF_COMPOWER */
@ -198,10 +207,6 @@ PHASE_LIST(phase_list, MAX_PHASE_NEIGHBORS);
#endif /* WITH_PHASE_OPTIMIZATION */
static volatile uint8_t is_streaming;
static rimeaddr_t is_streaming_to, is_streaming_to_too;
static volatile rtimer_clock_t stream_until;
#define DEFAULT_STREAM_TIME (4 * CYCLE_TIME)
#ifndef MIN
@ -238,7 +243,7 @@ on(void)
static void
off(void)
{
if(contikimac_is_on && radio_is_on != 0 && /*is_streaming == 0 &&*/
if(contikimac_is_on && radio_is_on != 0 &&
contikimac_keep_radio_on == 0) {
radio_is_on = 0;
NETSTACK_RADIO.off();
@ -292,7 +297,7 @@ powercycle_turn_radio_off(void)
uint8_t was_on = radio_is_on;
#endif /* CONTIKIMAC_CONF_COMPOWER */
if(we_are_sending == 0) {
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
off();
#if CONTIKIMAC_CONF_COMPOWER
if(was_on && !radio_is_on) {
@ -305,7 +310,7 @@ powercycle_turn_radio_off(void)
static void
powercycle_turn_radio_on(void)
{
if(we_are_sending == 0) {
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
on();
}
}
@ -324,93 +329,82 @@ powercycle(struct rtimer *t, void *ptr)
cycle_start += CYCLE_TIME;
if(WITH_STREAMING && is_streaming) {
if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until)) {
is_streaming = 0;
rimeaddr_copy(&is_streaming_to, &rimeaddr_null);
rimeaddr_copy(&is_streaming_to_too, &rimeaddr_null);
}
}
packet_seen = 0;
do {
for(count = 0; count < CCA_COUNT_MAX; ++count) {
t0 = RTIMER_NOW();
if(we_are_sending == 0) {
powercycle_turn_radio_on();
/* Check if a packet is seen in the air. If so, we keep the
for(count = 0; count < CCA_COUNT_MAX; ++count) {
t0 = RTIMER_NOW();
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
powercycle_turn_radio_on();
/* Check if a packet is seen in the air. If so, we keep the
radio on for a while (LISTEN_TIME_AFTER_PACKET_DETECTED) to
be able to receive the packet. We also continuously check
the radio medium to make sure that we wasn't woken up by a
false positive: a spurious radio interference that was not
caused by an incoming packet. */
if(NETSTACK_RADIO.channel_clear() == 0) {
packet_seen = 1;
break;
}
powercycle_turn_radio_off();
if(NETSTACK_RADIO.channel_clear() == 0) {
packet_seen = 1;
break;
}
schedule_powercycle_fixed(t, RTIMER_NOW() + CCA_SLEEP_TIME);
PT_YIELD(&pt);
powercycle_turn_radio_off();
}
schedule_powercycle_fixed(t, RTIMER_NOW() + CCA_SLEEP_TIME);
PT_YIELD(&pt);
}
if(packet_seen) {
static rtimer_clock_t start;
static uint8_t silence_periods, periods;
start = RTIMER_NOW();
periods = silence_periods = 0;
while(we_are_sending == 0 && radio_is_on &&
RTIMER_CLOCK_LT(RTIMER_NOW(),
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
/* Check for a number of consecutive periods of
if(packet_seen) {
static rtimer_clock_t start;
static uint8_t silence_periods, periods;
start = RTIMER_NOW();
periods = silence_periods = 0;
while(we_are_sending == 0 && radio_is_on &&
RTIMER_CLOCK_LT(RTIMER_NOW(),
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
/* Check for a number of consecutive periods of
non-activity. If we see two such periods, we turn the
radio off. Also, if a packet has been successfully
received (as indicated by the
NETSTACK_RADIO.pending_packet() function), we stop
snooping. */
if(NETSTACK_RADIO.channel_clear()) {
++silence_periods;
} else {
silence_periods = 0;
}
++periods;
if(NETSTACK_RADIO.receiving_packet()) {
silence_periods = 0;
}
if(silence_periods > MAX_SILENCE_PERIODS) {
powercycle_turn_radio_off();
break;
}
if(WITH_FAST_SLEEP &&
periods > MAX_NONACTIVITY_PERIODS &&
!(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) {
powercycle_turn_radio_off();
break;
}
if(NETSTACK_RADIO.pending_packet()) {
break;
}
schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
PT_YIELD(&pt);
if(NETSTACK_RADIO.channel_clear()) {
++silence_periods;
} else {
silence_periods = 0;
}
if(radio_is_on) {
if(!(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet()) ||
++periods;
if(NETSTACK_RADIO.receiving_packet()) {
silence_periods = 0;
}
if(silence_periods > MAX_SILENCE_PERIODS) {
powercycle_turn_radio_off();
break;
}
if(WITH_FAST_SLEEP &&
periods > MAX_NONACTIVITY_PERIODS &&
!(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet())) {
powercycle_turn_radio_off();
break;
}
if(NETSTACK_RADIO.pending_packet()) {
break;
}
schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
PT_YIELD(&pt);
}
if(radio_is_on) {
if(!(NETSTACK_RADIO.receiving_packet() ||
NETSTACK_RADIO.pending_packet()) ||
!RTIMER_CLOCK_LT(RTIMER_NOW(),
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
powercycle_turn_radio_off();
}
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
powercycle_turn_radio_off();
}
}
} while((is_snooping || is_streaming) &&
RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME * 8));
}
if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME * 4)) {
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
@ -443,7 +437,7 @@ broadcast_rate_drop(void)
}
/*---------------------------------------------------------------------------*/
static int
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_list *buf_list)
{
rtimer_clock_t t0;
rtimer_clock_t encounter_time = 0, previous_txtime = 0;
@ -458,6 +452,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
int i;
int ret;
uint8_t contikimac_was_on;
uint8_t seqno;
#if WITH_CONTIKIMAC_HEADER
struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */
@ -495,25 +490,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);
if(WITH_STREAMING) {
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
if(rimeaddr_cmp(&is_streaming_to, &rimeaddr_null)) {
rimeaddr_copy(&is_streaming_to,
packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
} else if(!rimeaddr_cmp
(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
rimeaddr_copy(&is_streaming_to_too,
packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
}
stream_until = RTIMER_NOW() + DEFAULT_STREAM_TIME;
is_streaming = 1;
}
}
if(is_streaming) {
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
}
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
#if WITH_CONTIKIMAC_HEADER
@ -568,11 +544,11 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
/* Remove the MAC-layer header since it will be recreated next time around. */
packetbuf_hdr_remove(hdrlen);
if(!is_broadcast && !is_streaming) {
if(!is_broadcast && !is_receiver_awake) {
#if WITH_PHASE_OPTIMIZATION
ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
CYCLE_TIME, GUARD_TIME,
mac_callback, mac_callback_ptr);
mac_callback, mac_callback_ptr, buf_list, 0);
if(ret == PHASE_DEFERRED) {
return MAC_TX_DEFERRED;
}
@ -617,10 +593,10 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
contikimac_is_on when we are done. */
contikimac_was_on = contikimac_is_on;
contikimac_is_on = 1;
if(is_streaming == 0) {
if(is_receiver_awake == 0) {
/* Check if there are any transmissions by others. */
for(i = 0; i < CCA_COUNT_MAX; ++i) {
for(i = 0; i < CCA_COUNT_MAX_TX; ++i) {
t0 = RTIMER_NOW();
on();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)) { }
@ -646,21 +622,22 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
if(!is_broadcast) {
on();
}
watchdog_periodic();
t0 = RTIMER_NOW();
seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
for(strobes = 0, collisions = 0;
got_strobe_ack == 0 && collisions == 0 &&
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
watchdog_periodic();
if(is_known_receiver && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) {
if((is_receiver_awake || is_known_receiver) && !RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) {
PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
break;
}
len = 0;
previous_txtime = RTIMER_NOW();
@ -683,7 +660,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
if(len == ACK_LEN) {
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN-1]) {
got_strobe_ack = 1;
encounter_time = previous_txtime;
break;
@ -740,42 +717,97 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
}
if(!is_broadcast) {
if(collisions == 0 && is_streaming == 0) {
if(collisions == 0 && is_receiver_awake == 0) {
phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
ret);
}
}
#endif /* WITH_PHASE_OPTIMIZATION */
if(WITH_STREAMING) {
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END) {
is_streaming = 0;
}
}
return ret;
}
/*---------------------------------------------------------------------------*/
static void
qsend_packet(mac_callback_t sent, void *ptr)
{
int ret = send_packet(sent, ptr);
int ret = send_packet(sent, ptr, NULL);
if(ret != MAC_TX_DEFERRED) {
mac_call_sent_callback(sent, ptr, ret, 1);
}
}
/*---------------------------------------------------------------------------*/
void
qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
struct rdc_buf_list *curr = buf_list;
struct rdc_buf_list *next;
int ret;
if(curr == NULL) {
mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
return;
}
/* Do not send during reception of a burst */
if(we_are_receiving_burst) {
queuebuf_to_packetbuf(curr->buf);
/* We try to defer, and return an error this wasn't possible */
int ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
CYCLE_TIME, GUARD_TIME,
sent, ptr, curr, 2);
if(ret != PHASE_DEFERRED) {
mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
}
return;
}
/* The receiver needs to be awoken before we send */
is_receiver_awake = 0;
do { /* A loop sending a burst of packets from buf_list */
next = list_item_next(curr);
/* Prepare the packetbuf */
queuebuf_to_packetbuf(curr->buf);
if(next != NULL) {
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
}
/* Send the current packet */
ret = send_packet(sent, ptr, curr);
if(ret != MAC_TX_DEFERRED) {
mac_call_sent_callback(sent, ptr, ret, 1);
}
if(ret == MAC_TX_OK) {
if(next != NULL) {
/* We're in a burst, no need to wake the receiver up again */
is_receiver_awake = 1;
curr = next;
}
} else {
/* The transmission failed, we stop the burst */
next = NULL;
}
} while(next != NULL);
is_receiver_awake = 0;
}
/*---------------------------------------------------------------------------*/
/* Timer callback triggered when receiving a burst, after having waited for a next
packet for a too long time. Turns the radio off and leaves burst reception mode */
static void
recv_burst_off(void *ptr)
{
off();
we_are_receiving_burst = 0;
}
/*---------------------------------------------------------------------------*/
static void
input_packet(void)
{
/* We have received the packet, so we can go back to being
asleep. */
off();
static struct ctimer ct;
if(!we_are_receiving_burst) {
off();
}
/* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/
if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) {
#if WITH_CONTIKIMAC_HEADER
@ -798,14 +830,16 @@ input_packet(void)
/* This is a regular packet that is destined to us or to the
broadcast address. */
#if WITH_PHASE_OPTIMIZATION
/* If the sender has set its pending flag, it has its radio
turned on and we should drop the phase estimation that we
have from before. */
if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) {
phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER));
/* If FRAME_PENDING is set, we are receiving a packets in a burst */
we_are_receiving_burst = packetbuf_attr(PACKETBUF_ATTR_PENDING);
if(we_are_receiving_burst) {
on();
/* Set a timer to turn the radio off in case we do not receive a next packet */
ctimer_set(&ct, INTER_PACKET_DEADLINE, recv_burst_off, NULL);
} else {
off();
ctimer_stop(&ct);
}
#endif /* WITH_PHASE_OPTIMIZATION */
/* Check for duplicate packet by comparing the sequence number
of the incoming packet with the last few ones we saw. */
@ -859,6 +893,7 @@ init(void)
{
radio_is_on = 0;
PT_INIT(&pt);
rtimer_set(&rt, RTIMER_NOW() + CYCLE_TIME, 1,
(void (*)(struct rtimer *, void *))powercycle, NULL);
@ -906,6 +941,7 @@ const struct rdc_driver contikimac_driver = {
"ContikiMAC",
init,
qsend_packet,
qsend_list,
input_packet,
turn_on,
turn_off,

View File

@ -43,6 +43,7 @@
#include "net/queuebuf.h"
#include "sys/ctimer.h"
#include "sys/clock.h"
#include "lib/random.h"
@ -76,26 +77,51 @@
#error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
#endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */
struct queued_packet {
struct queued_packet *next;
struct queuebuf *buf;
/* struct ctimer retransmit_timer;*/
/* Packet metadata */
struct qbuf_metadata {
mac_callback_t sent;
void *cptr;
uint8_t transmissions, max_transmissions;
uint8_t collisions, deferrals;
uint8_t max_transmissions;
};
#define MAX_QUEUED_PACKETS 6
MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
LIST(queued_packet_list);
/* Every neighbor has its own packet queue */
struct neighbor_queue {
struct neighbor_queue *next;
rimeaddr_t addr;
struct ctimer transmit_timer;
uint8_t transmissions;
uint8_t collisions, deferrals;
LIST_STRUCT(queued_packet_list);
};
static struct ctimer transmit_timer;
/* The maximum number of co-existing neighbor queues */
#ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
#define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
#else
#define CSMA_MAX_NEIGHBOR_QUEUES 2
#endif /* CSMA_CONF_MAX_NEIGHBOR_QUEUES */
static uint8_t rdc_is_transmitting;
#define MAX_QUEUED_PACKETS QUEUEBUF_NUM
MEMB(neighbor_memb, struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
MEMB(packet_memb, struct rdc_buf_list, MAX_QUEUED_PACKETS);
MEMB(metadata_memb, struct qbuf_metadata, MAX_QUEUED_PACKETS);
LIST(neighbor_list);
static void packet_sent(void *ptr, int status, int num_transmissions);
static void transmit_packet_list(void *ptr);
/*---------------------------------------------------------------------------*/
static struct
neighbor_queue *neighbor_queue_from_addr(const rimeaddr_t *addr) {
struct neighbor_queue *n = list_head(neighbor_list);
while(n != NULL) {
if(rimeaddr_cmp(&n->addr, addr)) {
return n;
}
n = list_item_next(n);
}
return NULL;
}
/*---------------------------------------------------------------------------*/
static clock_time_t
default_timebase(void)
@ -115,61 +141,44 @@ default_timebase(void)
}
/*---------------------------------------------------------------------------*/
static void
transmit_queued_packet(void *ptr)
transmit_packet_list(void *ptr)
{
/* struct queued_packet *q = ptr;*/
struct queued_packet *q;
/* Don't transmit a packet if the RDC is still transmitting the
previous one. */
if(rdc_is_transmitting) {
return;
}
// printf("q %d\n", list_length(queued_packet_list));
q = list_head(queued_packet_list);
if(q != NULL) {
queuebuf_to_packetbuf(q->buf);
PRINTF("csma: sending number %d %p, queue len %d\n", q->transmissions, q,
list_length(queued_packet_list));
// printf("s %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
rdc_is_transmitting = 1;
NETSTACK_RDC.send(packet_sent, q);
}
}
/*---------------------------------------------------------------------------*/
static void
start_transmission_timer(void)
{
PRINTF("csma: start_transmission_timer, queue len %d\n",
list_length(queued_packet_list));
if(list_length(queued_packet_list) > 0) {
if(ctimer_expired(&transmit_timer)) {
ctimer_set(&transmit_timer, 0,
transmit_queued_packet, NULL);
struct neighbor_queue *n = ptr;
if(n) {
struct rdc_buf_list *q = list_head(n->queued_packet_list);
if(q != NULL) {
PRINTF("csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
list_length(n->queued_packet_list));
/* Send packets in the neighbor's list */
NETSTACK_RDC.send_list(packet_sent, n, q);
}
}
}
/*---------------------------------------------------------------------------*/
static void
free_queued_packet(void)
free_first_packet(struct neighbor_queue *n)
{
struct queued_packet *q;
// printf("q %d\n", list_length(queued_packet_list));
q = list_head(queued_packet_list);
struct rdc_buf_list *q = list_head(n->queued_packet_list);
if(q != NULL) {
/* Remove first packet from list and deallocate */
queuebuf_free(q->buf);
list_remove(queued_packet_list, q);
list_pop(n->queued_packet_list);
memb_free(&metadata_memb, q->ptr);
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);
list_length(n->queued_packet_list));
if(list_head(n->queued_packet_list)) {
/* 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);
}
}
}
@ -177,32 +186,32 @@ free_queued_packet(void)
static void
packet_sent(void *ptr, int status, int num_transmissions)
{
struct queued_packet *q = ptr;
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;
rdc_is_transmitting = 0;
switch(status) {
case MAC_TX_OK:
case MAC_TX_NOACK:
q->transmissions++;
n->transmissions++;
break;
case MAC_TX_COLLISION:
q->collisions++;
n->collisions++;
break;
case MAC_TX_DEFERRED:
q->deferrals++;
n->deferrals++;
break;
}
sent = q->sent;
cptr = q->cptr;
num_tx = q->transmissions;
sent = metadata->sent;
cptr = metadata->cptr;
num_tx = n->transmissions;
if(status == MAC_TX_COLLISION ||
status == MAC_TX_NOACK) {
@ -211,13 +220,13 @@ packet_sent(void *ptr, int status, int num_transmissions)
switch(status) {
case MAC_TX_COLLISION:
PRINTF("csma: rexmit collision %d\n", q->transmissions);
PRINTF("csma: rexmit collision %d\n", n->transmissions);
break;
case MAC_TX_NOACK:
PRINTF("csma: rexmit noack %d\n", q->transmissions);
PRINTF("csma: rexmit noack %d\n", n->transmissions);
break;
default:
PRINTF("csma: rexmit err %d, %d\n", status, q->transmissions);
PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions);
}
/* The retransmission time must be proportional to the channel
@ -227,7 +236,7 @@ packet_sent(void *ptr, int status, int num_transmissions)
/* The retransmission time uses a linear backoff so that the
interval between the transmissions increase with each
retransmit. */
backoff_transmissions = q->transmissions + 1;
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
@ -235,32 +244,29 @@ packet_sent(void *ptr, int status, int num_transmissions)
if(backoff_transmissions > 3) {
backoff_transmissions = 3;
}
time = time + (random_rand() % (backoff_transmissions * time));
if(q->transmissions < q->max_transmissions) {
if(n->transmissions < metadata->max_transmissions) {
PRINTF("csma: retransmitting with time %lu %p\n", time, q);
ctimer_set(&transmit_timer, time,
transmit_queued_packet, NULL);
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, q->transmissions, q->collisions);
/* queuebuf_to_packetbuf(q->buf);*/
free_queued_packet();
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", q->transmissions);
PRINTF("csma: rexmit ok %d\n", n->transmissions);
} else {
PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status);
}
/* queuebuf_to_packetbuf(q->buf);*/
free_queued_packet();
free_first_packet(n);
mac_call_sent_callback(sent, cptr, status, num_tx);
}
}
@ -268,53 +274,89 @@ packet_sent(void *ptr, int status, int num_transmissions)
static void
send_packet(mac_callback_t sent, void *ptr)
{
struct queued_packet *q;
struct rdc_buf_list *q;
struct neighbor_queue *n;
static uint16_t seqno;
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
/* If the packet is a broadcast, do not allocate a queue
entry. Instead, just send it out. */
if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
&rimeaddr_null)) {
const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
/* Remember packet for later. */
q = memb_alloc(&packet_memb);
if(q != NULL) {
q->buf = queuebuf_new_from_packetbuf();
if(q->buf != NULL) {
if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
/* Use default configuration for max transmissions */
q->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
} else {
q->max_transmissions =
packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
}
q->transmissions = 0;
q->collisions = 0;
q->deferrals = 0;
q->sent = sent;
q->cptr = ptr;
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
list_push(queued_packet_list, q);
} else {
list_add(queued_packet_list, q);
}
start_transmission_timer();
return;
/* 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);
}
memb_free(&packet_memb, q);
PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
}
PRINTF("csma: could not allocate memb, will drop if collision or noack\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);
} else {
PRINTF("csma: send broadcast (%d) or without retransmissions (%d)\n",
!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
&rimeaddr_null),
packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS));
PRINTF("csma: send broadcast\n");
NETSTACK_RDC.send(sent, ptr);
}
NETSTACK_RDC.send(sent, ptr);
}
/*---------------------------------------------------------------------------*/
static void
@ -348,7 +390,8 @@ static void
init(void)
{
memb_init(&packet_memb);
rdc_is_transmitting = 0;
memb_init(&metadata_memb);
memb_init(&neighbor_memb);
}
/*---------------------------------------------------------------------------*/
const struct mac_driver csma_driver = {

View File

@ -699,6 +699,15 @@ qsend_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1);
}
/*---------------------------------------------------------------------------*/
void
qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
qsend_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static void
input_packet(void)
{
@ -914,6 +923,7 @@ const struct rdc_driver cxmac_driver =
"CX-MAC",
cxmac_init,
qsend_packet,
qsend_list,
input_packet,
turn_on,
turn_off,

View File

@ -726,6 +726,15 @@ send_packet(mac_callback_t sent, void *ptr)
}
}
/*---------------------------------------------------------------------------*/
void
send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
send_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static int
detect_ack(void)
{
@ -1024,6 +1033,7 @@ const struct rdc_driver lpp_driver = {
"LPP",
init,
send_packet,
send_list,
input_packet,
on,
off,

View File

@ -55,6 +55,15 @@ send_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1);
}
/*---------------------------------------------------------------------------*/
void
send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
send_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static void
packet_input(void)
{
@ -93,6 +102,7 @@ const struct rdc_driver nullrdc_noframer_driver = {
"nullrdc-noframer",
init,
send_packet,
send_list,
packet_input,
on,
off,

View File

@ -201,6 +201,15 @@ send_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1);
}
/*---------------------------------------------------------------------------*/
void
send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
send_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static void
packet_input(void)
{
@ -278,6 +287,7 @@ const struct rdc_driver nullrdc_driver = {
"nullrdc",
init,
send_packet,
send_list,
packet_input,
on,
off,

View File

@ -52,6 +52,7 @@ struct phase_queueitem {
mac_callback_t mac_callback;
void *mac_callback_ptr;
struct queuebuf *q;
struct rdc_buf_list *buf_list;
};
#define PHASE_DEFER_THRESHOLD 1
@ -150,17 +151,23 @@ send_packet(void *ptr)
{
struct phase_queueitem *p = ptr;
queuebuf_to_packetbuf(p->q);
queuebuf_free(p->q);
if(p->buf_list == NULL) {
queuebuf_to_packetbuf(p->q);
queuebuf_free(p->q);
NETSTACK_RDC.send(p->mac_callback, p->mac_callback_ptr);
} else {
NETSTACK_RDC.send_list(p->mac_callback, p->mac_callback_ptr, p->buf_list);
}
memb_free(&queued_packets_memb, p);
NETSTACK_RDC.send(p->mac_callback, p->mac_callback_ptr);
}
/*---------------------------------------------------------------------------*/
phase_status_t
phase_wait(struct phase_list *list,
const rimeaddr_t *neighbor, rtimer_clock_t cycle_time,
rtimer_clock_t guard_time,
mac_callback_t mac_callback, void *mac_callback_ptr)
mac_callback_t mac_callback, void *mac_callback_ptr,
struct rdc_buf_list *buf_list, int extra_deferment)
{
struct phase *e;
// const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
@ -169,8 +176,8 @@ phase_wait(struct phase_list *list,
time for the next expected phase and setup a ctimer to switch on
the radio just before the phase. */
e = find_neighbor(list, neighbor);
if(e != NULL) {
rtimer_clock_t wait, now, expected;
if((e != NULL) | extra_deferment) {
rtimer_clock_t wait, now, expected, sync;
clock_time_t ctimewait;
/* We expect phases to happen every CYCLE_TIME time
@ -188,31 +195,38 @@ phase_wait(struct phase_list *list,
}*/
now = RTIMER_NOW();
wait = (rtimer_clock_t)((e->time - now) &
sync = (e == NULL) ? now : e->time;
wait = (rtimer_clock_t)((sync - now) &
(cycle_time - 1));
if(wait < guard_time) {
wait += cycle_time;
}
if(extra_deferment) {
wait += extra_deferment * cycle_time;
}
ctimewait = (CLOCK_SECOND * (wait - guard_time)) / RTIMER_ARCH_SECOND;
if(ctimewait > PHASE_DEFER_THRESHOLD) {
if((ctimewait > PHASE_DEFER_THRESHOLD) | extra_deferment) {
struct phase_queueitem *p;
p = memb_alloc(&queued_packets_memb);
if(p != NULL) {
p->q = queuebuf_new_from_packetbuf();
if(p->q != NULL) {
p->mac_callback = mac_callback;
p->mac_callback_ptr = mac_callback_ptr;
ctimer_set(&p->timer, ctimewait, send_packet, p);
return PHASE_DEFERRED;
} else {
memb_free(&queued_packets_memb, p);
if(buf_list == NULL) {
p->q = queuebuf_new_from_packetbuf();
}
p->mac_callback = mac_callback;
p->mac_callback_ptr = mac_callback_ptr;
p->buf_list = buf_list;
ctimer_set(&p->timer, ctimewait, send_packet, p);
return PHASE_DEFERRED;
} else {
memb_free(&queued_packets_memb, p);
}
}
expected = now + wait - guard_time;
if(!RTIMER_CLOCK_LT(expected, now)) {
/* Wait until the receiver is expected to be awake */

View File

@ -75,7 +75,8 @@ typedef enum {
void phase_init(struct phase_list *list);
phase_status_t phase_wait(struct phase_list *list, const rimeaddr_t *neighbor,
rtimer_clock_t cycle_time, rtimer_clock_t wait_before,
mac_callback_t mac_callback, void *mac_callback_ptr);
mac_callback_t mac_callback, void *mac_callback_ptr,
struct rdc_buf_list *buf_list, int extra_deferment);
void phase_update(const struct phase_list *list, const rimeaddr_t *neighbor,
rtimer_clock_t time, int mac_status);

View File

@ -45,6 +45,13 @@
#include "contiki-conf.h"
#include "net/mac/mac.h"
/* List of packets to be sent by RDC layer */
struct rdc_buf_list {
struct rdc_buf_list *next;
struct queuebuf *buf;
void *ptr;
};
/**
* The structure of a RDC (radio duty cycling) driver in Contiki.
*/
@ -57,6 +64,9 @@ struct rdc_driver {
/** Send a packet from the Rime buffer */
void (* send)(mac_callback_t sent_callback, void *ptr);
/** Send a packet list */
void (* send_list)(mac_callback_t sent_callback, void *ptr, struct rdc_buf_list *list);
/** Callback for getting notified of incoming packet. */
void (* input)(void);

View File

@ -175,6 +175,15 @@ send_packet(mac_callback_t sent, void *ptr)
}
}
/*---------------------------------------------------------------------------*/
void
send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
send_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static void
input_packet(void)
{
@ -248,6 +257,7 @@ const struct rdc_driver sicslowmac_driver = {
"sicslowmac",
init,
send_packet,
send_list,
input_packet,
on,
off,

View File

@ -763,6 +763,15 @@ qsend_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1);
}
/*---------------------------------------------------------------------------*/
void
qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
{
if(buf_list != NULL) {
queuebuf_to_packetbuf(buf_list->buf);
qsend_packet(sent, ptr);
}
}
/*---------------------------------------------------------------------------*/
static void
input_packet(void)
{
@ -999,6 +1008,7 @@ const struct rdc_driver xmac_driver =
"X-MAC",
init,
qsend_packet,
qsend_list,
input_packet,
turn_on,
turn_off,

View File

@ -44,6 +44,9 @@
*/
#include "contiki-net.h"
#if WITH_SWAP
#include "cfs/cfs.h"
#endif
#include <string.h> /* for memcpy() */
@ -53,6 +56,8 @@
#define QUEUEBUF_REF_NUM 2
#endif
/* Structure pointing to a buffer either stored
in RAM or swapped in CFS */
struct queuebuf {
#if QUEUEBUF_DEBUG
struct queuebuf *next;
@ -60,6 +65,19 @@ struct queuebuf {
int line;
clock_time_t time;
#endif /* QUEUEBUF_DEBUG */
#if WITH_SWAP
enum {IN_RAM, IN_CFS} location;
union {
#endif
struct queuebuf_data *ram_ptr;
#if WITH_SWAP
int swap_id;
};
#endif
};
/* The actual queuebuf data */
struct queuebuf_data {
uint16_t len;
uint8_t data[PACKETBUF_SIZE];
struct packetbuf_attr attrs[PACKETBUF_NUM_ATTRS];
@ -75,6 +93,37 @@ struct queuebuf_ref {
MEMB(bufmem, struct queuebuf, QUEUEBUF_NUM);
MEMB(refbufmem, struct queuebuf_ref, QUEUEBUF_REF_NUM);
MEMB(buframmem, struct queuebuf_data, QUEUEBUFRAM_NUM);
#if WITH_SWAP
/* Swapping allows to store up to QUEUEBUF_NUM - QUEUEBUFRAM_NUM
queuebufs in CFS. The swap is made of several large CFS files.
Every buffer stored in CFS has a swap id, referring to a specific
offset in one of these files. */
#define NQBUF_FILES 4
#define NQBUF_PER_FILE 256
#define QBUF_FILE_SIZE (NQBUF_PER_FILE*sizeof(struct queuebuf_data))
#define NQBUF_ID (NQBUF_PER_FILE * NQBUF_FILES)
struct qbuf_file {
int fd;
int usage;
int renewable;
};
/* A statically allocated queuebuf used as a cache for swapped qbufs */
static struct queuebuf_data tmpdata;
/* A pointer to the qbuf associated to the data in tmpdata */
static struct queuebuf *tmpdata_qbuf = NULL;
/* The swap id counter */
static int next_swap_id = 0;
/* The swap files */
static struct qbuf_file qbuf_files[NQBUF_FILES];
/* The timer used to renew files during inactivity periods */
static struct ctimer renew_timer;
#endif
#if QUEUEBUF_DEBUG
#include "lib/list.h"
@ -99,10 +148,161 @@ LIST(queuebuf_list);
uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len;
#endif /* QUEUEBUF_STATS */
static void queuebuf_remove_from_file(int swap_id);
#if WITH_SWAP
/*---------------------------------------------------------------------------*/
static void
qbuf_renew_file(int file)
{
int ret;
char name[2];
name[0] = 'a' + file;
name[1] = '\0';
if(qbuf_files[file].renewable == 1) {
PRINTF("qbuf_renew_file: removing file %d\n", file);
cfs_remove(name);
}
ret = cfs_open(name, CFS_READ | CFS_WRITE);
if(ret == -1) {
PRINTF("qbuf_renew_file: cfs open error\n");
}
qbuf_files[file].fd = ret;
qbuf_files[file].usage = 0;
qbuf_files[file].renewable = 0;
}
/*---------------------------------------------------------------------------*/
/* Renews every file with renewable flag set */
static void
qbuf_renew_all(void *unused)
{
int i;
for(i=0; i<NQBUF_FILES; i++) {
if(qbuf_files[i].renewable == 1) {
qbuf_renew_file(i);
}
}
}
/*---------------------------------------------------------------------------*/
/* Removes a queuebuf from its swap file */
static void
queuebuf_remove_from_file(int swap_id)
{
int fileid;
if(swap_id != -1) {
fileid = swap_id / NQBUF_PER_FILE;
qbuf_files[fileid].usage--;
/* The file is full but doesn't contain any more queuebuf, mark it as renewable */
if(qbuf_files[fileid].usage == 0 && fileid != next_swap_id / NQBUF_PER_FILE) {
qbuf_files[fileid].renewable = 1;
/* This file is renewable, set a timer to renew files */
ctimer_set(&renew_timer, 0, qbuf_renew_all, NULL);
}
if(tmpdata_qbuf->swap_id == swap_id) {
tmpdata_qbuf->swap_id = -1;
}
}
}
/*---------------------------------------------------------------------------*/
static int
get_new_swap_id(void)
{
int fileid;
int swap_id = next_swap_id;
fileid = swap_id / NQBUF_PER_FILE;
if(swap_id % NQBUF_PER_FILE == 0) { /* This is the first id in the file */
if(qbuf_files[fileid].renewable) {
qbuf_renew_file(fileid);
}
if(qbuf_files[fileid].usage>0) {
return -1;
}
}
qbuf_files[fileid].usage++;
next_swap_id = (next_swap_id+1) % NQBUF_ID;
return swap_id;
}
/*---------------------------------------------------------------------------*/
/* Flush tmpdata to CFS */
static int
queuebuf_flush_tmpdata(void)
{
int fileid, fd, ret;
cfs_offset_t offset;
if(tmpdata_qbuf) {
queuebuf_remove_from_file(tmpdata_qbuf->swap_id);
tmpdata_qbuf->swap_id = get_new_swap_id();
if(tmpdata_qbuf->swap_id == -1) {
return -1;
}
fileid = tmpdata_qbuf->swap_id / NQBUF_PER_FILE;
offset = (tmpdata_qbuf->swap_id % NQBUF_PER_FILE) * sizeof(struct queuebuf_data);
fd = qbuf_files[fileid].fd;
ret = cfs_seek(fd, offset, CFS_SEEK_SET);
if(ret == -1) {
PRINTF("queuebuf_flush_tmpdata: cfs seek error\n");
return -1;
}
ret = cfs_write(fd, &tmpdata, sizeof(struct queuebuf_data));
if(ret == -1) {
PRINTF("queuebuf_flush_tmpdata: cfs write error\n");
return -1;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* If the queuebuf is in CFS, load it to tmpdata */
static struct queuebuf_data *
queuebuf_load_to_ram(struct queuebuf *b)
{
int fileid, fd, ret;
cfs_offset_t offset;
if(b->location == IN_RAM) { /* the qbuf is loacted in RAM */
return b->ram_ptr;
} else { /* the qbuf is located in CFS */
if(tmpdata_qbuf && tmpdata_qbuf->swap_id == b->swap_id) { /* the qbuf is already in tmpdata */
return &tmpdata;
} else { /* the qbuf needs to be loaded from CFS */
tmpdata_qbuf = b;
/* read the qbuf from CFS */
fileid = b->swap_id / NQBUF_PER_FILE;
offset = (b->swap_id % NQBUF_PER_FILE) * sizeof(struct queuebuf_data);
fd = qbuf_files[fileid].fd;
ret = cfs_seek(fd, offset, CFS_SEEK_SET);
if(ret == -1) {
PRINTF("queuebuf_load_to_ram: cfs seek error\n");
}
ret = cfs_read(fd, &tmpdata, sizeof(struct queuebuf_data));
if(ret == -1) {
PRINTF("queuebuf_load_to_ram: cfs read error\n");
}
return &tmpdata;
}
}
}
#else /* WITH_SWAP */
/*---------------------------------------------------------------------------*/
static struct queuebuf_data *
queuebuf_load_to_ram(struct queuebuf *b)
{
return b->ram_ptr;
}
#endif /* WITH_SWAP */
/*---------------------------------------------------------------------------*/
void
queuebuf_init(void)
{
#if WITH_SWAP
int i;
for(i=0; i<NQBUF_FILES; i++) {
qbuf_files[i].renewable = 1;
qbuf_renew_file(i);
}
#endif
memb_init(&buframmem);
memb_init(&bufmem);
memb_init(&refbufmem);
#if QUEUEBUF_STATS
@ -135,6 +335,7 @@ queuebuf_new_from_packetbuf(void)
}
return (struct queuebuf *)rbuf;
} else {
struct queuebuf_data *buframptr;
buf = memb_alloc(&bufmem);
if(buf != NULL) {
#if QUEUEBUF_DEBUG
@ -143,18 +344,50 @@ queuebuf_new_from_packetbuf(void)
buf->line = line;
buf->time = clock_time();
#endif /* QUEUEBUF_DEBUG */
buf->ram_ptr = memb_alloc(&buframmem);
#if WITH_SWAP
/* If the allocation failed, store the qbuf in swap files */
if(buf->ram_ptr != NULL) {
buf->location = IN_RAM;
buframptr = buf->ram_ptr;
} else {
buf->location = IN_CFS;
buf->swap_id = -1;
tmpdata_qbuf = buf;
buframptr = &tmpdata;
}
#else
if(buf->ram_ptr == NULL) {
PRINTF("queuebuf_new_from_packetbuf: could not queuebuf data\n");
return NULL;
}
buframptr = buf->ram_ptr;
#endif
buframptr->len = packetbuf_copyto(buframptr->data);
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
#if WITH_SWAP
if(buf->location == IN_CFS) {
if(queuebuf_flush_tmpdata() == -1) {
/* We were unable to write the data in the swap */
memb_free(&bufmem, buf);
return NULL;
}
}
#endif
#if QUEUEBUF_STATS
++queuebuf_len;
PRINTF("queuebuf len %d\n", queuebuf_len);
printf("#A q=%d\n", queuebuf_len);
if(queuebuf_len == queuebuf_max_len + 1) {
memb_free(&bufmem, buf);
queuebuf_len--;
return NULL;
memb_free(&bufmem, buf);
queuebuf_len--;
return NULL;
}
#endif /* QUEUEBUF_STATS */
buf->len = packetbuf_copyto(buf->data);
packetbuf_attr_copyto(buf->attrs, buf->addrs);
} else {
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
}
@ -165,13 +398,28 @@ queuebuf_new_from_packetbuf(void)
void
queuebuf_update_attr_from_packetbuf(struct queuebuf *buf)
{
packetbuf_attr_copyto(buf->attrs, buf->addrs);
struct queuebuf_data *buframptr = queuebuf_load_to_ram(buf);
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
#if WITH_SWAP
if(buf->location == IN_CFS) {
queuebuf_flush_tmpdata();
}
#endif
}
/*---------------------------------------------------------------------------*/
void
queuebuf_free(struct queuebuf *buf)
{
if(memb_inmemb(&bufmem, buf)) {
#if WITH_SWAP
if(buf->location == IN_RAM) {
memb_free(&buframmem, buf->ram_ptr);
} else {
queuebuf_remove_from_file(buf->swap_id);
}
#else
memb_free(&buframmem, buf->ram_ptr);
#endif
memb_free(&bufmem, buf);
#if QUEUEBUF_STATS
--queuebuf_len;
@ -192,10 +440,10 @@ void
queuebuf_to_packetbuf(struct queuebuf *b)
{
struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) {
packetbuf_copyfrom(b->data, b->len);
packetbuf_attr_copyfrom(b->attrs, b->addrs);
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
packetbuf_copyfrom(buframptr->data, buframptr->len);
packetbuf_attr_copyfrom(buframptr->attrs, buframptr->addrs);
} else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b;
packetbuf_clear();
@ -209,9 +457,10 @@ void *
queuebuf_dataptr(struct queuebuf *b)
{
struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) {
return b->data;
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return buframptr->data;
} else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b;
return r->ref;
@ -222,19 +471,22 @@ queuebuf_dataptr(struct queuebuf *b)
int
queuebuf_datalen(struct queuebuf *b)
{
return b->len;
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return buframptr->len;
}
/*---------------------------------------------------------------------------*/
rimeaddr_t *
queuebuf_addr(struct queuebuf *b, uint8_t type)
{
return &b->addrs[type - PACKETBUF_ADDR_FIRST].addr;
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return &buframptr->addrs[type - PACKETBUF_ADDR_FIRST].addr;
}
/*---------------------------------------------------------------------------*/
packetbuf_attr_t
queuebuf_attr(struct queuebuf *b, uint8_t type)
{
return b->attrs[type].val;
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return buframptr->attrs[type].val;
}
/*---------------------------------------------------------------------------*/
void

View File

@ -56,12 +56,30 @@
#include "net/packetbuf.h"
/* QUEUEBUF_NUM is the total number of queuebuf */
#ifdef QUEUEBUF_CONF_NUM
#define QUEUEBUF_NUM QUEUEBUF_CONF_NUM
#else
#define QUEUEBUF_NUM 8
#endif
/* QUEUEBUFRAM_NUM is the number of queuebufs stored in RAM.
If QUEUEBUFRAM_CONF_NUM is set lower than QUEUEBUF_NUM,
swapping is enabled and queuebufs are stored either in RAM of CFS.
If QUEUEBUFRAM_CONF_NUM is unset or >= to QUEUEBUF_NUM, all
queuebufs are in RAM and swapping is disabled. */
#ifdef QUEUEBUFRAM_CONF_NUM
#if QUEUEBUFRAM_CONF_NUM>QUEUEBUF_NUM
#error "QUEUEBUFRAM_CONF_NUM cannot be greater than QUEUEBUF_NUM"
#else
#define QUEUEBUFRAM_NUM QUEUEBUFRAM_CONF_NUM
#define WITH_SWAP (QUEUEBUFRAM_NUM < QUEUEBUF_NUM)
#endif
#else /* QUEUEBUFRAM_CONF_NUM */
#define QUEUEBUFRAM_NUM QUEUEBUF_NUM
#define WITH_SWAP 0
#endif /* QUEUEBUFRAM_CONF_NUM */
#ifdef QUEUEBUF_CONF_DEBUG
#define QUEUEBUF_DEBUG QUEUEBUF_CONF_DEBUG
#else /* QUEUEBUF_CONF_DEBUG */

View File

@ -0,0 +1,14 @@
all: udp-stream
APPS = servreg-hack
CONTIKI = ../..
ifndef TARGET
TARGET = sky
endif
WITH_UIP6 = 1
UIP_CONF_IPV6 = 1
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
SMALL = 1
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,21 @@
This is an example of bursts support in CSMA/ContikiMAC,
together with storage of long packet queue in CFS. This
is useful to support large fragmented UDP datagrams or
continuous data streaming. The current implementation
is a simplified version of the techniques presented in
"Lossy Links, Low Power, High Throughput", published in
the proceeding of ACM SenSys 2011.
In this example, node with ID==5 sends bursts of UDP
datagrams to node with ID==1, the root of the RPL dodag.
Testing in cooja:
$make TARGET=cooja udp-stream.csc
Testing on Tmote sky:
1) set node IDs to different motes so node 5 sends to
node 1 (using examples/sky-shell)
2) compile and program:
$make TARGET=sky udp-stream.upload
3) monitor motes with:
$make login MOTE=xxx

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: project-conf.h,v 1.1 2010/10/28 13:11:08 simonduq Exp $
*/
#ifndef __PROJECT_H__
#define __PROJECT_H__
/* Free some code and RAM space */
#define UIP_CONF_TCP 0
#undef UIP_CONF_DS6_NBR_NBU
#define UIP_CONF_DS6_NBR_NBU 12
#undef UIP_CONF_DS6_ROUTE_NBU
#define UIP_CONF_DS6_ROUTE_NBU 12
/* The total number of queuebuf */
#undef QUEUEBUF_CONF_NUM
#define QUEUEBUF_CONF_NUM 140
/* The number of queuebuf actually stored in RAM. If
not set or equal to the total number of queuebuf,
swapping is disabled, and CFS not linked. */
#define QUEUEBUFRAM_CONF_NUM 2
/* Set a large (1 sector) default size for coffee files. */
#define COFFEE_CONF_DYN_SIZE (COFFEE_SECTOR_SIZE - COFFEE_PAGE_SIZE + 1)
#endif /* __PROJECT_H__ */

View File

@ -0,0 +1,204 @@
/*
* Copyright (c) 2006, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* $Id: hello-world.c,v 1.1 2006/10/02 21:46:46 simonduq Exp $
*/
/**
* \file
* An example sending a UDP stream
* \author
* Simon Duquennoy <simonduq@sics.se>
*/
#include "contiki.h"
#include "contiki-net.h"
#include "uip.h"
#include "net/rpl/rpl.h"
#include "node-id.h"
#include "servreg-hack.h"
#include "cfs/cfs.h"
#include "cfs/cfs-coffee.h"
#define SINK_ID 1
#define SENDER_ID 5
#define DATASIZE 73
#define STREAMLEN QUEUEBUF_CONF_NUM
#define UDP_PORT 9876
#define SERVICE_ID 190
struct msg {
uint8_t streamno;
uint8_t seqno;
uint8_t buf[DATASIZE];
};
static struct simple_udp_connection unicast_connection;
/*---------------------------------------------------------------------------*/
PROCESS(udpstream_process, "UDP Stream Process");
AUTOSTART_PROCESSES(&udpstream_process);
/*---------------------------------------------------------------------------*/
static uip_ipaddr_t *
set_global_address(void)
{
static uip_ipaddr_t ipaddr;
int i;
uint8_t state;
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
printf("IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
printf("\n");
}
}
return &ipaddr;
}
/*---------------------------------------------------------------------------*/
static void
create_rpl_dag(uip_ipaddr_t *ipaddr)
{
struct uip_ds6_addr *root_if;
root_if = uip_ds6_addr_lookup(ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
uip_ipaddr_t prefix;
rpl_set_root(ipaddr);
dag = rpl_get_dag(RPL_ANY_INSTANCE);
uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &prefix, 64);
printf("created a new RPL dag\n");
} else {
printf("failed to create a new RPL DAG\n");
}
}
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
static int cpt;
cpt++;
if(cpt%128==0) {
printf("Received %d datagrams\n", cpt);
}
}
/*---------------------------------------------------------------------------*/
static void
send_stream(uip_ipaddr_t *addr, uint16_t streamno)
{
int i;
int seqno = 0;
struct msg msg;
memset(&msg, 0xaa, sizeof(msg));
msg.streamno = streamno;
for(i=0; i<STREAMLEN; i++) {
msg.seqno = ++seqno;
simple_udp_sendto(&unicast_connection, (char*)&msg, sizeof(msg), addr);
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(udpstream_process, ev, data)
{
static uint16_t streamno;
static struct etimer et;
static uip_ipaddr_t *ipaddr;
PROCESS_BEGIN();
PROCESS_PAUSE();
printf("Formatting Coffee FS...\n");
cfs_coffee_format();
printf("done.\n");
/* We need re-initialize queuebuf after formatting */
queuebuf_init();
/* Start service registration */
servreg_hack_init();
ipaddr = set_global_address();
if(node_id == SINK_ID) {
/* The sink creates a dag and waits for UDP datagrams */
create_rpl_dag(ipaddr);
servreg_hack_register(SERVICE_ID, ipaddr);
simple_udp_register(&unicast_connection, UDP_PORT,
NULL, UDP_PORT, receiver);
while(1) {
PROCESS_WAIT_EVENT();
}
} else if(node_id == SENDER_ID) {
/* The sender looks for the sink and sends UDP streams */
ipaddr = NULL;
simple_udp_register(&unicast_connection, UDP_PORT,
NULL, UDP_PORT, receiver);
etimer_set(&et, 10*CLOCK_SECOND);
etimer_restart(&et);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
if(ipaddr != NULL) {
streamno++;
send_stream(ipaddr, streamno);
} else {
ipaddr = servreg_hack_lookup(SERVICE_ID);
if(ipaddr != NULL) {
etimer_set(&et, 2*CLOCK_SECOND);
printf("Streaming to ");
uip_debug_ipaddr_print(ipaddr);
printf("\n");
} else {
printf("Service %d not found\n", SERVICE_ID);
}
}
etimer_restart(&et);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
<simulation>
<title>UDP Stream Example</title>
<delaytime>0</delaytime>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
se.sics.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>100.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
se.sics.cooja.mspmote.SkyMoteType
<identifier>mote</identifier>
<description>mote</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/udp-stream/udp-stream.c</source>
<commands EXPORT="discard">make udp-stream.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/udp-stream/udp-stream.sky</firmware>
<moteinterface>se.sics.cooja.interfaces.Position</moteinterface>
<moteinterface>se.sics.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>se.sics.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>se.sics.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>se.sics.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>33.260163187353555</x>
<y>30.643217359962595</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>mote</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>70.87477363740156</x>
<y>31.656474063135494</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>mote</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>112.33402646502834</x>
<y>47.18506616257089</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>3</id>
</interface_config>
<motetype_identifier>mote</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>132.53950850661624</x>
<y>78.99637996219282</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>4</id>
</interface_config>
<motetype_identifier>mote</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
se.sics.cooja.interfaces.Position
<x>136.72844990548202</x>
<y>114.94735349716447</y>
<z>0.0</z>
</interface_config>
<interface_config>
se.sics.cooja.mspmote.interfaces.MspMoteID
<id>5</id>
</interface_config>
<motetype_identifier>mote</motetype_identifier>
</mote>
</simulation>
<plugin>
se.sics.cooja.plugins.SimControl
<width>259</width>
<z>4</z>
<height>178</height>
<location_x>0</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.Visualizer
<plugin_config>
<skin>se.sics.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>se.sics.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<skin>se.sics.cooja.plugins.skins.MoteTypeVisualizerSkin</skin>
<skin>se.sics.cooja.plugins.skins.AttributeVisualizerSkin</skin>
<viewport>1.2465387687077096 0.0 0.0 1.2465387687077096 22.99764760264848 12.704392736072247</viewport>
</plugin_config>
<width>257</width>
<z>3</z>
<height>297</height>
<location_x>0</location_x>
<location_y>180</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.LogListener
<plugin_config>
<filter />
<coloring />
</plugin_config>
<width>568</width>
<z>2</z>
<height>663</height>
<location_x>257</location_x>
<location_y>-2</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.RadioLogger
<plugin_config>
<split>449</split>
<analyzers name="6lowpan" />
</plugin_config>
<width>605</width>
<z>1</z>
<height>661</height>
<location_x>824</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
se.sics.cooja.plugins.TimeLine
<plugin_config>
<mote>0</mote>
<mote>1</mote>
<mote>2</mote>
<mote>3</mote>
<mote>4</mote>
<showRadioRXTX />
<showRadioHW />
<split>125</split>
<zoomfactor>100000.0</zoomfactor>
</plugin_config>
<width>1429</width>
<z>0</z>
<height>141</height>
<location_x>1</location_x>
<location_y>661</location_y>
</plugin>
</simconf>

View File

@ -52,7 +52,11 @@
#define COFFEE_MAX_OPEN_FILES 6
#define COFFEE_FD_SET_SIZE 8
#define COFFEE_LOG_TABLE_LIMIT 256
#define COFFEE_DYN_SIZE 4*1024
#ifdef COFFEE_CONF_DYN_SIZE
#define COFFEE_DYN_SIZE COFFEE_CONF_DYN_SIZE
#else
#define COFFEE_DYN_SIZE 4*1024
#endif
#define COFFEE_LOG_SIZE 1024
#define COFFEE_IO_SEMANTICS 1