improvements to lpp based on code from Adam and discussions with Thiemo.
* queue multiple packets * send a strobe back immediately after receiving a data packet * double the packet lifetime to allow for a missed probe
This commit is contained in:
parent
e90149b7b4
commit
dd082f7fcf
@ -28,7 +28,7 @@
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* $Id: lpp.c,v 1.11 2009/03/26 12:50:57 nvt-se Exp $
|
||||
* $Id: lpp.c,v 1.12 2009/03/31 12:47:00 nvt-se Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -51,6 +51,8 @@
|
||||
*/
|
||||
|
||||
#include "dev/leds.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/memb.h"
|
||||
#include "lib/random.h"
|
||||
#include "net/rime.h"
|
||||
#include "net/mac/mac.h"
|
||||
@ -94,28 +96,27 @@ static const struct radio_driver *radio;
|
||||
static void (* receiver_callback)(const struct mac_driver *);
|
||||
static struct pt pt;
|
||||
static struct ctimer timer;
|
||||
static struct timer packet_lifetime_timer;
|
||||
|
||||
static struct queuebuf *queued_packet;
|
||||
|
||||
static uint8_t is_listening = 0;
|
||||
|
||||
#ifdef LPP_CONF_LISTEN_TIME
|
||||
#define LPP_LISTEN_TIME LPP_CONF_LISTEN_TIME
|
||||
#else
|
||||
#define LPP_LISTEN_TIME CLOCK_SECOND / 64
|
||||
#endif /* LPP_CONF_LISTEN_TIME */
|
||||
#define LISTEN_TIME CLOCK_SECOND / 32
|
||||
#define OFF_TIME CLOCK_SECOND * 1
|
||||
#define PACKET_LIFETIME 2 * (LISTEN_TIME + OFF_TIME)
|
||||
|
||||
#ifdef LPP_CONF_OFF_TIME
|
||||
#define LPP_OFF_TIME LPP_CONF_OFF_TIME
|
||||
#else
|
||||
#define LPP_OFF_TIME CLOCK_SECOND * 1
|
||||
#endif /* LPP_CONF_OFF_TIME */
|
||||
struct queue_list_item {
|
||||
struct queue_list_item *next;
|
||||
struct queuebuf *packet;
|
||||
struct ctimer timer;
|
||||
};
|
||||
|
||||
#define PACKET_LIFETIME LPP_LISTEN_TIME + LPP_OFF_TIME
|
||||
|
||||
#define DUMP_QUEUED_PACKET 0
|
||||
#ifdef QUEUEBUF_CONF_NUM
|
||||
#define MAX_QUEUED_PACKETS QUEUEBUF_CONF_NUM / 2
|
||||
#else /* QUEUEBUF_CONF_NUM */
|
||||
#define MAX_QUEUED_PACKETS 4
|
||||
#endif /* QUEUEBUF_CONF_NUM */
|
||||
|
||||
LIST(queued_packets_list);
|
||||
MEMB(queued_packets_memb, struct queue_list_item, MAX_QUEUED_PACKETS);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
@ -133,10 +134,18 @@ turn_radio_off(void)
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
remove_queued_packet(void)
|
||||
remove_queued_packet(void *item)
|
||||
{
|
||||
queuebuf_free(queued_packet);
|
||||
queued_packet = NULL;
|
||||
struct queue_list_item *i = item;
|
||||
|
||||
queuebuf_free(i->packet);
|
||||
list_remove(queued_packets_list, i);
|
||||
memb_free(&queued_packets_memb, i);
|
||||
|
||||
/* XXX potential optimization */
|
||||
if(list_length(queued_packets_list) == 0 && is_listening == 0) {
|
||||
turn_radio_off();
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
@ -197,31 +206,25 @@ dutycycle(void *ptr)
|
||||
while(1) {
|
||||
turn_radio_on();
|
||||
send_probe();
|
||||
ctimer_set(t, LPP_LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
||||
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
||||
PT_YIELD(&pt);
|
||||
|
||||
if(queued_packet == NULL) {
|
||||
/* if(queued_packet == NULL) {*/
|
||||
if(list_length(queued_packets_list) == 0) {
|
||||
if(is_listening == 0) {
|
||||
turn_radio_off();
|
||||
/* There is a bit of randomness here right now to avoid collisions
|
||||
due to synchronization effects. Not sure how needed it is
|
||||
though. XXX */
|
||||
ctimer_set(t, LPP_OFF_TIME / 2 + (random_rand() % (LPP_OFF_TIME / 2)),
|
||||
ctimer_set(t, OFF_TIME / 2 + (random_rand() % (OFF_TIME / 2)),
|
||||
(void (*)(void *))dutycycle, t);
|
||||
PT_YIELD(&pt);
|
||||
} else {
|
||||
is_listening--;
|
||||
ctimer_set(t, LPP_OFF_TIME,
|
||||
ctimer_set(t, OFF_TIME,
|
||||
(void (*)(void *))dutycycle, t);
|
||||
PT_YIELD(&pt);
|
||||
}
|
||||
} else {
|
||||
/* We are currently sending a packet so we should keep the radio
|
||||
turned on and not send any probes at this point. */
|
||||
ctimer_set(t, PACKET_LIFETIME, (void (*)(void *))dutycycle, t);
|
||||
PT_YIELD(&pt);
|
||||
remove_queued_packet();
|
||||
PRINTF("Removing old packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,25 +269,21 @@ send_packet(void)
|
||||
/* printf("Immediately sending ACK\n");*/
|
||||
return radio->send(packetbuf_hdrptr(), packetbuf_totlen());
|
||||
} else {
|
||||
struct queue_list_item *i;
|
||||
i = memb_alloc(&queued_packets_memb);
|
||||
if(i != NULL) {
|
||||
i->packet = queuebuf_new_from_packetbuf();
|
||||
if(i->packet == NULL) {
|
||||
memb_free(&queued_packets_memb, i);
|
||||
return 0;
|
||||
} else {
|
||||
list_add(queued_packets_list, i);
|
||||
ctimer_set(&i->timer, PACKET_LIFETIME, remove_queued_packet, i);
|
||||
|
||||
/* If a packet is already queued, the DUMP_QUEUED_PACKET option
|
||||
determines if the queued packet should be replaced with the new
|
||||
packet, or if the new packet should be dropped. XXX haven't
|
||||
measured the effect of this option */
|
||||
#if DUMP_QUEUED_PACKET
|
||||
if(queued_packet != NULL) {
|
||||
remove_queued_packet();
|
||||
/* Wait for a probe packet from a neighbor */
|
||||
turn_radio_on();
|
||||
}
|
||||
}
|
||||
queued_packet = queuebuf_new_from_packetbuf();
|
||||
#else /* DUMP_QUEUED_PACKET */
|
||||
if(queued_packet == NULL) {
|
||||
queued_packet = queuebuf_new_from_packetbuf();
|
||||
}
|
||||
#endif /* DUMP_QUEUED_PACKET */
|
||||
|
||||
timer_set(&packet_lifetime_timer, PACKET_LIFETIME);
|
||||
/* Wait for a probe packet from a neighbor */
|
||||
turn_radio_on();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -299,7 +298,7 @@ static int
|
||||
read_packet(void)
|
||||
{
|
||||
int len;
|
||||
struct lpp_hdr *hdr, *qhdr;
|
||||
struct lpp_hdr *hdr;
|
||||
|
||||
packetbuf_clear();
|
||||
len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
|
||||
@ -327,43 +326,57 @@ read_packet(void)
|
||||
adata->data[i].id,
|
||||
adata->data[i].value);
|
||||
}
|
||||
|
||||
/* Check if the outbound packet has been waiting too long in the
|
||||
queue. If so, we remove the packet from the queue. */
|
||||
if(queued_packet != NULL && timer_expired(&packet_lifetime_timer)) {
|
||||
remove_queued_packet();
|
||||
}
|
||||
if(queued_packet != NULL) {
|
||||
qhdr = queuebuf_dataptr(queued_packet);
|
||||
if(rimeaddr_cmp(&qhdr->receiver, &hdr->sender) ||
|
||||
rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
||||
PRINTF("%d.%d: got a probe from %d.%d, sending packet to %d.%d\n",
|
||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
||||
hdr->sender.u8[0], hdr->sender.u8[1],
|
||||
qhdr->receiver.u8[0], qhdr->receiver.u8[1]);
|
||||
|
||||
if(list_length(queued_packets_list) > 0) {
|
||||
struct queue_list_item *i;
|
||||
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
||||
struct lpp_hdr *qhdr;
|
||||
|
||||
qhdr = queuebuf_dataptr(i->packet);
|
||||
if(rimeaddr_cmp(&qhdr->receiver, &hdr->sender) ||
|
||||
rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
||||
PRINTF("%d.%d: got a probe from %d.%d, sending packet to %d.%d\n",
|
||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
||||
hdr->sender.u8[0], hdr->sender.u8[1],
|
||||
qhdr->receiver.u8[0], qhdr->receiver.u8[1]);
|
||||
|
||||
radio->send(queuebuf_dataptr(queued_packet),
|
||||
queuebuf_datalen(queued_packet));
|
||||
radio->send(queuebuf_dataptr(i->packet),
|
||||
queuebuf_datalen(i->packet));
|
||||
|
||||
/* If the packet was not a broadcast packet, we dequeue it
|
||||
now. Broadcast packets should be transmitted to all
|
||||
neighbors, and are dequeued by the dutycycling function
|
||||
instead, after the appropriate time. */
|
||||
if(!rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
||||
remove_queued_packet(i);
|
||||
}
|
||||
|
||||
|
||||
turn_radio_on(); /* XXX Awaiting an ACK: we should check the
|
||||
packet type of the queued packet to see
|
||||
if it is a data packet. If not, we
|
||||
should not turn the radio on. */
|
||||
|
||||
/* If the packet was not a broadcast packet, we dequeue it
|
||||
now. Broadcast packets should be transmitted to all
|
||||
neighbors, and are dequeued by the dutycycling function
|
||||
instead, after the appropriate time. */
|
||||
if(!rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
||||
remove_queued_packet();
|
||||
}
|
||||
|
||||
|
||||
turn_radio_on(); /* XXX Awaiting an ACK: we should check the
|
||||
packet type of the queued packet to see
|
||||
if it is a data packet. If not, we
|
||||
should not turn the radio on. */
|
||||
}
|
||||
}
|
||||
|
||||
} else if(hdr->type == TYPE_DATA) {
|
||||
PRINTF("%d.%d: got data from %d.%d\n",
|
||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
||||
hdr->sender.u8[0], hdr->sender.u8[1]);
|
||||
|
||||
/* XXX send probe after receiving a packet to facilitate data
|
||||
streaming. We must first copy the contents of the packetbuf into
|
||||
a queuebuf to avoid overwriting the data with the probe packet. */
|
||||
|
||||
struct queuebuf *q;
|
||||
q = queuebuf_new_from_packetbuf();
|
||||
if(q != NULL) {
|
||||
send_probe();
|
||||
queuebuf_to_packetbuf(q);
|
||||
queuebuf_free(q);
|
||||
}
|
||||
}
|
||||
len = packetbuf_datalen();
|
||||
}
|
||||
@ -416,10 +429,12 @@ lpp_init(const struct radio_driver *d)
|
||||
{
|
||||
radio = d;
|
||||
radio->set_receive_function(input_packet);
|
||||
ctimer_set(&timer, LPP_LISTEN_TIME, (void (*)(void *))dutycycle, &timer);
|
||||
ctimer_set(&timer, LISTEN_TIME, (void (*)(void *))dutycycle, &timer);
|
||||
|
||||
announcement_register_listen_callback(listen_callback);
|
||||
|
||||
|
||||
memb_init(&queued_packets_memb);
|
||||
list_init(queued_packets_list);
|
||||
return &lpp_driver;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
Loading…
Reference in New Issue
Block a user