Added bursts support in CSMA/ContikiMAC, and CFS-swapping in
queuebuf. Exemplified in examples/udp-stream.
This commit is contained in:
parent
5b1d9617c4
commit
dd8576830e
|
@ -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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
14
examples/udp-stream/Makefile
Normal file
14
examples/udp-stream/Makefile
Normal 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
|
21
examples/udp-stream/README
Normal file
21
examples/udp-stream/README
Normal 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
|
53
examples/udp-stream/project-conf.h
Normal file
53
examples/udp-stream/project-conf.h
Normal 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__ */
|
204
examples/udp-stream/udp-stream.c
Normal file
204
examples/udp-stream/udp-stream.c
Normal 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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
182
examples/udp-stream/udp-stream.csc
Normal file
182
examples/udp-stream/udp-stream.csc
Normal 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>
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue