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: ctdma_mac.c,v 1.6 2010/06/14 19:19:16 adamdunkels Exp $ 00032 */ 00033 00034 #include "contiki.h" 00035 #include "net/mac/ctdma_mac.h" 00036 #include "net/packetbuf.h" 00037 #include "net/uip-fw.h" 00038 #include "sys/ctimer.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 */ 00062 #define NR_SLOTS 3 00063 #define SLOT_LENGTH (CLOCK_SECOND/3) 00064 #define GUARD_PERIOD (CLOCK_SECOND/12) 00065 00066 #define MY_SLOT (node_id % NR_SLOTS) 00067 #define PERIOD_LENGTH CLOCK_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 ctimer ctimer; 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 void 00087 transmitter(void *ptr) 00088 { 00089 clock_time_t now, rest, period_start, slot_start; 00090 00091 /* Calculate slot start time */ 00092 now = clock_time(); 00093 rest = now % PERIOD_LENGTH; 00094 period_start = now - rest; 00095 slot_start = period_start + MY_SLOT*SLOT_LENGTH; 00096 00097 /* Check if we are inside our slot */ 00098 if (now < slot_start || 00099 now > slot_start + SLOT_LENGTH - GUARD_PERIOD) 00100 { 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 { 00104 slot_start += PERIOD_LENGTH; 00105 } 00106 00107 PRINTF("TIMER Rescheduling until %u\n", slot_start); 00108 ctimer_set(&ctimer, slot_start - clock_time(), transmitter, NULL); 00109 return; 00110 } 00111 00112 /* Transmit queued packets */ 00113 while (nextsend != freeslot) 00114 { 00115 PRINTF("RADIO Transmitting packet #%i\n", id[nextsend]); 00116 if(!radio->send( 00117 queuebuf_dataptr(data[nextsend]), 00118 queuebuf_datalen(data[nextsend]))) 00119 { 00120 sent_counter++; 00121 PRINTF("RADIO Transmit OK for #%i, total=%i\n", id[nextsend], sent_counter); 00122 DLEDS_TOGGLE(LEDS_GREEN); 00123 } 00124 else 00125 { 00126 PRINTF("RADIO Transmit failed for #%i, total=%i\n", id[nextsend], sent_counter); 00127 DLEDS_TOGGLE(LEDS_RED); 00128 } 00129 00130 nextsend = (nextsend + 1) % NUM_PACKETS; 00131 00132 /* Recalculate new slot */ 00133 if (clock_time() > slot_start + SLOT_LENGTH - GUARD_PERIOD) 00134 { 00135 PRINTF("TIMER No more time to transmit\n"); 00136 break; 00137 } 00138 } 00139 00140 /* Calculate time of our next slot */ 00141 slot_start += PERIOD_LENGTH; 00142 PRINTF("TIMER Rescheduling until %u\n", slot_start); 00143 ctimer_set(&ctimer, slot_start - clock_time(), transmitter, NULL); 00144 } 00145 /*---------------------------------------------------------------------------*/ 00146 static int 00147 send(void) 00148 { 00149 id_counter++; 00150 00151 /* Clean up already sent packets */ 00152 while (lastqueued != nextsend) 00153 { 00154 PRINTF("BUFFER Cleaning up packet #%i\n", id[lastqueued]); 00155 queuebuf_free(data[lastqueued]); 00156 data[lastqueued] = NULL; 00157 00158 lastqueued = (lastqueued + 1) % NUM_PACKETS; 00159 } 00160 00161 if ((freeslot + 1) % NUM_PACKETS == lastqueued) 00162 { 00163 PRINTF("BUFFER Buffer full, dropping packet #%i\n", (id_counter+1)); 00164 return UIP_FW_DROPPED; 00165 } 00166 00167 /* Allocate queue buf for packet */ 00168 data[freeslot] = queuebuf_new_from_packetbuf(); 00169 id[freeslot] = id_counter; 00170 if (data[freeslot] == NULL) 00171 { 00172 PRINTF("BUFFER Queuebuffer full, dropping packet #%i\n", id[freeslot]); 00173 return UIP_FW_DROPPED; 00174 } 00175 PRINTF("BUFFER Wrote packet #%i to buffer \n", id[freeslot]); 00176 00177 freeslot = (freeslot + 1) % NUM_PACKETS; 00178 00179 if (!timer_on) 00180 { 00181 PRINTF("TIMER Starting timer\n"); 00182 ctimer_set(&ctimer, CLOCK_SECOND, transmitter, NULL); 00183 timer_on = 1; 00184 } 00185 00186 return UIP_FW_OK; /* TODO Return what? */ 00187 } 00188 /*---------------------------------------------------------------------------*/ 00189 static void 00190 input(const struct radio_driver *d) 00191 { 00192 receiver_callback(&ctdma_mac_driver); 00193 } 00194 /*---------------------------------------------------------------------------*/ 00195 static int 00196 read(void) 00197 { 00198 int len; 00199 packetbuf_clear(); 00200 len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE); 00201 packetbuf_set_datalen(len); 00202 return len; 00203 } 00204 /*---------------------------------------------------------------------------*/ 00205 static void 00206 set_receive_function(void (* recv)(const struct mac_driver *)) 00207 { 00208 receiver_callback = recv; 00209 } 00210 /*---------------------------------------------------------------------------*/ 00211 static int 00212 on(void) 00213 { 00214 return radio->on(); 00215 } 00216 /*---------------------------------------------------------------------------*/ 00217 static int 00218 off(int keep_radio_on) 00219 { 00220 if(keep_radio_on) { 00221 return radio->on(); 00222 } else { 00223 return radio->off(); 00224 } 00225 } 00226 /*---------------------------------------------------------------------------*/ 00227 const struct mac_driver * 00228 ctdma_mac_init(const struct radio_driver *d) 00229 { 00230 int i; 00231 for (i=0; i < NUM_PACKETS; i++) 00232 { 00233 data[i] = NULL; 00234 } 00235 00236 radio = d; 00237 radio->set_receive_function(input); 00238 radio->on(); 00239 return &ctdma_mac_driver; 00240 } 00241 /*---------------------------------------------------------------------------*/ 00242 const struct mac_driver ctdma_mac_driver = { 00243 "CTDMA", 00244 ctdma_mac_init, 00245 send, 00246 read, 00247 set_receive_function, 00248 on, 00249 off, 00250 };