Contiki 2.5
tdma_mac.c
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * $Id: tdma_mac.c,v 1.8 2010/06/14 19:19:17 adamdunkels Exp $
32  */
33 
34 #include "contiki.h"
35 #include "net/mac/tdma_mac.h"
36 #include "net/packetbuf.h"
37 #include "net/uip-fw.h"
38 #include "sys/rtimer.h"
39 #include "net/rime.h"
40 #include "lib/memb.h"
41 #include "lib/list.h"
42 #include "dev/leds.h"
43 #include "node-id.h"
44 
45 #include <string.h>
46 #include <stdio.h>
47 
48 #define DEBUG 1
49 #if DEBUG
50 #define DLEDS_ON(x) leds_on(x)
51 #define DLEDS_OFF(x) leds_off(x)
52 #define DLEDS_TOGGLE(x) leds_toggle(x)
53 #define PRINTF(...) printf(__VA_ARGS__)
54 #else
55 #define DLEDS_ON(x)
56 #define DLEDS_OFF(x)
57 #define DLEDS_TOGGLE(x)
58 #define PRINTF(...)
59 #endif
60 
61 /* TDMA configuration */
62 #define NR_SLOTS 3
63 #define SLOT_LENGTH (RTIMER_SECOND/3)
64 #define GUARD_PERIOD (RTIMER_SECOND/12)
65 
66 #define MY_SLOT (node_id % NR_SLOTS)
67 #define PERIOD_LENGTH RTIMER_SECOND
68 
69 /* Buffers */
70 #define NUM_PACKETS 8
71 uint8_t lastqueued = 0;
72 uint8_t nextsend = 0;
73 uint8_t freeslot = 0;
74 struct queuebuf* data[NUM_PACKETS];
75 int id[NUM_PACKETS];
76 
77 static struct rtimer rtimer;
78 uint8_t timer_on = 0;
79 
80 static const struct radio_driver *radio;
81 static void (* receiver_callback)(const struct mac_driver *);
82 static int id_counter = 0;
83 static int sent_counter = 0;
84 
85 /*---------------------------------------------------------------------------*/
86 static char
87 transmitter(struct rtimer *t, void *ptr)
88 {
89  int r;
90  rtimer_clock_t now, rest, period_start, slot_start;
91 
92  /* Calculate slot start time */
93  now = RTIMER_NOW();
94  rest = now % PERIOD_LENGTH;
95  period_start = now - rest;
96  slot_start = period_start + MY_SLOT*SLOT_LENGTH;
97 
98  /* Check if we are inside our slot */
99  if(now < slot_start ||
100  now > slot_start + SLOT_LENGTH - GUARD_PERIOD) {
101  PRINTF("TIMER We are outside our slot: %u != [%u,%u]\n", now, slot_start, slot_start + SLOT_LENGTH);
102  while(now > slot_start + SLOT_LENGTH - GUARD_PERIOD) {
103  slot_start += PERIOD_LENGTH;
104  }
105 
106  PRINTF("TIMER Rescheduling until %u\n", slot_start);
107  r = rtimer_set(&rtimer, slot_start, 1,
108  (void (*)(struct rtimer *, void *))transmitter, NULL);
109  if(r) {
110  PRINTF("TIMER Error #1: %d\n", r);
111  }
112 
113  return 1;
114  }
115 
116  /* Transmit queued packets */
117  while(nextsend != freeslot) {
118  PRINTF("RADIO Transmitting packet #%i\n", id[nextsend]);
119  if(!radio->send(queuebuf_dataptr(data[nextsend]),
120  queuebuf_datalen(data[nextsend]))) {
121  sent_counter++;
122  PRINTF("RADIO Transmit OK for #%i, total=%i\n", id[nextsend], sent_counter);
123  DLEDS_TOGGLE(LEDS_GREEN);
124  } else {
125  PRINTF("RADIO Transmit failed for #%i, total=%i\n", id[nextsend], sent_counter);
126  DLEDS_TOGGLE(LEDS_RED);
127  }
128 
129  nextsend = (nextsend + 1) % NUM_PACKETS;
130 
131  /* Recalculate new slot */
132  if(RTIMER_NOW() > slot_start + SLOT_LENGTH - GUARD_PERIOD) {
133  PRINTF("TIMER No more time to transmit\n");
134  break;
135  }
136  }
137 
138  /* Calculate time of our next slot */
139  slot_start += PERIOD_LENGTH;
140  PRINTF("TIMER Rescheduling until %u\n", slot_start);
141  r = rtimer_set(&rtimer, slot_start, 1,
142  (void (*)(struct rtimer *, void *))transmitter, NULL);
143  if(r) {
144  PRINTF("TIMER Error #2: %d\n", r);
145  }
146 
147  return 0;
148 }
149 /*---------------------------------------------------------------------------*/
150 static int
151 send(void)
152 {
153  int r;
154  id_counter++;
155 
156  /* Clean up already sent packets */
157  while(lastqueued != nextsend) {
158  PRINTF("BUFFER Cleaning up packet #%i\n", id[lastqueued]);
159  queuebuf_free(data[lastqueued]);
160  data[lastqueued] = NULL;
161 
162  lastqueued = (lastqueued + 1) % NUM_PACKETS;
163  }
164 
165  if((freeslot + 1) % NUM_PACKETS == lastqueued) {
166  PRINTF("BUFFER Buffer full, dropping packet #%i\n", (id_counter+1));
167  return UIP_FW_DROPPED;
168  }
169 
170  /* Allocate queue buf for packet */
171  data[freeslot] = queuebuf_new_from_packetbuf();
172  id[freeslot] = id_counter;
173  if(data[freeslot] == NULL) {
174  PRINTF("BUFFER Queuebuffer full, dropping packet #%i\n", id[freeslot]);
175  return UIP_FW_DROPPED;
176  }
177  PRINTF("BUFFER Wrote packet #%i to buffer \n", id[freeslot]);
178 
179  freeslot = (freeslot + 1) % NUM_PACKETS;
180 
181  if(!timer_on) {
182  PRINTF("TIMER Starting timer\n");
183  r = rtimer_set(&rtimer, RTIMER_NOW() + RTIMER_SECOND, 1,
184  (void (*)(struct rtimer *, void *))transmitter, NULL);
185  if(r) {
186  PRINTF("TIMER Error #3: %d\n", r);
187  } else {
188  timer_on = 1;
189  }
190  }
191 
192  return UIP_FW_OK; /* TODO Return what? */
193 }
194 /*---------------------------------------------------------------------------*/
195 static void
196 input(const struct radio_driver *d)
197 {
198  receiver_callback(&tdma_mac_driver);
199 }
200 /*---------------------------------------------------------------------------*/
201 static int
202 read(void)
203 {
204  int len;
205  packetbuf_clear();
206  len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
208  return len;
209 }
210 /*---------------------------------------------------------------------------*/
211 static void
212 set_receive_function(void (* recv)(const struct mac_driver *))
213 {
214  receiver_callback = recv;
215 }
216 /*---------------------------------------------------------------------------*/
217 static int
218 on(void)
219 {
220  return radio->on();
221 }
222 /*---------------------------------------------------------------------------*/
223 static int
224 off(int keep_radio_on)
225 {
226  if(keep_radio_on) {
227  return radio->on();
228  } else {
229  return radio->off();
230  }
231 }
232 /*---------------------------------------------------------------------------*/
233 const struct mac_driver *
234 tdma_mac_init(const struct radio_driver *d)
235 {
236  int i;
237  for(i = 0; i < NUM_PACKETS; i++) {
238  data[i] = NULL;
239  }
240 
241  radio = d;
242  radio->set_receive_function(input);
243  radio->on();
244 
245  return &tdma_mac_driver;
246 }
247 /*---------------------------------------------------------------------------*/
248 const struct mac_driver tdma_mac_driver = {
249  "TDMA MAC",
250  tdma_mac_init,
251  send,
252  read,
253  set_receive_function,
254  on,
255  off,
256 };