Bugfix: memory from the wrong memb was freed.
[contiki-2.x.git] / core / net / mac / phase.c
blobfe9f6a97bb5c23bed5863c9a7ece89220d9d4b3d
1 /*
2 * Copyright (c) 2010, Swedish Institute of Computer Science.
3 * All rights reserved.
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.
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.
29 * This file is part of the Contiki operating system.
31 * $Id: phase.c,v 1.9 2010/04/04 21:02:09 adamdunkels Exp $
34 /**
35 * \file
36 * Common functionality for phase optimization in duty cycling radio protocols
37 * \author
38 * Adam Dunkels <adam@sics.se>
41 #include "net/mac/phase.h"
42 #include "net/rime/packetbuf.h"
43 #include "sys/clock.h"
44 #include "lib/memb.h"
45 #include "net/rime/ctimer.h"
46 #include "net/rime/queuebuf.h"
47 #include "dev/watchdog.h"
48 #include "dev/leds.h"
50 struct phase_queueitem {
51 struct ctimer timer;
52 mac_callback_t mac_callback;
53 void *mac_callback_ptr;
54 struct queuebuf *q;
57 #define PHASE_DEFER_THRESHOLD 1
58 #define PHASE_QUEUESIZE 8
60 #define MAX_NOACKS 2
62 MEMB(queued_packets_memb, struct phase_queueitem, PHASE_QUEUESIZE);
64 #define DEBUG 1
65 #if DEBUG
66 #include <stdio.h>
67 #define PRINTF(...) printf(__VA_ARGS__)
68 #define PRINTDEBUG(...) printf(__VA_ARGS__)
69 #else
70 #define PRINTF(...)
71 #define PRINTDEBUG(...)
72 #endif
73 /*---------------------------------------------------------------------------*/
74 struct phase *
75 find_neighbor(const struct phase_list *list, const rimeaddr_t *addr)
77 struct phase *e;
78 for(e = list_head(*list->list); e != NULL; e = e->next) {
79 if(rimeaddr_cmp(addr, &e->neighbor)) {
80 return e;
83 return NULL;
85 /*---------------------------------------------------------------------------*/
86 void
87 phase_remove(const struct phase_list *list, const rimeaddr_t *neighbor)
89 struct phase *e;
90 e = find_neighbor(list, neighbor);
91 if(e != NULL) {
92 list_remove(*list->list, e);
93 memb_free(list->memb, e);
96 /*---------------------------------------------------------------------------*/
97 void
98 phase_update(const struct phase_list *list,
99 const rimeaddr_t *neighbor, rtimer_clock_t time,
100 int mac_status)
102 struct phase *e;
104 /* If we have an entry for this neighbor already, we renew it. */
105 e = find_neighbor(list, neighbor);
106 if(e != NULL) {
107 if(mac_status == MAC_TX_OK) {
108 e->time = time;
111 /* If the neighbor didn't reply to us, it may have switched
112 phase (rebooted). We try a number of transmissions to it
113 before we drop it from the phase list. */
114 if(mac_status == MAC_TX_NOACK) {
115 PRINTF("phase noacks %d to %d.%d\n", e->noacks, neighbor->u8[0], neighbor->u8[1]);
116 e->noacks++;
117 if(e->noacks >= MAX_NOACKS) {
118 list_remove(*list->list, e);
119 memb_free(list->memb, e);
120 return;
122 } else if(mac_status == MAC_TX_OK) {
123 e->noacks = 0;
125 } else {
126 /* No matching phase was found, so we allocate a new one. */
127 if(mac_status == MAC_TX_OK && e == NULL) {
128 e = memb_alloc(list->memb);
129 if(e == NULL) {
130 printf("phase alloc NULL\n");
131 /* We could not allocate memory for this phase, so we drop
132 the last item on the list and reuse it for our phase. */
133 e = list_chop(*list->list);
135 rimeaddr_copy(&e->neighbor, neighbor);
136 e->time = time;
137 e->noacks = 0;
138 list_push(*list->list, e);
142 /*---------------------------------------------------------------------------*/
143 static void
144 send_packet(void *ptr)
146 struct phase_queueitem *p = ptr;
148 queuebuf_to_packetbuf(p->q);
149 queuebuf_free(p->q);
150 memb_free(&queued_packets_memb, p);
151 NETSTACK_RDC.send(p->mac_callback, p->mac_callback_ptr);
153 /*---------------------------------------------------------------------------*/
154 phase_status_t
155 phase_wait(struct phase_list *list,
156 const rimeaddr_t *neighbor, rtimer_clock_t cycle_time,
157 rtimer_clock_t wait_before,
158 mac_callback_t mac_callback, void *mac_callback_ptr)
160 struct phase *e;
161 // const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
162 /* We go through the list of phases to find if we have recorded a
163 phase for this particular neighbor. If so, we can compute the
164 time for the next expected phase and setup a ctimer to switch on
165 the radio just before the phase. */
166 e = find_neighbor(list, neighbor);
167 if(e != NULL) {
168 rtimer_clock_t wait, now, expected, additional_wait;
169 clock_time_t ctimewait;
171 /* We expect phases to happen every CYCLE_TIME time
172 units. The next expected phase is at time e->time +
173 CYCLE_TIME. To compute a relative offset, we subtract
174 with clock_time(). Because we are only interested in turning
175 on the radio within the CYCLE_TIME period, we compute the
176 waiting time with modulo CYCLE_TIME. */
178 /* printf("neighbor phase 0x%02x (cycle 0x%02x)\n", e->time & (cycle_time - 1),
179 cycle_time);*/
181 additional_wait = 2 * e->noacks * wait_before;
183 /* if(e->noacks > 0) {
184 printf("additional wait %d\n", additional_wait);
187 now = RTIMER_NOW();
188 wait = (rtimer_clock_t)((e->time - now) &
189 (cycle_time - 1));
190 if(wait < wait_before + additional_wait) {
191 wait += cycle_time;
194 ctimewait = (CLOCK_SECOND * (wait - wait_before - additional_wait)) / RTIMER_ARCH_SECOND;
196 if(ctimewait > PHASE_DEFER_THRESHOLD) {
197 struct phase_queueitem *p;
199 p = memb_alloc(&queued_packets_memb);
200 if(p != NULL) {
201 p->q = queuebuf_new_from_packetbuf();
202 if(p->q != NULL) {
203 p->mac_callback = mac_callback;
204 p->mac_callback_ptr = mac_callback_ptr;
205 ctimer_set(&p->timer, ctimewait, send_packet, p);
206 return PHASE_DEFERRED;
207 } else {
208 memb_free(&queued_packets_memb, p);
213 expected = now + wait - wait_before - additional_wait;
214 if(!RTIMER_CLOCK_LT(expected, now)) {
215 /* Wait until the receiver is expected to be awake */
216 while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected)) {
219 return PHASE_SEND_NOW;
221 return PHASE_UNKNOWN;
223 /*---------------------------------------------------------------------------*/
224 void
225 phase_init(struct phase_list *list)
227 list_init(*list->list);
228 memb_init(list->memb);
229 memb_init(&queued_packets_memb);
231 /*---------------------------------------------------------------------------*/