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.
|
* 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 "dev/leds.h"
|
||||||
|
#include "lib/list.h"
|
||||||
|
#include "lib/memb.h"
|
||||||
#include "lib/random.h"
|
#include "lib/random.h"
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
#include "net/mac/mac.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 void (* receiver_callback)(const struct mac_driver *);
|
||||||
static struct pt pt;
|
static struct pt pt;
|
||||||
static struct ctimer timer;
|
static struct ctimer timer;
|
||||||
static struct timer packet_lifetime_timer;
|
|
||||||
|
|
||||||
static struct queuebuf *queued_packet;
|
|
||||||
|
|
||||||
static uint8_t is_listening = 0;
|
static uint8_t is_listening = 0;
|
||||||
|
|
||||||
#ifdef LPP_CONF_LISTEN_TIME
|
#define LISTEN_TIME CLOCK_SECOND / 32
|
||||||
#define LPP_LISTEN_TIME LPP_CONF_LISTEN_TIME
|
#define OFF_TIME CLOCK_SECOND * 1
|
||||||
#else
|
#define PACKET_LIFETIME 2 * (LISTEN_TIME + OFF_TIME)
|
||||||
#define LPP_LISTEN_TIME CLOCK_SECOND / 64
|
|
||||||
#endif /* LPP_CONF_LISTEN_TIME */
|
|
||||||
|
|
||||||
#ifdef LPP_CONF_OFF_TIME
|
struct queue_list_item {
|
||||||
#define LPP_OFF_TIME LPP_CONF_OFF_TIME
|
struct queue_list_item *next;
|
||||||
#else
|
struct queuebuf *packet;
|
||||||
#define LPP_OFF_TIME CLOCK_SECOND * 1
|
struct ctimer timer;
|
||||||
#endif /* LPP_CONF_OFF_TIME */
|
};
|
||||||
|
|
||||||
#define PACKET_LIFETIME LPP_LISTEN_TIME + LPP_OFF_TIME
|
#ifdef QUEUEBUF_CONF_NUM
|
||||||
|
#define MAX_QUEUED_PACKETS QUEUEBUF_CONF_NUM / 2
|
||||||
#define DUMP_QUEUED_PACKET 0
|
#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
|
static void
|
||||||
@ -133,10 +134,18 @@ turn_radio_off(void)
|
|||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
remove_queued_packet(void)
|
remove_queued_packet(void *item)
|
||||||
{
|
{
|
||||||
queuebuf_free(queued_packet);
|
struct queue_list_item *i = item;
|
||||||
queued_packet = NULL;
|
|
||||||
|
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
|
static void
|
||||||
@ -197,31 +206,25 @@ dutycycle(void *ptr)
|
|||||||
while(1) {
|
while(1) {
|
||||||
turn_radio_on();
|
turn_radio_on();
|
||||||
send_probe();
|
send_probe();
|
||||||
ctimer_set(t, LPP_LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&pt);
|
PT_YIELD(&pt);
|
||||||
|
|
||||||
if(queued_packet == NULL) {
|
/* if(queued_packet == NULL) {*/
|
||||||
|
if(list_length(queued_packets_list) == 0) {
|
||||||
if(is_listening == 0) {
|
if(is_listening == 0) {
|
||||||
turn_radio_off();
|
turn_radio_off();
|
||||||
/* There is a bit of randomness here right now to avoid collisions
|
/* There is a bit of randomness here right now to avoid collisions
|
||||||
due to synchronization effects. Not sure how needed it is
|
due to synchronization effects. Not sure how needed it is
|
||||||
though. XXX */
|
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);
|
(void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&pt);
|
PT_YIELD(&pt);
|
||||||
} else {
|
} else {
|
||||||
is_listening--;
|
is_listening--;
|
||||||
ctimer_set(t, LPP_OFF_TIME,
|
ctimer_set(t, OFF_TIME,
|
||||||
(void (*)(void *))dutycycle, t);
|
(void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&pt);
|
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");*/
|
/* printf("Immediately sending ACK\n");*/
|
||||||
return radio->send(packetbuf_hdrptr(), packetbuf_totlen());
|
return radio->send(packetbuf_hdrptr(), packetbuf_totlen());
|
||||||
} else {
|
} 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
|
/* Wait for a probe packet from a neighbor */
|
||||||
determines if the queued packet should be replaced with the new
|
turn_radio_on();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -299,7 +298,7 @@ static int
|
|||||||
read_packet(void)
|
read_packet(void)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
struct lpp_hdr *hdr, *qhdr;
|
struct lpp_hdr *hdr;
|
||||||
|
|
||||||
packetbuf_clear();
|
packetbuf_clear();
|
||||||
len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
|
len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
|
||||||
@ -327,43 +326,57 @@ read_packet(void)
|
|||||||
adata->data[i].id,
|
adata->data[i].id,
|
||||||
adata->data[i].value);
|
adata->data[i].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the outbound packet has been waiting too long in the
|
if(list_length(queued_packets_list) > 0) {
|
||||||
queue. If so, we remove the packet from the queue. */
|
struct queue_list_item *i;
|
||||||
if(queued_packet != NULL && timer_expired(&packet_lifetime_timer)) {
|
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
||||||
remove_queued_packet();
|
struct lpp_hdr *qhdr;
|
||||||
}
|
|
||||||
if(queued_packet != NULL) {
|
qhdr = queuebuf_dataptr(i->packet);
|
||||||
qhdr = queuebuf_dataptr(queued_packet);
|
if(rimeaddr_cmp(&qhdr->receiver, &hdr->sender) ||
|
||||||
if(rimeaddr_cmp(&qhdr->receiver, &hdr->sender) ||
|
rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
||||||
rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
|
PRINTF("%d.%d: got a probe from %d.%d, sending packet to %d.%d\n",
|
||||||
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],
|
||||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
hdr->sender.u8[0], hdr->sender.u8[1],
|
||||||
hdr->sender.u8[0], hdr->sender.u8[1],
|
qhdr->receiver.u8[0], qhdr->receiver.u8[1]);
|
||||||
qhdr->receiver.u8[0], qhdr->receiver.u8[1]);
|
|
||||||
|
|
||||||
radio->send(queuebuf_dataptr(queued_packet),
|
radio->send(queuebuf_dataptr(i->packet),
|
||||||
queuebuf_datalen(queued_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) {
|
} else if(hdr->type == TYPE_DATA) {
|
||||||
PRINTF("%d.%d: got data from %d.%d\n",
|
PRINTF("%d.%d: got data from %d.%d\n",
|
||||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
||||||
hdr->sender.u8[0], hdr->sender.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();
|
len = packetbuf_datalen();
|
||||||
}
|
}
|
||||||
@ -416,10 +429,12 @@ lpp_init(const struct radio_driver *d)
|
|||||||
{
|
{
|
||||||
radio = d;
|
radio = d;
|
||||||
radio->set_receive_function(input_packet);
|
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);
|
announcement_register_listen_callback(listen_callback);
|
||||||
|
|
||||||
|
memb_init(&queued_packets_memb);
|
||||||
|
list_init(queued_packets_list);
|
||||||
return &lpp_driver;
|
return &lpp_driver;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
Loading…
Reference in New Issue
Block a user