Added an optimization option that avoids multiple simultaneous broadcasts from neighbors: when a broadcast is to be sent, a sender does not send until it knows that no other nodes are broadcasting.
This commit is contained in:
parent
fe30886b37
commit
fe5a1f1068
1 changed files with 158 additions and 17 deletions
|
@ -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.21 2009/05/06 15:06:38 adamdunkels Exp $
|
* $Id: lpp.c,v 1.22 2009/05/10 21:09:05 adamdunkels Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +78,7 @@
|
||||||
#define WITH_PROBE_AFTER_TRANSMISSION 0
|
#define WITH_PROBE_AFTER_TRANSMISSION 0
|
||||||
#define WITH_ENCOUNTER_OPTIMIZATION 1
|
#define WITH_ENCOUNTER_OPTIMIZATION 1
|
||||||
#define WITH_ADAPTIVE_OFF_TIME 0
|
#define WITH_ADAPTIVE_OFF_TIME 0
|
||||||
|
#define WITH_PENDING_BROADCAST 1
|
||||||
|
|
||||||
#ifdef LPP_CONF_LISTEN_TIME
|
#ifdef LPP_CONF_LISTEN_TIME
|
||||||
#define LISTEN_TIME LPP_CONF_LISTEN_TIME
|
#define LISTEN_TIME LPP_CONF_LISTEN_TIME
|
||||||
|
@ -150,10 +151,17 @@ static clock_time_t off_time = OFF_TIME;
|
||||||
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 removal_timer;
|
||||||
struct compower_activity compower;
|
struct compower_activity compower;
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
uint8_t broadcast_flag;
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BROADCAST_FLAG_NONE 0
|
||||||
|
#define BROADCAST_FLAG_WAITING 1
|
||||||
|
#define BROADCAST_FLAG_PENDING 2
|
||||||
|
#define BROADCAST_FLAG_SEND 3
|
||||||
|
|
||||||
LIST(pending_packets_list);
|
LIST(pending_packets_list);
|
||||||
LIST(queued_packets_list);
|
LIST(queued_packets_list);
|
||||||
|
@ -250,9 +258,11 @@ turn_radio_on_for_neighbor(rimeaddr_t *neighbor, struct queue_list_item *i)
|
||||||
struct encounter *e;
|
struct encounter *e;
|
||||||
|
|
||||||
if(rimeaddr_cmp(neighbor, &rimeaddr_null)) {
|
if(rimeaddr_cmp(neighbor, &rimeaddr_null)) {
|
||||||
|
#if ! WITH_PENDING_BROADCAST
|
||||||
/* We have been asked to turn on the radio for a broadcast, so we
|
/* We have been asked to turn on the radio for a broadcast, so we
|
||||||
just turn on the radio. */
|
just turn on the radio. */
|
||||||
turn_radio_on();
|
turn_radio_on();
|
||||||
|
#endif /* ! WITH_PENDING_BROADCAST */
|
||||||
list_add(queued_packets_list, i);
|
list_add(queued_packets_list, i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -313,7 +323,7 @@ remove_queued_packet(void *item)
|
||||||
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]);
|
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]);
|
||||||
|
|
||||||
|
|
||||||
ctimer_stop(&i->timer);
|
ctimer_stop(&i->removal_timer);
|
||||||
queuebuf_free(i->packet);
|
queuebuf_free(i->packet);
|
||||||
list_remove(pending_packets_list, i);
|
list_remove(pending_packets_list, i);
|
||||||
list_remove(queued_packets_list, i);
|
list_remove(queued_packets_list, i);
|
||||||
|
@ -327,6 +337,15 @@ remove_queued_packet(void *item)
|
||||||
memb_free(&queued_packets_memb, i);
|
memb_free(&queued_packets_memb, i);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
static void
|
||||||
|
set_broadcast_flag(struct queue_list_item *i, uint8_t flag)
|
||||||
|
{
|
||||||
|
i->broadcast_flag = flag;
|
||||||
|
ctimer_set(&i->removal_timer, PACKET_LIFETIME, remove_queued_packet, i);
|
||||||
|
}
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
listen_callback(int periods)
|
listen_callback(int periods)
|
||||||
{
|
{
|
||||||
|
@ -379,6 +398,25 @@ send_probe(void)
|
||||||
compower_accumulate(&compower_idle_activity);
|
compower_accumulate(&compower_idle_activity);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
num_packets_to_send(void)
|
||||||
|
{
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
struct queue_list_item *i;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
||||||
|
if(i->broadcast_flag == BROADCAST_FLAG_SEND ||
|
||||||
|
i->broadcast_flag == BROADCAST_FLAG_NONE) {
|
||||||
|
++num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
#else /* WITH_PENDING_BROADCAST */
|
||||||
|
return list_length(queued_packets_list);
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* Duty cycle the radio and send probes. This function is called
|
* Duty cycle the radio and send probes. This function is called
|
||||||
* repeatedly by a ctimer. The function restart_dutycycle() is used to
|
* repeatedly by a ctimer. The function restart_dutycycle() is used to
|
||||||
|
@ -393,6 +431,22 @@ dutycycle(void *ptr)
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
{
|
||||||
|
struct queue_list_item *p;
|
||||||
|
/* Before sending the probe, we mark all broadcast packets in
|
||||||
|
our output queue to be pending. This means that they are
|
||||||
|
ready to be sent, once we know that no neighbor is
|
||||||
|
currently broadcasting. */
|
||||||
|
for(p = list_head(queued_packets_list); p != NULL; p = p->next) {
|
||||||
|
if(p->broadcast_flag == BROADCAST_FLAG_WAITING) {
|
||||||
|
PRINTF("wait -> pending\n");
|
||||||
|
set_broadcast_flag(p, BROADCAST_FLAG_PENDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
|
||||||
/* Send a probe packet. */
|
/* Send a probe packet. */
|
||||||
send_probe();
|
send_probe();
|
||||||
|
|
||||||
|
@ -404,11 +458,28 @@ dutycycle(void *ptr)
|
||||||
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&dutycycle_pt);
|
PT_YIELD(&dutycycle_pt);
|
||||||
|
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
{
|
||||||
|
struct queue_list_item *p;
|
||||||
|
/* Go through the list of packets we are waiting to send, and
|
||||||
|
check if there are any pending broadcasts in the list. If
|
||||||
|
there are pending broadcasts, and we did not receive any
|
||||||
|
broadcast packets from a neighbor in response to our probe,
|
||||||
|
we mark the broadcasts as being ready to send. */
|
||||||
|
for(p = list_head(queued_packets_list); p != NULL; p = p->next) {
|
||||||
|
if(p->broadcast_flag == BROADCAST_FLAG_PENDING) {
|
||||||
|
PRINTF("pending -> send\n");
|
||||||
|
set_broadcast_flag(p, BROADCAST_FLAG_SEND);
|
||||||
|
turn_radio_on();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
|
||||||
/* If we have no packets to send (indicated by the list length of
|
/* If we have no packets to send (indicated by the list length of
|
||||||
queued_packets_list being zero), we should turn the radio
|
queued_packets_list being zero), we should turn the radio
|
||||||
off. Othersize, we keep the radio on. */
|
off. Othersize, we keep the radio on. */
|
||||||
|
if(num_packets_to_send() == 0) {
|
||||||
if(list_length(queued_packets_list) == 0) {
|
|
||||||
|
|
||||||
/* If we are not listening for announcements, we turn the radio
|
/* If we are not listening for announcements, we turn the radio
|
||||||
off and wait until we send the next probe. */
|
off and wait until we send the next probe. */
|
||||||
|
@ -427,11 +498,15 @@ dutycycle(void *ptr)
|
||||||
#endif /* WITH_ADAPTIVE_OFF_TIME */
|
#endif /* WITH_ADAPTIVE_OFF_TIME */
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
/* We are listening for annonucements, so we count down the
|
||||||
|
listen time, and keep the radio on. */
|
||||||
is_listening--;
|
is_listening--;
|
||||||
ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
|
ctimer_set(t, OFF_TIME, (void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&dutycycle_pt);
|
PT_YIELD(&dutycycle_pt);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* We had pending packets to send, so we do not turn the radio off. */
|
||||||
|
|
||||||
ctimer_set(t, off_time, (void (*)(void *))dutycycle, t);
|
ctimer_set(t, off_time, (void (*)(void *))dutycycle, t);
|
||||||
PT_YIELD(&dutycycle_pt);
|
PT_YIELD(&dutycycle_pt);
|
||||||
}
|
}
|
||||||
|
@ -466,9 +541,13 @@ send_packet(void)
|
||||||
{
|
{
|
||||||
struct lpp_hdr hdr;
|
struct lpp_hdr hdr;
|
||||||
clock_time_t timeout;
|
clock_time_t timeout;
|
||||||
|
uint8_t is_broadcast = 0;
|
||||||
|
|
||||||
rimeaddr_copy(&hdr.sender, &rimeaddr_node_addr);
|
rimeaddr_copy(&hdr.sender, &rimeaddr_node_addr);
|
||||||
rimeaddr_copy(&hdr.receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
rimeaddr_copy(&hdr.receiver, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
|
||||||
|
if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
|
||||||
|
is_broadcast = 1;
|
||||||
|
}
|
||||||
hdr.type = TYPE_DATA;
|
hdr.type = TYPE_DATA;
|
||||||
|
|
||||||
packetbuf_hdralloc(sizeof(struct lpp_hdr));
|
packetbuf_hdralloc(sizeof(struct lpp_hdr));
|
||||||
|
@ -491,7 +570,7 @@ send_packet(void)
|
||||||
off_time = LOWEST_OFF_TIME;
|
off_time = LOWEST_OFF_TIME;
|
||||||
restart_dutycycle(off_time);
|
restart_dutycycle(off_time);
|
||||||
#endif /* WITH_ADAPTIVE_OFF_TIME */
|
#endif /* WITH_ADAPTIVE_OFF_TIME */
|
||||||
|
|
||||||
{
|
{
|
||||||
struct queue_list_item *i;
|
struct queue_list_item *i;
|
||||||
i = memb_alloc(&queued_packets_memb);
|
i = memb_alloc(&queued_packets_memb);
|
||||||
|
@ -501,17 +580,33 @@ send_packet(void)
|
||||||
memb_free(&queued_packets_memb, i);
|
memb_free(&queued_packets_memb, i);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
if(is_broadcast) {
|
||||||
timeout = UNICAST_TIMEOUT;
|
|
||||||
if(rimeaddr_cmp(&hdr.receiver, &rimeaddr_null)) {
|
|
||||||
timeout = PACKET_LIFETIME;
|
timeout = PACKET_LIFETIME;
|
||||||
}
|
#if WITH_PENDING_BROADCAST
|
||||||
ctimer_set(&i->timer, timeout, remove_queued_packet, i);
|
/* We set the broadcast state of the packet to be
|
||||||
|
waiting. This means that the packet is waiting for our
|
||||||
|
next probe to be sent. Our next probe is used to check if
|
||||||
|
there are any neighbors currently broadcasting a
|
||||||
|
packet. If so, we will get a broadcast packet in response
|
||||||
|
to our probe. If no broadcast packet is received in
|
||||||
|
response to our probe, we mark the packet as ready to be
|
||||||
|
sent. */
|
||||||
|
set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
|
||||||
|
PRINTF("-> waiting\n");
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
} else {
|
||||||
|
timeout = UNICAST_TIMEOUT;
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
i->broadcast_flag = BROADCAST_FLAG_NONE;
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
}
|
||||||
|
ctimer_set(&i->removal_timer, timeout, remove_queued_packet, i);
|
||||||
|
|
||||||
/* Wait for a probe packet from a neighbor. The actual packet
|
/* Wait for a probe packet from a neighbor. The actual packet
|
||||||
transmission is handled by the read_packet() function,
|
transmission is handled by the read_packet() function,
|
||||||
which receives the probe from the neighbor. */
|
which receives the probe from the neighbor. */
|
||||||
turn_radio_on_for_neighbor(&hdr.receiver, i);
|
turn_radio_on_for_neighbor(&hdr.receiver, i);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,6 +635,7 @@ read_packet(void)
|
||||||
hdr = packetbuf_dataptr();
|
hdr = packetbuf_dataptr();
|
||||||
packetbuf_hdrreduce(sizeof(struct lpp_hdr));
|
packetbuf_hdrreduce(sizeof(struct lpp_hdr));
|
||||||
/* PRINTF("got packet type %d\n", hdr->type);*/
|
/* PRINTF("got packet type %d\n", hdr->type);*/
|
||||||
|
|
||||||
if(hdr->type == TYPE_PROBE) {
|
if(hdr->type == TYPE_PROBE) {
|
||||||
/* Parse incoming announcements */
|
/* Parse incoming announcements */
|
||||||
struct announcement_msg *adata = packetbuf_dataptr();
|
struct announcement_msg *adata = packetbuf_dataptr();
|
||||||
|
@ -560,8 +656,13 @@ read_packet(void)
|
||||||
adata->data[i].value);
|
adata->data[i].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Register the encounter with the sending node. We now know the
|
||||||
|
neighbor's phase. */
|
||||||
register_encounter(&hdr->sender, reception_time);
|
register_encounter(&hdr->sender, reception_time);
|
||||||
|
|
||||||
|
/* Go through the list of packets to be sent to see if any of
|
||||||
|
them match the sender of the probe, or if they are a
|
||||||
|
broadcast packet that should be sent. */
|
||||||
if(list_length(queued_packets_list) > 0) {
|
if(list_length(queued_packets_list) > 0) {
|
||||||
struct queue_list_item *i;
|
struct queue_list_item *i;
|
||||||
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
||||||
|
@ -569,15 +670,34 @@ read_packet(void)
|
||||||
|
|
||||||
qhdr = queuebuf_dataptr(i->packet);
|
qhdr = queuebuf_dataptr(i->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",
|
queuebuf_to_packetbuf(i->packet);
|
||||||
|
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
if(i->broadcast_flag == BROADCAST_FLAG_NONE ||
|
||||||
|
i->broadcast_flag == BROADCAST_FLAG_SEND) {
|
||||||
|
radio->send(queuebuf_dataptr(i->packet),
|
||||||
|
queuebuf_datalen(i->packet));
|
||||||
|
PRINTF("%d.%d: got a probe from %d.%d, sent 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]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PRINTF("%d.%d: got a probe from %d.%d, did not send packet\n",
|
||||||
|
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
|
||||||
|
hdr->sender.u8[0], hdr->sender.u8[1]);
|
||||||
|
}
|
||||||
|
#else /* WITH_PENDING_BROADCAST */
|
||||||
|
radio->send(queuebuf_dataptr(i->packet),
|
||||||
|
queuebuf_datalen(i->packet));
|
||||||
|
PRINTF("%d.%d: got a probe from %d.%d, sent 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]);
|
||||||
queuebuf_to_packetbuf(i->packet);
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
|
||||||
|
|
||||||
radio->send(queuebuf_dataptr(i->packet),
|
|
||||||
queuebuf_datalen(i->packet));
|
|
||||||
|
|
||||||
/* Attribute the energy spent on listening for the probe
|
/* Attribute the energy spent on listening for the probe
|
||||||
to this packet transmission. */
|
to this packet transmission. */
|
||||||
|
@ -626,6 +746,27 @@ read_packet(void)
|
||||||
for the next packet. */
|
for the next packet. */
|
||||||
compower_clear(¤t_packet);
|
compower_clear(¤t_packet);
|
||||||
|
|
||||||
|
#if WITH_PENDING_BROADCAST
|
||||||
|
if(rimeaddr_cmp(&hdr->receiver, &rimeaddr_null)) {
|
||||||
|
/* This is a broadcast packet. Check the list of pending
|
||||||
|
packets to see if we are currently sending a broadcast. If
|
||||||
|
so, we refrain from sending our broadcast until one sleep
|
||||||
|
cycle period, so that the other broadcaster will have
|
||||||
|
finished sending. */
|
||||||
|
|
||||||
|
struct queue_list_item *i;
|
||||||
|
for(i = list_head(queued_packets_list); i != NULL; i = i->next) {
|
||||||
|
/* If the packet is a broadcast packet that is not yet
|
||||||
|
ready to be sent, we do not send it. */
|
||||||
|
if(i->broadcast_flag == BROADCAST_FLAG_PENDING) {
|
||||||
|
PRINTF("Someone else is sending, pending -> waiting\n");
|
||||||
|
set_broadcast_flag(i, BROADCAST_FLAG_WAITING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* WITH_PENDING_BROADCAST */
|
||||||
|
|
||||||
|
|
||||||
#if WITH_PROBE_AFTER_RECEPTION
|
#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
|
||||||
|
|
Loading…
Reference in a new issue