Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2007, Swedish Institute of Computer Science. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * $Id: tdma_mac.c,v 1.8 2010/06/14 19:19:17 adamdunkels Exp $ 00032 */ 00033 00034 #include "contiki.h" 00035 #include "net/mac/tdma_mac.h" 00036 #include "net/packetbuf.h" 00037 #include "net/uip-fw.h" 00038 #include "sys/rtimer.h" 00039 #include "net/rime.h" 00040 #include "lib/memb.h" 00041 #include "lib/list.h" 00042 #include "dev/leds.h" 00043 #include "node-id.h" 00044 00045 #include <string.h> 00046 #include <stdio.h> 00047 00048 #define DEBUG 1 00049 #if DEBUG 00050 #define DLEDS_ON(x) leds_on(x) 00051 #define DLEDS_OFF(x) leds_off(x) 00052 #define DLEDS_TOGGLE(x) leds_toggle(x) 00053 #define PRINTF(...) printf(__VA_ARGS__) 00054 #else 00055 #define DLEDS_ON(x) 00056 #define DLEDS_OFF(x) 00057 #define DLEDS_TOGGLE(x) 00058 #define PRINTF(...) 00059 #endif 00060 00061 /* TDMA configuration */ 00062 #define NR_SLOTS 3 00063 #define SLOT_LENGTH (RTIMER_SECOND/3) 00064 #define GUARD_PERIOD (RTIMER_SECOND/12) 00065 00066 #define MY_SLOT (node_id % NR_SLOTS) 00067 #define PERIOD_LENGTH RTIMER_SECOND 00068 00069 /* Buffers */ 00070 #define NUM_PACKETS 8 00071 uint8_t lastqueued = 0; 00072 uint8_t nextsend = 0; 00073 uint8_t freeslot = 0; 00074 struct queuebuf* data[NUM_PACKETS]; 00075 int id[NUM_PACKETS]; 00076 00077 static struct rtimer rtimer; 00078 uint8_t timer_on = 0; 00079 00080 static const struct radio_driver *radio; 00081 static void (* receiver_callback)(const struct mac_driver *); 00082 static int id_counter = 0; 00083 static int sent_counter = 0; 00084 00085 /*---------------------------------------------------------------------------*/ 00086 static char 00087 transmitter(struct rtimer *t, void *ptr) 00088 { 00089 int r; 00090 rtimer_clock_t now, rest, period_start, slot_start; 00091 00092 /* Calculate slot start time */ 00093 now = RTIMER_NOW(); 00094 rest = now % PERIOD_LENGTH; 00095 period_start = now - rest; 00096 slot_start = period_start + MY_SLOT*SLOT_LENGTH; 00097 00098 /* Check if we are inside our slot */ 00099 if(now < slot_start || 00100 now > slot_start + SLOT_LENGTH - GUARD_PERIOD) { 00101 PRINTF("TIMER We are outside our slot: %u != [%u,%u]\n", now, slot_start, slot_start + SLOT_LENGTH); 00102 while(now > slot_start + SLOT_LENGTH - GUARD_PERIOD) { 00103 slot_start += PERIOD_LENGTH; 00104 } 00105 00106 PRINTF("TIMER Rescheduling until %u\n", slot_start); 00107 r = rtimer_set(&rtimer, slot_start, 1, 00108 (void (*)(struct rtimer *, void *))transmitter, NULL); 00109 if(r) { 00110 PRINTF("TIMER Error #1: %d\n", r); 00111 } 00112 00113 return 1; 00114 } 00115 00116 /* Transmit queued packets */ 00117 while(nextsend != freeslot) { 00118 PRINTF("RADIO Transmitting packet #%i\n", id[nextsend]); 00119 if(!radio->send(queuebuf_dataptr(data[nextsend]), 00120 queuebuf_datalen(data[nextsend]))) { 00121 sent_counter++; 00122 PRINTF("RADIO Transmit OK for #%i, total=%i\n", id[nextsend], sent_counter); 00123 DLEDS_TOGGLE(LEDS_GREEN); 00124 } else { 00125 PRINTF("RADIO Transmit failed for #%i, total=%i\n", id[nextsend], sent_counter); 00126 DLEDS_TOGGLE(LEDS_RED); 00127 } 00128 00129 nextsend = (nextsend + 1) % NUM_PACKETS; 00130 00131 /* Recalculate new slot */ 00132 if(RTIMER_NOW() > slot_start + SLOT_LENGTH - GUARD_PERIOD) { 00133 PRINTF("TIMER No more time to transmit\n"); 00134 break; 00135 } 00136 } 00137 00138 /* Calculate time of our next slot */ 00139 slot_start += PERIOD_LENGTH; 00140 PRINTF("TIMER Rescheduling until %u\n", slot_start); 00141 r = rtimer_set(&rtimer, slot_start, 1, 00142 (void (*)(struct rtimer *, void *))transmitter, NULL); 00143 if(r) { 00144 PRINTF("TIMER Error #2: %d\n", r); 00145 } 00146 00147 return 0; 00148 } 00149 /*---------------------------------------------------------------------------*/ 00150 static int 00151 send(void) 00152 { 00153 int r; 00154 id_counter++; 00155 00156 /* Clean up already sent packets */ 00157 while(lastqueued != nextsend) { 00158 PRINTF("BUFFER Cleaning up packet #%i\n", id[lastqueued]); 00159 queuebuf_free(data[lastqueued]); 00160 data[lastqueued] = NULL; 00161 00162 lastqueued = (lastqueued + 1) % NUM_PACKETS; 00163 } 00164 00165 if((freeslot + 1) % NUM_PACKETS == lastqueued) { 00166 PRINTF("BUFFER Buffer full, dropping packet #%i\n", (id_counter+1)); 00167 return UIP_FW_DROPPED; 00168 } 00169 00170 /* Allocate queue buf for packet */ 00171 data[freeslot] = queuebuf_new_from_packetbuf(); 00172 id[freeslot] = id_counter; 00173 if(data[freeslot] == NULL) { 00174 PRINTF("BUFFER Queuebuffer full, dropping packet #%i\n", id[freeslot]); 00175 return UIP_FW_DROPPED; 00176 } 00177 PRINTF("BUFFER Wrote packet #%i to buffer \n", id[freeslot]); 00178 00179 freeslot = (freeslot + 1) % NUM_PACKETS; 00180 00181 if(!timer_on) { 00182 PRINTF("TIMER Starting timer\n"); 00183 r = rtimer_set(&rtimer, RTIMER_NOW() + RTIMER_SECOND, 1, 00184 (void (*)(struct rtimer *, void *))transmitter, NULL); 00185 if(r) { 00186 PRINTF("TIMER Error #3: %d\n", r); 00187 } else { 00188 timer_on = 1; 00189 } 00190 } 00191 00192 return UIP_FW_OK; /* TODO Return what? */ 00193 } 00194 /*---------------------------------------------------------------------------*/ 00195 static void 00196 input(const struct radio_driver *d) 00197 { 00198 receiver_callback(&tdma_mac_driver); 00199 } 00200 /*---------------------------------------------------------------------------*/ 00201 static int 00202 read(void) 00203 { 00204 int len; 00205 packetbuf_clear(); 00206 len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE); 00207 packetbuf_set_datalen(len); 00208 return len; 00209 } 00210 /*---------------------------------------------------------------------------*/ 00211 static void 00212 set_receive_function(void (* recv)(const struct mac_driver *)) 00213 { 00214 receiver_callback = recv; 00215 } 00216 /*---------------------------------------------------------------------------*/ 00217 static int 00218 on(void) 00219 { 00220 return radio->on(); 00221 } 00222 /*---------------------------------------------------------------------------*/ 00223 static int 00224 off(int keep_radio_on) 00225 { 00226 if(keep_radio_on) { 00227 return radio->on(); 00228 } else { 00229 return radio->off(); 00230 } 00231 } 00232 /*---------------------------------------------------------------------------*/ 00233 const struct mac_driver * 00234 tdma_mac_init(const struct radio_driver *d) 00235 { 00236 int i; 00237 for(i = 0; i < NUM_PACKETS; i++) { 00238 data[i] = NULL; 00239 } 00240 00241 radio = d; 00242 radio->set_receive_function(input); 00243 radio->on(); 00244 00245 return &tdma_mac_driver; 00246 } 00247 /*---------------------------------------------------------------------------*/ 00248 const struct mac_driver tdma_mac_driver = { 00249 "TDMA MAC", 00250 tdma_mac_init, 00251 send, 00252 read, 00253 set_receive_function, 00254 on, 00255 off, 00256 };