From 858e2682e670e3746601f97322360477b94dcd8d Mon Sep 17 00:00:00 2001 From: fros4943 Date: Fri, 31 Aug 2007 13:42:22 +0000 Subject: [PATCH] platform independent simple slotted tdma mac protocol observe: uses event timers, not real-time timers! --- core/net/mac/tdma_mac.c | 248 ++++++++++++++++++++++++++++++++++++++++ core/net/mac/tdma_mac.h | 44 +++++++ 2 files changed, 292 insertions(+) create mode 100644 core/net/mac/tdma_mac.c create mode 100644 core/net/mac/tdma_mac.h diff --git a/core/net/mac/tdma_mac.c b/core/net/mac/tdma_mac.c new file mode 100644 index 000000000..a7899b3fe --- /dev/null +++ b/core/net/mac/tdma_mac.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2007, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: tdma_mac.c,v 1.1 2007/08/31 13:42:22 fros4943 Exp $ + */ + +#include "contiki.h" +#include "net/mac/tdma_mac.h" +#include "net/rime/rimebuf.h" +#include "net/uip-fw.h" +#include "lib/memb.h" +#include "lib/list.h" +#include "node-id.h" + +#include +#include + +static const struct radio_driver *radio; +static void (* receiver_callback)(const struct mac_driver *); +static int id_counter = 0; + +#define DEBUG 1 +#if DEBUG +/*#include "printf2log.h"*/ /* XXX COOJA specifics */ +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/* TDMA configuration */ +#define MAX_BUFFERED_PACKETS 6 + +#define NR_SLOTS 10 +#define SLOT_LENGTH (CLOCK_SECOND) /* Slot length */ +#define GUARD_PERIOD (CLOCK_SECOND / 2) /* Approx. packet transmission time */ + +#define MY_SLOT (node_id % NR_SLOTS) +#define PERIOD_LENGTH (SLOT_LENGTH*NR_SLOTS) + +enum { + EVENT_PACKET_BUFFERED +}; + +struct buf_packet { + struct buf_packet *next; + struct queuebuf *queued_packet; + int id; + struct etimer etimer; +}; + +LIST(buf_packet_list); +MEMB(buf_packet_mem, struct buf_packet, MAX_BUFFERED_PACKETS); + +PROCESS(tdma_process, "TDMA process"); + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(tdma_process, ev, data) +{ + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD(); + + if(ev == EVENT_PACKET_BUFFERED || ev == PROCESS_EVENT_TIMER) { + struct buf_packet *packet; + + /* Locate packet */ + for(packet = list_head(buf_packet_list); packet != NULL; packet = packet->next) { + if (etimer_expired(&packet->etimer)) { + int ret, rest, period_start, my_next_slot; + clock_time_t now; + + /* Calculate time of our next slot */ + now = clock_time(); + rest = now % PERIOD_LENGTH; + period_start = now - rest; + my_next_slot = period_start + MY_SLOT*SLOT_LENGTH; + + /* Transmit if inside our slot, with enough time left */ + if ((now == my_next_slot) || + (now > my_next_slot && (now - my_next_slot) < (SLOT_LENGTH-GUARD_PERIOD))) + { + PRINTF("SCHEDULE We can deliver right now (%i), slot = (%i <-> %i)\n", now, my_next_slot, my_next_slot + SLOT_LENGTH); + } + else + { + if (now > my_next_slot) { + my_next_slot += PERIOD_LENGTH; + } + + int distance = my_next_slot - now; + etimer_set(&packet->etimer, distance); + PRINTF("SCHEDULE Packet #%i rescheduled at %i to %i\n", packet->id, clock_time(), my_next_slot); + continue; + } + + /* Clear Rime buffer */ + rimebuf_clear(); + + /* Restore packet from buffer */ + if(packet->queued_packet != NULL) { + queuebuf_to_rimebuf(packet->queued_packet); + queuebuf_free(packet->queued_packet); + } + + /* Send packet */ + PRINTF("TDMA_PROC Packet #%i send starting at %i\n", packet->id, clock_time()); + ret = radio->send(rimebuf_hdrptr(), rimebuf_totlen()); + + + if (ret == UIP_FW_OK) { + /* Remove transmitted packet */ + list_remove(buf_packet_list, packet); + memb_free(&buf_packet_mem, packet); + PRINTF("BUFFER Packet removed, memory freed\n"); + PRINTF("TDMA_PROC Packet #%i sent at %i\n", packet->id, clock_time()); + } else { + /* Reschedule packet */ + etimer_set(&packet->etimer, SLOT_LENGTH); + PRINTF("TDMA_PROC Packet #%i forced rescheduled\n", packet->id); + } + } + } + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +static int +send(void) +{ + struct buf_packet *packet; + + packet = (struct buf_packet *)memb_alloc(&buf_packet_mem); + if (packet == NULL) { + PRINTF("BUFFER No memory available, packet dropped\n"); + return UIP_FW_DROPPED; + } + + /* Add to buffered packets list */ + list_add(buf_packet_list, packet); + PRINTF("BUFFER Packet added, memory allocated\n"); + + /* Store packet data */ + packet->queued_packet = queuebuf_new_from_rimebuf(); + if (packet->queued_packet == NULL) { + list_remove(buf_packet_list, packet); + memb_free(&buf_packet_mem, packet); + PRINTF("BUFFER No queue memory available, packet dropped\n"); + return UIP_FW_DROPPED; + } + + PROCESS_CONTEXT_BEGIN(&tdma_process); + etimer_set(&packet->etimer, 0); + PROCESS_CONTEXT_END(&tdma_process); + + /* TODO ID only used for debugging */ + packet->id = id_counter++; + + /* Clear Rime buffer */ + rimebuf_clear(); + + process_post(&tdma_process, EVENT_PACKET_BUFFERED, NULL); + + return UIP_FW_OK; /* TODO Return what? */ + +} +/*---------------------------------------------------------------------------*/ +static void +input(const struct radio_driver *d) +{ + receiver_callback(&tdma_mac_driver); +} +/*---------------------------------------------------------------------------*/ +static int +read(void) +{ + int len; + rimebuf_clear(); + len = radio->read(rimebuf_dataptr(), RIMEBUF_SIZE); + rimebuf_set_datalen(len); + return len; +} +/*---------------------------------------------------------------------------*/ +static void +set_receive_function(void (* recv)(const struct mac_driver *)) +{ + receiver_callback = recv; +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + return radio->on(); +} +/*---------------------------------------------------------------------------*/ +static int +off(void) +{ + return radio->off(); +} +/*---------------------------------------------------------------------------*/ +void +tdma_mac_init(const struct radio_driver *d) +{ + memb_init(&buf_packet_mem); + list_init(buf_packet_list); + process_start(&tdma_process, NULL); + + radio = d; + radio->set_receive_function(input); + radio->on(); +} +/*---------------------------------------------------------------------------*/ +const struct mac_driver tdma_mac_driver = { + send, + read, + set_receive_function, + on, + off, +}; diff --git a/core/net/mac/tdma_mac.h b/core/net/mac/tdma_mac.h new file mode 100644 index 000000000..763274209 --- /dev/null +++ b/core/net/mac/tdma_mac.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: tdma_mac.h,v 1.1 2007/08/31 13:42:22 fros4943 Exp $ + */ + +#ifndef __TDMA_MAC_H__ +#define __TDMA_MAC_H__ + +#include "net/mac/mac.h" +#include "dev/radio.h" + +extern const struct mac_driver tdma_mac_driver; + +void tdma_mac_init(const struct radio_driver *r); + +#endif /* __TDMA_MAC_H__ */