Contiki 2.5
ctdma_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: ctdma_mac.c,v 1.6 2010/06/14 19:19:16 adamdunkels Exp $
32  */
33 
34 #include "contiki.h"
35 #include "net/mac/ctdma_mac.h"
36 #include "net/packetbuf.h"
37 #include "net/uip-fw.h"
38 #include "sys/ctimer.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 */
62 #define NR_SLOTS 3
63 #define SLOT_LENGTH (CLOCK_SECOND/3)
64 #define GUARD_PERIOD (CLOCK_SECOND/12)
65 
66 #define MY_SLOT (node_id % NR_SLOTS)
67 #define PERIOD_LENGTH CLOCK_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 ctimer ctimer;
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 void
87 transmitter(void *ptr)
88 {
89  clock_time_t now, rest, period_start, slot_start;
90 
91  /* Calculate slot start time */
92  now = clock_time();
93  rest = now % PERIOD_LENGTH;
94  period_start = now - rest;
95  slot_start = period_start + MY_SLOT*SLOT_LENGTH;
96 
97  /* Check if we are inside our slot */
98  if (now < slot_start ||
99  now > slot_start + SLOT_LENGTH - GUARD_PERIOD)
100  {
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  {
104  slot_start += PERIOD_LENGTH;
105  }
106 
107  PRINTF("TIMER Rescheduling until %u\n", slot_start);
108  ctimer_set(&ctimer, slot_start - clock_time(), transmitter, NULL);
109  return;
110  }
111 
112  /* Transmit queued packets */
113  while (nextsend != freeslot)
114  {
115  PRINTF("RADIO Transmitting packet #%i\n", id[nextsend]);
116  if(!radio->send(
117  queuebuf_dataptr(data[nextsend]),
118  queuebuf_datalen(data[nextsend])))
119  {
120  sent_counter++;
121  PRINTF("RADIO Transmit OK for #%i, total=%i\n", id[nextsend], sent_counter);
122  DLEDS_TOGGLE(LEDS_GREEN);
123  }
124  else
125  {
126  PRINTF("RADIO Transmit failed for #%i, total=%i\n", id[nextsend], sent_counter);
127  DLEDS_TOGGLE(LEDS_RED);
128  }
129 
130  nextsend = (nextsend + 1) % NUM_PACKETS;
131 
132  /* Recalculate new slot */
133  if (clock_time() > slot_start + SLOT_LENGTH - GUARD_PERIOD)
134  {
135  PRINTF("TIMER No more time to transmit\n");
136  break;
137  }
138  }
139 
140  /* Calculate time of our next slot */
141  slot_start += PERIOD_LENGTH;
142  PRINTF("TIMER Rescheduling until %u\n", slot_start);
143  ctimer_set(&ctimer, slot_start - clock_time(), transmitter, NULL);
144 }
145 /*---------------------------------------------------------------------------*/
146 static int
147 send(void)
148 {
149  id_counter++;
150 
151  /* Clean up already sent packets */
152  while (lastqueued != nextsend)
153  {
154  PRINTF("BUFFER Cleaning up packet #%i\n", id[lastqueued]);
155  queuebuf_free(data[lastqueued]);
156  data[lastqueued] = NULL;
157 
158  lastqueued = (lastqueued + 1) % NUM_PACKETS;
159  }
160 
161  if ((freeslot + 1) % NUM_PACKETS == lastqueued)
162  {
163  PRINTF("BUFFER Buffer full, dropping packet #%i\n", (id_counter+1));
164  return UIP_FW_DROPPED;
165  }
166 
167  /* Allocate queue buf for packet */
168  data[freeslot] = queuebuf_new_from_packetbuf();
169  id[freeslot] = id_counter;
170  if (data[freeslot] == NULL)
171  {
172  PRINTF("BUFFER Queuebuffer full, dropping packet #%i\n", id[freeslot]);
173  return UIP_FW_DROPPED;
174  }
175  PRINTF("BUFFER Wrote packet #%i to buffer \n", id[freeslot]);
176 
177  freeslot = (freeslot + 1) % NUM_PACKETS;
178 
179  if (!timer_on)
180  {
181  PRINTF("TIMER Starting timer\n");
182  ctimer_set(&ctimer, CLOCK_SECOND, transmitter, NULL);
183  timer_on = 1;
184  }
185 
186  return UIP_FW_OK; /* TODO Return what? */
187 }
188 /*---------------------------------------------------------------------------*/
189 static void
190 input(const struct radio_driver *d)
191 {
192  receiver_callback(&ctdma_mac_driver);
193 }
194 /*---------------------------------------------------------------------------*/
195 static int
196 read(void)
197 {
198  int len;
199  packetbuf_clear();
200  len = radio->read(packetbuf_dataptr(), PACKETBUF_SIZE);
202  return len;
203 }
204 /*---------------------------------------------------------------------------*/
205 static void
206 set_receive_function(void (* recv)(const struct mac_driver *))
207 {
208  receiver_callback = recv;
209 }
210 /*---------------------------------------------------------------------------*/
211 static int
212 on(void)
213 {
214  return radio->on();
215 }
216 /*---------------------------------------------------------------------------*/
217 static int
218 off(int keep_radio_on)
219 {
220  if(keep_radio_on) {
221  return radio->on();
222  } else {
223  return radio->off();
224  }
225 }
226 /*---------------------------------------------------------------------------*/
227 const struct mac_driver *
228 ctdma_mac_init(const struct radio_driver *d)
229 {
230  int i;
231  for (i=0; i < NUM_PACKETS; i++)
232  {
233  data[i] = NULL;
234  }
235 
236  radio = d;
237  radio->set_receive_function(input);
238  radio->on();
239  return &ctdma_mac_driver;
240 }
241 /*---------------------------------------------------------------------------*/
242 const struct mac_driver ctdma_mac_driver = {
243  "CTDMA",
244  ctdma_mac_init,
245  send,
246  read,
247  set_receive_function,
248  on,
249  off,
250 };