Improved version of LPP with support for broadcasts as well as announcement data in the probes

This commit is contained in:
adamdunkels 2009-02-08 19:30:18 +00:00
parent 37b86b9236
commit 085df6b630

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.5 2008/06/30 08:08:59 adamdunkels Exp $ * $Id: lpp.c,v 1.6 2009/02/08 19:30:18 adamdunkels Exp $
*/ */
/** /**
@ -51,13 +51,14 @@
*/ */
#include "dev/leds.h" #include "dev/leds.h"
#include "lib/random.h"
#include "net/rime.h" #include "net/rime.h"
#include "net/mac/mac.h" #include "net/mac/mac.h"
#include "net/mac/lpp.h" #include "net/mac/lpp.h"
#include "net/rime/rimebuf.h" #include "net/rime/rimebuf.h"
#include <stdlib.h>
#define DEBUG 0 #define DEBUG 0
#if DEBUG #if DEBUG
#include <stdio.h> #include <stdio.h>
@ -67,6 +68,19 @@
#endif #endif
struct announcement_data {
uint16_t id;
uint16_t value;
};
#define ANNOUNCEMENT_MSG_HEADERLEN 2
struct announcement_msg {
uint16_t num;
struct announcement_data data[];
};
#define LPP_PROBE_HEADERLEN 2
#define TYPE_PROBE 1 #define TYPE_PROBE 1
#define TYPE_DATA 2 #define TYPE_DATA 2
struct lpp_hdr { struct lpp_hdr {
@ -79,13 +93,18 @@ 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 struct queuebuf *queued_packet;
#define LISTEN_TIME CLOCK_SECOND / 128 static uint8_t is_listening = 0;
#define OFF_TIME CLOCK_SECOND / 4
#define LISTEN_TIME CLOCK_SECOND / 64
#define OFF_TIME CLOCK_SECOND * 1
#define PACKET_LIFETIME LISTEN_TIME + OFF_TIME
#define DUMP_QUEUED_PACKET 0
#define DUMP_QUEUED_PACKET 1
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -102,6 +121,20 @@ turn_radio_off(void)
leds_off(LEDS_YELLOW); leds_off(LEDS_YELLOW);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void
remove_queued_packet(void)
{
queuebuf_free(queued_packet);
queued_packet = NULL;
}
/*---------------------------------------------------------------------------*/
static void
listen_callback(int periods)
{
is_listening = periods;
turn_radio_on();
}
/*---------------------------------------------------------------------------*/
/** /**
* Send a probe packet. * Send a probe packet.
*/ */
@ -109,15 +142,33 @@ static void
send_probe(void) send_probe(void)
{ {
struct lpp_hdr *hdr; struct lpp_hdr *hdr;
struct announcement_msg *adata;
struct announcement *a;
/* Set up the probe header. */
rimebuf_clear(); rimebuf_clear();
hdr = rimebuf_dataptr();
rimebuf_set_datalen(sizeof(struct lpp_hdr)); rimebuf_set_datalen(sizeof(struct lpp_hdr));
hdr = rimebuf_dataptr();
hdr->type = TYPE_PROBE;
rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr); rimeaddr_copy(&hdr->sender, &rimeaddr_node_addr);
rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER)); rimeaddr_copy(&hdr->receiver, rimebuf_addr(RIMEBUF_ADDR_RECEIVER));
hdr->type = TYPE_PROBE;
PRINTF("Sending probe\n");
/* Construct the announcements */
adata = (struct announcement_msg *)((char *)hdr + sizeof(struct lpp_hdr));
adata->num = 0;
for(a = announcement_list(); a != NULL; a = a->next) {
adata->data[adata->num].id = a->id;
adata->data[adata->num].value = a->value;
adata->num++;
}
rimebuf_set_datalen(sizeof(struct lpp_hdr) +
ANNOUNCEMENT_MSG_HEADERLEN +
sizeof(struct announcement_data) * adata->num);
/* PRINTF("Sending probe\n");*/
radio->send(rimebuf_hdrptr(), rimebuf_totlen()); radio->send(rimebuf_hdrptr(), rimebuf_totlen());
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -133,28 +184,34 @@ dutycycle(void *ptr)
PT_BEGIN(&pt); PT_BEGIN(&pt);
while(1) { while(1) {
if(queued_packet != NULL) {
/* 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, OFF_TIME * 2, (void (*)(void *))dutycycle, t);
PT_YIELD(&pt);
queuebuf_free(queued_packet);
queued_packet = NULL;
PRINTF("Removing old packet\n");
}
turn_radio_on(); turn_radio_on();
send_probe(); send_probe();
ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t); ctimer_set(t, LISTEN_TIME, (void (*)(void *))dutycycle, t);
PT_YIELD(&pt); PT_YIELD(&pt);
turn_radio_off();
if(queued_packet == NULL) {
if(is_listening == 0) {
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, OFF_TIME / 2 + (random_rand() % OFF_TIME / 2), ctimer_set(t, OFF_TIME / 2 + (rand() % (OFF_TIME / 2)),
(void (*)(void *))dutycycle, t); (void (*)(void *))dutycycle, t);
PT_YIELD(&pt); PT_YIELD(&pt);
} else {
is_listening--;
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");
}
} }
PT_END(&pt); PT_END(&pt);
@ -187,7 +244,10 @@ send_packet(void)
hdr->type = TYPE_DATA; hdr->type = TYPE_DATA;
rimebuf_compact(); rimebuf_compact();
PRINTF("queueing packet type %d\n", hdr->type); PRINTF("%d.%d: queueing packet to %d.%d, channel %d\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
hdr->receiver.u8[0], hdr->receiver.u8[1],
rimebuf_attr(RIMEBUF_ATTR_CHANNEL));
if(rimebuf_attr(RIMEBUF_ATTR_PACKET_TYPE) == RIMEBUF_ATTR_PACKET_TYPE_ACK) { if(rimebuf_attr(RIMEBUF_ATTR_PACKET_TYPE) == RIMEBUF_ATTR_PACKET_TYPE_ACK) {
/* Immediately send ACKs - we're assuming that the other node is /* Immediately send ACKs - we're assuming that the other node is
@ -202,7 +262,7 @@ send_packet(void)
measured the effect of this option */ measured the effect of this option */
#if DUMP_QUEUED_PACKET #if DUMP_QUEUED_PACKET
if(queued_packet != NULL) { if(queued_packet != NULL) {
queuebuf_free(queued_packet); remove_queued_packet();
} }
queued_packet = queuebuf_new_from_rimebuf(); queued_packet = queuebuf_new_from_rimebuf();
#else /* DUMP_QUEUED_PACKET */ #else /* DUMP_QUEUED_PACKET */
@ -211,6 +271,7 @@ send_packet(void)
} }
#endif /* DUMP_QUEUED_PACKET */ #endif /* DUMP_QUEUED_PACKET */
timer_set(&packet_lifetime_timer, PACKET_LIFETIME);
/* Wait for a probe packet from a neighbor */ /* Wait for a probe packet from a neighbor */
turn_radio_on(); turn_radio_on();
} }
@ -235,20 +296,52 @@ read_packet(void)
rimebuf_set_datalen(len); rimebuf_set_datalen(len);
hdr = rimebuf_dataptr(); hdr = rimebuf_dataptr();
rimebuf_hdrreduce(sizeof(struct lpp_hdr)); rimebuf_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 */
struct announcement_msg *adata = rimebuf_dataptr();
int i;
/* PRINTF("%d.%d: probe from %d.%d with %d announcements\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
hdr->sender.u8[0], hdr->sender.u8[1], adata->num);*/
for(i = 0; i < adata->num; ++i) {
/* PRINTF("%d.%d: announcement %d: %d\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
adata->data[i].id,
adata->data[i].value);*/
announcement_heard(&hdr->sender,
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) { if(queued_packet != NULL) {
qhdr = queuebuf_dataptr(queued_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\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]);
radio->send(queuebuf_dataptr(queued_packet), radio->send(queuebuf_dataptr(queued_packet),
queuebuf_datalen(queued_packet)); queuebuf_datalen(queued_packet));
queuebuf_free(queued_packet);
queued_packet = NULL; /* 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 turn_radio_on(); /* XXX Awaiting an ACK: we should check the
packet type of the queued packet to see packet type of the queued packet to see
@ -313,6 +406,9 @@ 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); ctimer_set(&timer, LISTEN_TIME, (void (*)(void *))dutycycle, &timer);
announcement_register_listen_callback(listen_callback);
return &lpp_driver; return &lpp_driver;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/