diff --git a/examples/rime/example-multihop.c b/examples/rime/example-multihop.c index f925f2831..4f49f4032 100644 --- a/examples/rime/example-multihop.c +++ b/examples/rime/example-multihop.c @@ -28,7 +28,7 @@ * * This file is part of the Contiki operating system. * - * $Id: example-multihop.c,v 1.3 2009/03/12 21:58:21 adamdunkels Exp $ + * $Id: example-multihop.c,v 1.4 2009/03/23 18:10:09 adamdunkels Exp $ */ /** @@ -36,31 +36,162 @@ * Testing the multihop forwarding layer (multihop) in Rime * \author * Adam Dunkels + * + * + * This example shows how to use the multihop Rime module, how + * to use the announcement mechanism, how to manage a list + * with the list module, and how to allocate memory with the + * memb module. + * + * The multihop module provides hooks for forwarding packets + * in a multi-hop fashion, but does not implement any routing + * protocol. A routing mechanism must be provided by the + * application or protocol running on top of the multihop + * module. In this case, this example program provides the + * routing mechanism. + * + * The routing mechanism implemented by this example program + * is very simple: it forwards every incoming packet to a + * random neighbor. The program maintains a list of neighbors, + * which it populated through the use of the announcement + * mechanism. + * + * The neighbor list is populated by incoming announcements + * from neighbors. The program maintains a list of neighbors, + * where each entry is allocated from a MEMB() (memory block + * pool). Each neighbor has a timeout so that they do not + * occupy their list entry for too long. + * + * When a packet arrives to the node, the function forward() + * is called by the multihop layer. This function picks a + * random neighbor to send the packet to. The packet is + * forwarded by every node in the network until it reaches its + * final destination (or is discarded in transit due to a + * transmission error or a collision). + * */ #include "contiki.h" #include "net/rime.h" - +#include "lib/list.h" +#include "lib/memb.h" +#include "lib/random.h" #include "dev/button-sensor.h" - #include "dev/leds.h" #include + +#define CHANNEL 128 + + +struct example_neighbor { + struct example_neighbor *next; + rimeaddr_t addr; + struct ctimer ctimer; +}; + +#define NEIGHBOR_TIMEOUT 60 * CLOCK_SECOND +#define MAX_NEIGHBORS 16 +LIST(neighbor_table); +MEMB(neighbor_mem, struct example_neighbor, MAX_NEIGHBORS); /*---------------------------------------------------------------------------*/ PROCESS(example_multihop_process, "multihop example"); AUTOSTART_PROCESSES(&example_multihop_process); /*---------------------------------------------------------------------------*/ +/* + * This function is called by the ctimer present in each neighbor + * table entry. The function removes the neighbor from the table + * because it has become too old. + */ static void -recv(struct multihop_conn *c, rimeaddr_t *sender, rimeaddr_t *prevhop, +remove_neighbor(void *n) +{ + struct example_neighbor *e = n; + + list_remove(neighbor_table, e); + memb_free(&neighbor_mem, e); +} +/*---------------------------------------------------------------------------*/ +/* + * This function is called when an incoming announcement arrives. The + * function checks the neighbor table to see if the neighbor is + * already present in the list. If the neighbor is not present in the + * list, a new neighbor table entry is allocated and is added to the + * neighbor table. + */ +static void +received_announcement(struct announcement *a, rimeaddr_t *from, + uint16_t id, uint16_t value) +{ + struct example_neighbor *e; + + /* printf("Got announcement from %d.%d, id %d, value %d\n", + from->u8[0], from->u8[1], id, value);*/ + + /* We received an announcement from a neighbor so we need to update + the neighbor list, or add a new entry to the table. */ + for(e = list_head(neighbor_table); e != NULL; e = e->next) { + if(rimeaddr_cmp(from, &e->addr)) { + /* Our neighbor was found, so we update the timeout. */ + ctimer_set(&e->ctimer, NEIGHBOR_TIMEOUT, remove_neighbor, e); + return; + } + } + + /* The neighbor was not found in the list, so we add a new entry by + allocating memory from the neighbor_mem pool, fill in the + necessary fields, and add it to the list. */ + e = memb_alloc(&neighbor_mem); + if(e != NULL) { + rimeaddr_copy(&e->addr, from); + list_add(neighbor_table, e); + ctimer_set(&e->ctimer, NEIGHBOR_TIMEOUT, remove_neighbor, e); + } +} +static struct announcement example_announcement; +/*---------------------------------------------------------------------------*/ +/* + * This function is called at the final recepient of the message. + */ +static void +recv(struct multihop_conn *c, const rimeaddr_t *sender, + const rimeaddr_t *prevhop, uint8_t hops) { printf("multihop message received '%s'\n", (char *)packetbuf_dataptr()); } +/* + * This function is called to forward a packet. The function picks a + * random neighbor from the neighbor list and returns its address. The + * multihop layer sends the packet to this address. If no neighbor is + * found, the function returns NULL to signal to the multihop layer + * that the packet should be dropped. + */ static rimeaddr_t * -forward(struct multihop_conn *c, rimeaddr_t *originator, rimeaddr_t *dest, - rimeaddr_t *prevhop, uint8_t hops) +forward(struct multihop_conn *c, + const rimeaddr_t *originator, const rimeaddr_t *dest, + const rimeaddr_t *prevhop, uint8_t hops) { - printf("Forwarding message '%s'\n", (char *)packetbuf_dataptr()); + /* Find a random neighbor to send to. */ + int num, i; + struct example_neighbor *n; + + if(list_length(neighbor_table) > 0) { + num = random_rand() % list_length(neighbor_table); + i = 0; + for(n = list_head(neighbor_table); n != NULL && i != num; n = n->next) { + ++i; + } + if(n != NULL) { + printf("%d.%d: Forwarding packet to %d.%d (%d in list), hops %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + n->addr.u8[0], n->addr.u8[1], num, + packetbuf_attr(PACKETBUF_ATTR_HOPS)); + return &n->addr; + } + } + printf("%d.%d: did not find a neighbor to foward to\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); return NULL; } static const struct multihop_callbacks multihop_call = {recv, forward}; @@ -72,19 +203,45 @@ PROCESS_THREAD(example_multihop_process, ev, data) PROCESS_BEGIN(); - multihop_open(&multihop, 128, &multihop_call); + /* Initialize the memory for the neighbor table entries. */ + memb_init(&neighbor_mem); + /* Initialize the list used for the neighbor table. */ + list_init(neighbor_table); + + /* Open a multihop connection on Rime channel CHANNEL. */ + multihop_open(&multihop, CHANNEL, &multihop_call); + + /* Register an announcement with the same announcement ID as the + Rime channel we use to open the multihop connection above. */ + announcement_register(&example_announcement, + CHANNEL, + 0, + received_announcement); + + /* Activate the button sensor. We use the button to drive traffic - + when the btton is pressed, a packet is sent. */ + button_sensor.activate(); + + /* Loop forever, send a packet when the button is pressed. */ while(1) { - static struct etimer et; rimeaddr_t to; - - etimer_set(&et, CLOCK_SECOND); - - PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); - packetbuf_copyfrom("Hej", 4); - to.u8[0] = 161; - to.u8[1] = 161; + /* Wait until we get a sensor event with the button sensor as data. */ + PROCESS_WAIT_EVENT_UNTIL(ev == sensors_event && + data == &button_sensor); + + /* Copy the "Hello" to the packet buffer. */ + packetbuf_copyfrom("Hello", 6); + + /* Set the Rime address of the final receiver of the packet to + 1.1. This is just a dummy value that happens to work nicely in a + netsim simulation (because the default simulation setup creates + one node with address 1.1). */ + to.u8[0] = 1; + to.u8[1] = 1; + + /* Send the packet. */ multihop_send(&multihop, &to); }