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 #ifndef WITH_PHASE_OPTIMIZATION
#define WITH_PHASE_OPTIMIZATION 1 #define WITH_PHASE_OPTIMIZATION 1
#endif #endif
#ifndef WITH_STREAMING
#define WITH_STREAMING 0
#endif
#ifdef CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER #ifdef CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER
#define WITH_CONTIKIMAC_HEADER CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER #define WITH_CONTIKIMAC_HEADER CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER
#else #else
@ -90,6 +87,14 @@ struct hdr {
#define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE) #define CYCLE_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE)
#endif #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 /* ContikiMAC performs periodic channel checks. Each channel check
consists of two or more CCA checks. CCA_COUNT_MAX is the number of consists of two or more CCA checks. CCA_COUNT_MAX is the number of
@ -97,6 +102,10 @@ struct hdr {
two.*/ two.*/
#define CCA_COUNT_MAX 2 #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. */ /* CCA_CHECK_TIME is the time it takes to perform a CCA check. */
#define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192 #define CCA_CHECK_TIME RTIMER_ARCH_SECOND / 8192
@ -107,6 +116,10 @@ struct hdr {
CCAs. */ CCAs. */
#define CHECK_TIME (CCA_COUNT_MAX * (CCA_CHECK_TIME + CCA_SLEEP_TIME)) #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 /* LISTEN_TIME_AFTER_PACKET_DETECTED is the time that we keep checking
for activity after a potential packet has been detected by a CCA for activity after a potential packet has been detected by a CCA
check. */ check. */
@ -130,7 +143,7 @@ struct hdr {
/* GUARD_TIME is the time before the expected phase of a neighbor that /* GUARD_TIME is the time before the expected phase of a neighbor that
a transmitted should begin transmitting packets. */ 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 */ /* INTER_PACKET_INTERVAL is the interval between two successive packet transmissions */
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000 #define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 5000
@ -174,10 +187,6 @@ static volatile unsigned char radio_is_on = 0;
#define PRINTDEBUG(...) #define PRINTDEBUG(...)
#endif #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 #if CONTIKIMAC_CONF_COMPOWER
static struct compower_activity current_packet; static struct compower_activity current_packet;
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
@ -198,10 +207,6 @@ PHASE_LIST(phase_list, MAX_PHASE_NEIGHBORS);
#endif /* WITH_PHASE_OPTIMIZATION */ #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) #define DEFAULT_STREAM_TIME (4 * CYCLE_TIME)
#ifndef MIN #ifndef MIN
@ -238,7 +243,7 @@ on(void)
static void static void
off(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) { contikimac_keep_radio_on == 0) {
radio_is_on = 0; radio_is_on = 0;
NETSTACK_RADIO.off(); NETSTACK_RADIO.off();
@ -292,7 +297,7 @@ powercycle_turn_radio_off(void)
uint8_t was_on = radio_is_on; uint8_t was_on = radio_is_on;
#endif /* CONTIKIMAC_CONF_COMPOWER */ #endif /* CONTIKIMAC_CONF_COMPOWER */
if(we_are_sending == 0) { if(we_are_sending == 0 && we_are_receiving_burst == 0) {
off(); off();
#if CONTIKIMAC_CONF_COMPOWER #if CONTIKIMAC_CONF_COMPOWER
if(was_on && !radio_is_on) { if(was_on && !radio_is_on) {
@ -305,7 +310,7 @@ powercycle_turn_radio_off(void)
static void static void
powercycle_turn_radio_on(void) powercycle_turn_radio_on(void)
{ {
if(we_are_sending == 0) { if(we_are_sending == 0 && we_are_receiving_burst == 0) {
on(); on();
} }
} }
@ -324,93 +329,82 @@ powercycle(struct rtimer *t, void *ptr)
cycle_start += CYCLE_TIME; 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; packet_seen = 0;
do { for(count = 0; count < CCA_COUNT_MAX; ++count) {
for(count = 0; count < CCA_COUNT_MAX; ++count) { t0 = RTIMER_NOW();
t0 = RTIMER_NOW(); if(we_are_sending == 0 && we_are_receiving_burst == 0) {
if(we_are_sending == 0) { powercycle_turn_radio_on();
powercycle_turn_radio_on(); /* Check if a packet is seen in the air. If so, we keep the
/* 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 radio on for a while (LISTEN_TIME_AFTER_PACKET_DETECTED) to
be able to receive the packet. We also continuously check be able to receive the packet. We also continuously check
the radio medium to make sure that we wasn't woken up by a the radio medium to make sure that we wasn't woken up by a
false positive: a spurious radio interference that was not false positive: a spurious radio interference that was not
caused by an incoming packet. */ caused by an incoming packet. */
if(NETSTACK_RADIO.channel_clear() == 0) { if(NETSTACK_RADIO.channel_clear() == 0) {
packet_seen = 1; packet_seen = 1;
break; break;
}
powercycle_turn_radio_off();
} }
schedule_powercycle_fixed(t, RTIMER_NOW() + CCA_SLEEP_TIME); powercycle_turn_radio_off();
PT_YIELD(&pt);
} }
schedule_powercycle_fixed(t, RTIMER_NOW() + CCA_SLEEP_TIME);
PT_YIELD(&pt);
}
if(packet_seen) { if(packet_seen) {
static rtimer_clock_t start; static rtimer_clock_t start;
static uint8_t silence_periods, periods; static uint8_t silence_periods, periods;
start = RTIMER_NOW(); start = RTIMER_NOW();
periods = silence_periods = 0; periods = silence_periods = 0;
while(we_are_sending == 0 && radio_is_on && while(we_are_sending == 0 && radio_is_on &&
RTIMER_CLOCK_LT(RTIMER_NOW(), RTIMER_CLOCK_LT(RTIMER_NOW(),
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) { (start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
/* Check for a number of consecutive periods of /* Check for a number of consecutive periods of
non-activity. If we see two such periods, we turn the non-activity. If we see two such periods, we turn the
radio off. Also, if a packet has been successfully radio off. Also, if a packet has been successfully
received (as indicated by the received (as indicated by the
NETSTACK_RADIO.pending_packet() function), we stop NETSTACK_RADIO.pending_packet() function), we stop
snooping. */ snooping. */
if(NETSTACK_RADIO.channel_clear()) { if(NETSTACK_RADIO.channel_clear()) {
++silence_periods; ++silence_periods;
} else { } else {
silence_periods = 0; 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(radio_is_on) {
if(!(NETSTACK_RADIO.receiving_packet() || ++periods;
NETSTACK_RADIO.pending_packet()) ||
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(), !RTIMER_CLOCK_LT(RTIMER_NOW(),
(start + LISTEN_TIME_AFTER_PACKET_DETECTED))) { (start + LISTEN_TIME_AFTER_PACKET_DETECTED))) {
powercycle_turn_radio_off(); 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)) { if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME * 4)) {
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start); schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
@ -443,7 +437,7 @@ broadcast_rate_drop(void)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int 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 t0;
rtimer_clock_t encounter_time = 0, previous_txtime = 0; 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 i;
int ret; int ret;
uint8_t contikimac_was_on; uint8_t contikimac_was_on;
uint8_t seqno;
#if WITH_CONTIKIMAC_HEADER #if WITH_CONTIKIMAC_HEADER
struct hdr *chdr; struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */ #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) || is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE); 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); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
#if WITH_CONTIKIMAC_HEADER #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. */ /* Remove the MAC-layer header since it will be recreated next time around. */
packetbuf_hdr_remove(hdrlen); packetbuf_hdr_remove(hdrlen);
if(!is_broadcast && !is_streaming) { if(!is_broadcast && !is_receiver_awake) {
#if WITH_PHASE_OPTIMIZATION #if WITH_PHASE_OPTIMIZATION
ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), ret = phase_wait(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
CYCLE_TIME, GUARD_TIME, CYCLE_TIME, GUARD_TIME,
mac_callback, mac_callback_ptr); mac_callback, mac_callback_ptr, buf_list, 0);
if(ret == PHASE_DEFERRED) { if(ret == PHASE_DEFERRED) {
return MAC_TX_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_is_on when we are done. */
contikimac_was_on = contikimac_is_on; contikimac_was_on = contikimac_is_on;
contikimac_is_on = 1; contikimac_is_on = 1;
if(is_streaming == 0) { if(is_receiver_awake == 0) {
/* Check if there are any transmissions by others. */ /* 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(); t0 = RTIMER_NOW();
on(); on();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + CCA_CHECK_TIME)) { } 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) { if(!is_broadcast) {
on(); on();
} }
watchdog_periodic(); watchdog_periodic();
t0 = RTIMER_NOW(); t0 = RTIMER_NOW();
seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
for(strobes = 0, collisions = 0; for(strobes = 0, collisions = 0;
got_strobe_ack == 0 && collisions == 0 && got_strobe_ack == 0 && collisions == 0 &&
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) { RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
watchdog_periodic(); 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]); PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
break; break;
} }
len = 0; len = 0;
previous_txtime = RTIMER_NOW(); 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)) { } while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
if(len == ACK_LEN) { if(len == ACK_LEN && seqno == ackbuf[ACK_LEN-1]) {
got_strobe_ack = 1; got_strobe_ack = 1;
encounter_time = previous_txtime; encounter_time = previous_txtime;
break; break;
@ -740,42 +717,97 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr)
} }
if(!is_broadcast) { 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, phase_update(&phase_list, packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time,
ret); ret);
} }
} }
#endif /* WITH_PHASE_OPTIMIZATION */ #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; return ret;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
qsend_packet(mac_callback_t sent, void *ptr) 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) { if(ret != MAC_TX_DEFERRED) {
mac_call_sent_callback(sent, ptr, ret, 1); 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 static void
input_packet(void) input_packet(void)
{ {
/* We have received the packet, so we can go back to being static struct ctimer ct;
asleep. */ if(!we_are_receiving_burst) {
off(); off();
}
/* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/ /* printf("cycle_start 0x%02x 0x%02x\n", cycle_start, cycle_start % CYCLE_TIME);*/
if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) { if(packetbuf_totlen() > 0 && NETSTACK_FRAMER.parse()) {
#if WITH_CONTIKIMAC_HEADER #if WITH_CONTIKIMAC_HEADER
@ -798,14 +830,16 @@ input_packet(void)
/* This is a regular packet that is destined to us or to the /* This is a regular packet that is destined to us or to the
broadcast address. */ broadcast address. */
#if WITH_PHASE_OPTIMIZATION /* If FRAME_PENDING is set, we are receiving a packets in a burst */
/* If the sender has set its pending flag, it has its radio we_are_receiving_burst = packetbuf_attr(PACKETBUF_ATTR_PENDING);
turned on and we should drop the phase estimation that we if(we_are_receiving_burst) {
have from before. */ on();
if(packetbuf_attr(PACKETBUF_ATTR_PENDING)) { /* Set a timer to turn the radio off in case we do not receive a next packet */
phase_remove(&phase_list, packetbuf_addr(PACKETBUF_ADDR_SENDER)); 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 /* Check for duplicate packet by comparing the sequence number
of the incoming packet with the last few ones we saw. */ of the incoming packet with the last few ones we saw. */
@ -859,6 +893,7 @@ init(void)
{ {
radio_is_on = 0; radio_is_on = 0;
PT_INIT(&pt); PT_INIT(&pt);
rtimer_set(&rt, RTIMER_NOW() + CYCLE_TIME, 1, rtimer_set(&rt, RTIMER_NOW() + CYCLE_TIME, 1,
(void (*)(struct rtimer *, void *))powercycle, NULL); (void (*)(struct rtimer *, void *))powercycle, NULL);
@ -906,6 +941,7 @@ const struct rdc_driver contikimac_driver = {
"ContikiMAC", "ContikiMAC",
init, init,
qsend_packet, qsend_packet,
qsend_list,
input_packet, input_packet,
turn_on, turn_on,
turn_off, turn_off,

View File

@ -43,6 +43,7 @@
#include "net/queuebuf.h" #include "net/queuebuf.h"
#include "sys/ctimer.h" #include "sys/ctimer.h"
#include "sys/clock.h"
#include "lib/random.h" #include "lib/random.h"
@ -76,26 +77,51 @@
#error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile. #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
#endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */ #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */
struct queued_packet { /* Packet metadata */
struct queued_packet *next; struct qbuf_metadata {
struct queuebuf *buf;
/* struct ctimer retransmit_timer;*/
mac_callback_t sent; mac_callback_t sent;
void *cptr; void *cptr;
uint8_t transmissions, max_transmissions; uint8_t max_transmissions;
uint8_t collisions, deferrals;
}; };
#define MAX_QUEUED_PACKETS 6 /* Every neighbor has its own packet queue */
MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS); struct neighbor_queue {
LIST(queued_packet_list); 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 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 static clock_time_t
default_timebase(void) default_timebase(void)
@ -115,61 +141,44 @@ default_timebase(void)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
transmit_queued_packet(void *ptr) transmit_packet_list(void *ptr)
{ {
/* struct queued_packet *q = ptr;*/ struct neighbor_queue *n = ptr;
struct queued_packet *q; if(n) {
struct rdc_buf_list *q = list_head(n->queued_packet_list);
/* Don't transmit a packet if the RDC is still transmitting the if(q != NULL) {
previous one. */ PRINTF("csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
if(rdc_is_transmitting) { list_length(n->queued_packet_list));
return; /* Send packets in the neighbor's list */
} NETSTACK_RDC.send_list(packet_sent, n, q);
// 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);
} }
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
free_queued_packet(void) free_first_packet(struct neighbor_queue *n)
{ {
struct queued_packet *q; struct rdc_buf_list *q = list_head(n->queued_packet_list);
// printf("q %d\n", list_length(queued_packet_list));
q = list_head(queued_packet_list);
if(q != NULL) { if(q != NULL) {
/* Remove first packet from list and deallocate */
queuebuf_free(q->buf); 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); memb_free(&packet_memb, q);
PRINTF("csma: free_queued_packet, queue length %d\n", PRINTF("csma: free_queued_packet, queue length %d\n",
list_length(queued_packet_list)); list_length(n->queued_packet_list));
if(list_length(queued_packet_list) > 0) { if(list_head(n->queued_packet_list)) {
ctimer_set(&transmit_timer, default_timebase(), transmit_queued_packet, NULL); /* 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 static void
packet_sent(void *ptr, int status, int num_transmissions) 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; clock_time_t time = 0;
mac_callback_t sent; mac_callback_t sent;
void *cptr; void *cptr;
int num_tx; int num_tx;
int backoff_transmissions; int backoff_transmissions;
rdc_is_transmitting = 0;
switch(status) { switch(status) {
case MAC_TX_OK: case MAC_TX_OK:
case MAC_TX_NOACK: case MAC_TX_NOACK:
q->transmissions++; n->transmissions++;
break; break;
case MAC_TX_COLLISION: case MAC_TX_COLLISION:
q->collisions++; n->collisions++;
break; break;
case MAC_TX_DEFERRED: case MAC_TX_DEFERRED:
q->deferrals++; n->deferrals++;
break; break;
} }
sent = q->sent; sent = metadata->sent;
cptr = q->cptr; cptr = metadata->cptr;
num_tx = q->transmissions; num_tx = n->transmissions;
if(status == MAC_TX_COLLISION || if(status == MAC_TX_COLLISION ||
status == MAC_TX_NOACK) { status == MAC_TX_NOACK) {
@ -211,13 +220,13 @@ packet_sent(void *ptr, int status, int num_transmissions)
switch(status) { switch(status) {
case MAC_TX_COLLISION: case MAC_TX_COLLISION:
PRINTF("csma: rexmit collision %d\n", q->transmissions); PRINTF("csma: rexmit collision %d\n", n->transmissions);
break; break;
case MAC_TX_NOACK: case MAC_TX_NOACK:
PRINTF("csma: rexmit noack %d\n", q->transmissions); PRINTF("csma: rexmit noack %d\n", n->transmissions);
break; break;
default: 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 /* 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 /* The retransmission time uses a linear backoff so that the
interval between the transmissions increase with each interval between the transmissions increase with each
retransmit. */ 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 /* Clamp the number of backoffs so that we don't get a too long
timeout here, since that will delay all packets in the 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) { if(backoff_transmissions > 3) {
backoff_transmissions = 3; backoff_transmissions = 3;
} }
time = time + (random_rand() % (backoff_transmissions * time)); 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); PRINTF("csma: retransmitting with time %lu %p\n", time, q);
ctimer_set(&transmit_timer, time, ctimer_set(&n->transmit_timer, time,
transmit_queued_packet, NULL); transmit_packet_list, n);
/* This is needed to correctly attribute energy that we spent /* This is needed to correctly attribute energy that we spent
transmitting this packet. */ transmitting this packet. */
queuebuf_update_attr_from_packetbuf(q->buf); queuebuf_update_attr_from_packetbuf(q->buf);
} else { } else {
PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n", PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
status, q->transmissions, q->collisions); status, n->transmissions, n->collisions);
/* queuebuf_to_packetbuf(q->buf);*/ free_first_packet(n);
free_queued_packet();
mac_call_sent_callback(sent, cptr, status, num_tx); mac_call_sent_callback(sent, cptr, status, num_tx);
} }
} else { } else {
if(status == MAC_TX_OK) { if(status == MAC_TX_OK) {
PRINTF("csma: rexmit ok %d\n", q->transmissions); PRINTF("csma: rexmit ok %d\n", n->transmissions);
} else { } 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_first_packet(n);
free_queued_packet();
mac_call_sent_callback(sent, cptr, status, num_tx); mac_call_sent_callback(sent, cptr, status, num_tx);
} }
} }
@ -268,53 +274,89 @@ packet_sent(void *ptr, int status, int num_transmissions)
static void static void
send_packet(mac_callback_t sent, void *ptr) 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; static uint16_t seqno;
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++); packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
/* If the packet is a broadcast, do not allocate a queue /* If the packet is a broadcast, do not allocate a queue
entry. Instead, just send it out. */ entry. Instead, just send it out. */
if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
&rimeaddr_null)) { &rimeaddr_null)) {
const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
/* Remember packet for later. */ /* Look for the neighbor entry */
q = memb_alloc(&packet_memb); n = neighbor_queue_from_addr(addr);
if(q != NULL) { if(n == NULL) {
q->buf = queuebuf_new_from_packetbuf(); /* Allocate a new neighbor entry */
if(q->buf != NULL) { n = memb_alloc(&neighbor_memb);
if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) { if(n != NULL) {
/* Use default configuration for max transmissions */ /* Init neighbor entry */
q->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS; rimeaddr_copy(&n->addr, addr);
} else { n->transmissions = 0;
q->max_transmissions = n->collisions = 0;
packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); n->deferrals = 0;
} /* Init packet list for this neighbor */
q->transmissions = 0; LIST_STRUCT_INIT(n, queued_packet_list);
q->collisions = 0; /* Add neighbor to the list */
q->deferrals = 0; list_add(neighbor_list, n);
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;
} }
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 { } else {
PRINTF("csma: send broadcast (%d) or without retransmissions (%d)\n", PRINTF("csma: send broadcast\n");
!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), NETSTACK_RDC.send(sent, ptr);
&rimeaddr_null),
packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS));
} }
NETSTACK_RDC.send(sent, ptr);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -348,7 +390,8 @@ static void
init(void) init(void)
{ {
memb_init(&packet_memb); memb_init(&packet_memb);
rdc_is_transmitting = 0; memb_init(&metadata_memb);
memb_init(&neighbor_memb);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
const struct mac_driver csma_driver = { 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); 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 static void
input_packet(void) input_packet(void)
{ {
@ -914,6 +923,7 @@ const struct rdc_driver cxmac_driver =
"CX-MAC", "CX-MAC",
cxmac_init, cxmac_init,
qsend_packet, qsend_packet,
qsend_list,
input_packet, input_packet,
turn_on, turn_on,
turn_off, 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 static int
detect_ack(void) detect_ack(void)
{ {
@ -1024,6 +1033,7 @@ const struct rdc_driver lpp_driver = {
"LPP", "LPP",
init, init,
send_packet, send_packet,
send_list,
input_packet, input_packet,
on, on,
off, off,

View File

@ -55,6 +55,15 @@ send_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1); 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 static void
packet_input(void) packet_input(void)
{ {
@ -93,6 +102,7 @@ const struct rdc_driver nullrdc_noframer_driver = {
"nullrdc-noframer", "nullrdc-noframer",
init, init,
send_packet, send_packet,
send_list,
packet_input, packet_input,
on, on,
off, off,

View File

@ -201,6 +201,15 @@ send_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1); 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 static void
packet_input(void) packet_input(void)
{ {
@ -278,6 +287,7 @@ const struct rdc_driver nullrdc_driver = {
"nullrdc", "nullrdc",
init, init,
send_packet, send_packet,
send_list,
packet_input, packet_input,
on, on,
off, off,

View File

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

View File

@ -75,7 +75,8 @@ typedef enum {
void phase_init(struct phase_list *list); void phase_init(struct phase_list *list);
phase_status_t phase_wait(struct phase_list *list, const rimeaddr_t *neighbor, phase_status_t phase_wait(struct phase_list *list, const rimeaddr_t *neighbor,
rtimer_clock_t cycle_time, rtimer_clock_t wait_before, 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, void phase_update(const struct phase_list *list, const rimeaddr_t *neighbor,
rtimer_clock_t time, int mac_status); rtimer_clock_t time, int mac_status);

View File

@ -45,6 +45,13 @@
#include "contiki-conf.h" #include "contiki-conf.h"
#include "net/mac/mac.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. * 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 */ /** Send a packet from the Rime buffer */
void (* send)(mac_callback_t sent_callback, void *ptr); 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. */ /** Callback for getting notified of incoming packet. */
void (* input)(void); 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 static void
input_packet(void) input_packet(void)
{ {
@ -248,6 +257,7 @@ const struct rdc_driver sicslowmac_driver = {
"sicslowmac", "sicslowmac",
init, init,
send_packet, send_packet,
send_list,
input_packet, input_packet,
on, on,
off, off,

View File

@ -763,6 +763,15 @@ qsend_packet(mac_callback_t sent, void *ptr)
mac_call_sent_callback(sent, ptr, ret, 1); 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 static void
input_packet(void) input_packet(void)
{ {
@ -999,6 +1008,7 @@ const struct rdc_driver xmac_driver =
"X-MAC", "X-MAC",
init, init,
qsend_packet, qsend_packet,
qsend_list,
input_packet, input_packet,
turn_on, turn_on,
turn_off, turn_off,

View File

@ -44,6 +44,9 @@
*/ */
#include "contiki-net.h" #include "contiki-net.h"
#if WITH_SWAP
#include "cfs/cfs.h"
#endif
#include <string.h> /* for memcpy() */ #include <string.h> /* for memcpy() */
@ -53,6 +56,8 @@
#define QUEUEBUF_REF_NUM 2 #define QUEUEBUF_REF_NUM 2
#endif #endif
/* Structure pointing to a buffer either stored
in RAM or swapped in CFS */
struct queuebuf { struct queuebuf {
#if QUEUEBUF_DEBUG #if QUEUEBUF_DEBUG
struct queuebuf *next; struct queuebuf *next;
@ -60,6 +65,19 @@ struct queuebuf {
int line; int line;
clock_time_t time; clock_time_t time;
#endif /* QUEUEBUF_DEBUG */ #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; uint16_t len;
uint8_t data[PACKETBUF_SIZE]; uint8_t data[PACKETBUF_SIZE];
struct packetbuf_attr attrs[PACKETBUF_NUM_ATTRS]; struct packetbuf_attr attrs[PACKETBUF_NUM_ATTRS];
@ -75,6 +93,37 @@ struct queuebuf_ref {
MEMB(bufmem, struct queuebuf, QUEUEBUF_NUM); MEMB(bufmem, struct queuebuf, QUEUEBUF_NUM);
MEMB(refbufmem, struct queuebuf_ref, QUEUEBUF_REF_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 #if QUEUEBUF_DEBUG
#include "lib/list.h" #include "lib/list.h"
@ -99,10 +148,161 @@ LIST(queuebuf_list);
uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len; uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len;
#endif /* QUEUEBUF_STATS */ #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 void
queuebuf_init(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(&bufmem);
memb_init(&refbufmem); memb_init(&refbufmem);
#if QUEUEBUF_STATS #if QUEUEBUF_STATS
@ -135,6 +335,7 @@ queuebuf_new_from_packetbuf(void)
} }
return (struct queuebuf *)rbuf; return (struct queuebuf *)rbuf;
} else { } else {
struct queuebuf_data *buframptr;
buf = memb_alloc(&bufmem); buf = memb_alloc(&bufmem);
if(buf != NULL) { if(buf != NULL) {
#if QUEUEBUF_DEBUG #if QUEUEBUF_DEBUG
@ -143,18 +344,50 @@ queuebuf_new_from_packetbuf(void)
buf->line = line; buf->line = line;
buf->time = clock_time(); buf->time = clock_time();
#endif /* QUEUEBUF_DEBUG */ #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 #if QUEUEBUF_STATS
++queuebuf_len; ++queuebuf_len;
PRINTF("queuebuf len %d\n", queuebuf_len); PRINTF("queuebuf len %d\n", queuebuf_len);
printf("#A q=%d\n", queuebuf_len); printf("#A q=%d\n", queuebuf_len);
if(queuebuf_len == queuebuf_max_len + 1) { if(queuebuf_len == queuebuf_max_len + 1) {
memb_free(&bufmem, buf); memb_free(&bufmem, buf);
queuebuf_len--; queuebuf_len--;
return NULL; return NULL;
} }
#endif /* QUEUEBUF_STATS */ #endif /* QUEUEBUF_STATS */
buf->len = packetbuf_copyto(buf->data);
packetbuf_attr_copyto(buf->attrs, buf->addrs);
} else { } else {
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n"); PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
} }
@ -165,13 +398,28 @@ queuebuf_new_from_packetbuf(void)
void void
queuebuf_update_attr_from_packetbuf(struct queuebuf *buf) 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 void
queuebuf_free(struct queuebuf *buf) queuebuf_free(struct queuebuf *buf)
{ {
if(memb_inmemb(&bufmem, 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); memb_free(&bufmem, buf);
#if QUEUEBUF_STATS #if QUEUEBUF_STATS
--queuebuf_len; --queuebuf_len;
@ -192,10 +440,10 @@ void
queuebuf_to_packetbuf(struct queuebuf *b) queuebuf_to_packetbuf(struct queuebuf *b)
{ {
struct queuebuf_ref *r; struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) { if(memb_inmemb(&bufmem, b)) {
packetbuf_copyfrom(b->data, b->len); struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
packetbuf_attr_copyfrom(b->attrs, b->addrs); packetbuf_copyfrom(buframptr->data, buframptr->len);
packetbuf_attr_copyfrom(buframptr->attrs, buframptr->addrs);
} else if(memb_inmemb(&refbufmem, b)) { } else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b; r = (struct queuebuf_ref *)b;
packetbuf_clear(); packetbuf_clear();
@ -209,9 +457,10 @@ void *
queuebuf_dataptr(struct queuebuf *b) queuebuf_dataptr(struct queuebuf *b)
{ {
struct queuebuf_ref *r; struct queuebuf_ref *r;
if(memb_inmemb(&bufmem, b)) { 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)) { } else if(memb_inmemb(&refbufmem, b)) {
r = (struct queuebuf_ref *)b; r = (struct queuebuf_ref *)b;
return r->ref; return r->ref;
@ -222,19 +471,22 @@ queuebuf_dataptr(struct queuebuf *b)
int int
queuebuf_datalen(struct queuebuf *b) queuebuf_datalen(struct queuebuf *b)
{ {
return b->len; struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
return buframptr->len;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
rimeaddr_t * rimeaddr_t *
queuebuf_addr(struct queuebuf *b, uint8_t type) 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 packetbuf_attr_t
queuebuf_attr(struct queuebuf *b, uint8_t type) 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 void

View File

@ -56,12 +56,30 @@
#include "net/packetbuf.h" #include "net/packetbuf.h"
/* QUEUEBUF_NUM is the total number of queuebuf */
#ifdef QUEUEBUF_CONF_NUM #ifdef QUEUEBUF_CONF_NUM
#define QUEUEBUF_NUM QUEUEBUF_CONF_NUM #define QUEUEBUF_NUM QUEUEBUF_CONF_NUM
#else #else
#define QUEUEBUF_NUM 8 #define QUEUEBUF_NUM 8
#endif #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 #ifdef QUEUEBUF_CONF_DEBUG
#define QUEUEBUF_DEBUG QUEUEBUF_CONF_DEBUG #define QUEUEBUF_DEBUG QUEUEBUF_CONF_DEBUG
#else /* 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_MAX_OPEN_FILES 6
#define COFFEE_FD_SET_SIZE 8 #define COFFEE_FD_SET_SIZE 8
#define COFFEE_LOG_TABLE_LIMIT 256 #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_LOG_SIZE 1024
#define COFFEE_IO_SEMANTICS 1 #define COFFEE_IO_SEMANTICS 1