Made optimizations explicit (and configurable). Added missing initialization of dutycycle protothread. Reduced default listen time and off time.

This commit is contained in:
adamdunkels 2009-04-03 11:45:06 +00:00
parent d936dc1d09
commit 1d86b01bfb

View File

@ -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.15 2009/03/31 17:39:54 adamdunkels Exp $ * $Id: lpp.c,v 1.16 2009/04/03 11:45:06 adamdunkels Exp $
*/ */
/** /**
@ -59,8 +59,10 @@
#include "net/mac/lpp.h" #include "net/mac/lpp.h"
#include "net/rime/packetbuf.h" #include "net/rime/packetbuf.h"
#include "net/rime/announcement.h" #include "net/rime/announcement.h"
#include "sys/compower.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define DEBUG 0 #define DEBUG 0
#if DEBUG #if DEBUG
@ -70,6 +72,9 @@
#define PRINTF(...) #define PRINTF(...)
#endif #endif
#define WITH_ACK_OPTIMIZATION 0
#define WITH_PROBE_AFTER_RECEPTION 0
#define WITH_PROBE_AFTER_TRANSMISSION 0
struct announcement_data { struct announcement_data {
uint16_t id; uint16_t id;
@ -92,22 +97,26 @@ struct lpp_hdr {
rimeaddr_t receiver; rimeaddr_t receiver;
}; };
static struct compower_activity current_packet;
static const struct radio_driver *radio; 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 dutycycle_pt;
static struct ctimer timer; static struct ctimer timer;
static uint8_t is_listening = 0; static uint8_t is_listening = 0;
#define LISTEN_TIME CLOCK_SECOND / 32 #define LISTEN_TIME CLOCK_SECOND / 128
#define OFF_TIME CLOCK_SECOND * 1 #define OFF_TIME CLOCK_SECOND / 2
#define PACKET_LIFETIME (LISTEN_TIME + OFF_TIME) #define PACKET_LIFETIME (LISTEN_TIME + OFF_TIME)
#define UNICAST_TIMEOUT 2 * PACKET_LIFETIME #define UNICAST_TIMEOUT 2 * PACKET_LIFETIME
#define PROBE_AFTER_TRANSMISSION_TIME LISTEN_TIME * 2
struct queue_list_item { struct queue_list_item {
struct queue_list_item *next; struct queue_list_item *next;
struct queuebuf *packet; struct queuebuf *packet;
struct ctimer timer; struct ctimer timer;
struct compower_activity compower;
}; };
#ifdef QUEUEBUF_CONF_NUM #ifdef QUEUEBUF_CONF_NUM
@ -142,12 +151,14 @@ remove_queued_packet(void *item)
ctimer_stop(&i->timer); ctimer_stop(&i->timer);
queuebuf_free(i->packet); queuebuf_free(i->packet);
list_remove(queued_packets_list, i); list_remove(queued_packets_list, i);
memb_free(&queued_packets_memb, i);
/* XXX potential optimization */ /* XXX potential optimization */
if(list_length(queued_packets_list) == 0 && is_listening == 0) { if(list_length(queued_packets_list) == 0 && is_listening == 0) {
turn_radio_off(); turn_radio_off();
compower_accumulate(&i->compower);
} }
memb_free(&queued_packets_memb, i);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -192,46 +203,71 @@ send_probe(void)
/* PRINTF("Sending probe\n");*/ /* PRINTF("Sending probe\n");*/
radio->send(packetbuf_hdrptr(), packetbuf_totlen()); radio->send(packetbuf_hdrptr(), packetbuf_totlen());
compower_accumulate(&compower_idle_activity);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** /**
* Duty cycle the radio. The protothread is driven by a ctimer that is * Duty cycle the radio and send probes. This function is called
* initiated in the lpp_init() function. * repeatedly by a ctimer. The function restart_dutycycle() is used to
* (re)start the duty cycling.
*/ */
static int static int
dutycycle(void *ptr) dutycycle(void *ptr)
{ {
struct ctimer *t = ptr; struct ctimer *t = ptr;
PT_BEGIN(&pt); PT_BEGIN(&dutycycle_pt);
while(1) { while(1) {
turn_radio_on();
send_probe();
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
PT_YIELD(&pt);
/* Send a probe packet. */
send_probe();
/* Turn on the radio for a while in anticipation of a data packet
from a neighbor. */
turn_radio_on();
/* Set a timer so that we keep the radio on for LISTEN_TIME. */
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
PT_YIELD(&dutycycle_pt);
/* If we have no packets to send (indicated by the list length of
queued_packets_list being zero), we should turn the radio
off. Othersize, we keep the radio on. */
if(list_length(queued_packets_list) == 0) { if(list_length(queued_packets_list) == 0) {
/* If we are not listening for announcements, we turn the radio
off and wait until we send the next probe. */
if(is_listening == 0) { if(is_listening == 0) {
turn_radio_off(); turn_radio_off();
compower_accumulate(&compower_idle_activity);
/* 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, OFF_TIME / 2 + (random_rand() % (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(&dutycycle_pt);
} else { } else {
is_listening--; is_listening--;
ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t); ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
PT_YIELD(&pt); PT_YIELD(&dutycycle_pt);
} }
} else { } else {
ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t); ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
PT_YIELD(&pt); PT_YIELD(&dutycycle_pt);
} }
} }
PT_END(&pt); PT_END(&dutycycle_pt);
}
/*---------------------------------------------------------------------------*/
static void
restart_dutycycle(clock_time_t initial_wait)
{
PT_INIT(&dutycycle_pt);
ctimer_set(&timer, initial_wait, (void (*)(void *))dutycycle, &timer);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** /**
@ -266,12 +302,7 @@ send_packet(void)
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
hdr.receiver.u8[0], hdr.receiver.u8[1], hdr.receiver.u8[0], hdr.receiver.u8[1],
packetbuf_attr(PACKETBUF_ATTR_CHANNEL)); packetbuf_attr(PACKETBUF_ATTR_CHANNEL));
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) { {
/* Immediately send ACKs - we're assuming that the other node is
listening. */
/* printf("Immediately sending ACK\n");*/
return radio->send(packetbuf_hdrptr(), packetbuf_totlen());
} else {
struct queue_list_item *i; struct queue_list_item *i;
i = memb_alloc(&queued_packets_memb); i = memb_alloc(&queued_packets_memb);
if(i != NULL) { if(i != NULL) {
@ -286,7 +317,10 @@ send_packet(void)
timeout = PACKET_LIFETIME; timeout = PACKET_LIFETIME;
} }
ctimer_set(&i->timer, timeout, remove_queued_packet, i); ctimer_set(&i->timer, timeout, remove_queued_packet, i);
/* Wait for a probe packet from a neighbor */
/* Wait for a probe packet from a neighbor. The actual packet
transmission is handled by the read_packet() function,
which receives the probe from the neighbor. */
turn_radio_on(); turn_radio_on();
} }
} }
@ -308,7 +342,7 @@ read_packet(void)
packetbuf_clear(); packetbuf_clear();
len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE); len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(len > 0) { if(len > sizeof(struct lpp_hdr)) {
packetbuf_set_datalen(len); packetbuf_set_datalen(len);
hdr = packetbuf_dataptr(); hdr = packetbuf_dataptr();
packetbuf_hdrreduce(sizeof(struct lpp_hdr)); packetbuf_hdrreduce(sizeof(struct lpp_hdr));
@ -345,9 +379,14 @@ read_packet(void)
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]);
queuebuf_to_packetbuf(i->packet);
radio->send(queuebuf_dataptr(i->packet), radio->send(queuebuf_dataptr(i->packet),
queuebuf_datalen(i->packet)); queuebuf_datalen(i->packet));
/* Attribute the energy spent on listening for the probe
to this packet transmission. */
compower_accumulate(&i->compower);
/* If the packet was not a broadcast packet, we dequeue it /* If the packet was not a broadcast packet, we dequeue it
now. Broadcast packets should be transmitted to all now. Broadcast packets should be transmitted to all
@ -355,13 +394,21 @@ read_packet(void)
instead, after the appropriate time. */ instead, after the appropriate time. */
if(!rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) { if(!rimeaddr_cmp(&qhdr->receiver, &rimeaddr_null)) {
remove_queued_packet(i); remove_queued_packet(i);
#if WITH_PROBE_AFTER_TRANSMISSION
/* Send a probe packet to catch any reply from the other node. */
restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);
#endif /* WITH_PROBE_AFTER_TRANSMISSION */
} }
#if WITH_ACK_OPTIMIZATION
turn_radio_on(); /* XXX Awaiting an ACK: we should check the if(packetbuf_attr(PACKETBUF_ATTR_RELIABLE)) {
packet type of the queued packet to see /* We're sending a packet that needs an ACK, so we keep
if it is a data packet. If not, we the radio on in anticipation of the ACK. */
should not turn the radio on. */ turn_radio_on();
}
#endif /* WITH_ACK_OPTIMIZATION */
} }
} }
} }
@ -370,7 +417,20 @@ read_packet(void)
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]);
/* Accumulate the power consumption for the packet reception. */
compower_accumulate(&current_packet);
/* Convert the accumulated power consumption for the received
packet to packet attributes so that the higher levels can
keep track of the amount of energy spent on receiving the
packet. */
compower_attrconv(&current_packet);
/* Clear the accumulated power consumption so that it is ready
for the next packet. */
compower_clear(&current_packet);
#if WITH_PROBE_AFTER_RECEPTION
/* XXX send probe after receiving a packet to facilitate data /* XXX send probe after receiving a packet to facilitate data
streaming. We must first copy the contents of the packetbuf into streaming. We must first copy the contents of the packetbuf into
a queuebuf to avoid overwriting the data with the probe packet. */ a queuebuf to avoid overwriting the data with the probe packet. */
@ -383,7 +443,9 @@ read_packet(void)
queuebuf_free(q); queuebuf_free(q);
} }
} }
#endif /* WITH_PROBE_AFTER_RECEPTION */
} }
len = packetbuf_datalen(); len = packetbuf_datalen();
} }
return len; return len;
@ -435,7 +497,7 @@ 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, LISTEN_TIME, (void (*)(void *))dutycycle, &timer); restart_dutycycle(LISTEN_TIME);
announcement_register_listen_callback(listen_callback); announcement_register_listen_callback(listen_callback);