phase.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "net/mac/phase.h"
00042 #include "net/packetbuf.h"
00043 #include "sys/clock.h"
00044 #include "lib/memb.h"
00045 #include "sys/ctimer.h"
00046 #include "net/queuebuf.h"
00047 #include "dev/watchdog.h"
00048 #include "dev/leds.h"
00049
00050 struct phase_queueitem {
00051 struct ctimer timer;
00052 mac_callback_t mac_callback;
00053 void *mac_callback_ptr;
00054 struct queuebuf *q;
00055 };
00056
00057 #define PHASE_DEFER_THRESHOLD 1
00058 #define PHASE_QUEUESIZE 8
00059
00060 #define MAX_NOACKS 16
00061
00062 #define MAX_NOACKS_TIME CLOCK_SECOND * 30
00063
00064 MEMB(queued_packets_memb, struct phase_queueitem, PHASE_QUEUESIZE);
00065
00066 #define DEBUG 0
00067 #if DEBUG
00068 #include <stdio.h>
00069 #define PRINTF(...) printf(__VA_ARGS__)
00070 #define PRINTDEBUG(...) printf(__VA_ARGS__)
00071 #else
00072 #define PRINTF(...)
00073 #define PRINTDEBUG(...)
00074 #endif
00075
00076 struct phase *
00077 find_neighbor(const struct phase_list *list, const rimeaddr_t *addr)
00078 {
00079 struct phase *e;
00080 for(e = list_head(*list->list); e != NULL; e = list_item_next(e)) {
00081 if(rimeaddr_cmp(addr, &e->neighbor)) {
00082 return e;
00083 }
00084 }
00085 return NULL;
00086 }
00087
00088 void
00089 phase_remove(const struct phase_list *list, const rimeaddr_t *neighbor)
00090 {
00091 struct phase *e;
00092 e = find_neighbor(list, neighbor);
00093 if(e != NULL) {
00094 list_remove(*list->list, e);
00095 memb_free(list->memb, e);
00096 }
00097 }
00098
00099 void
00100 phase_update(const struct phase_list *list,
00101 const rimeaddr_t *neighbor, rtimer_clock_t time,
00102 int mac_status)
00103 {
00104 struct phase *e;
00105
00106
00107 e = find_neighbor(list, neighbor);
00108 if(e != NULL) {
00109 if(mac_status == MAC_TX_OK) {
00110 e->time = time;
00111 }
00112
00113
00114
00115 if(mac_status == MAC_TX_NOACK) {
00116 PRINTF("phase noacks %d to %d.%d\n", e->noacks, neighbor->u8[0], neighbor->u8[1]);
00117 e->noacks++;
00118 if(e->noacks == 1) {
00119 timer_set(&e->noacks_timer, MAX_NOACKS_TIME);
00120 }
00121 if(e->noacks >= MAX_NOACKS || timer_expired(&e->noacks_timer)) {
00122 PRINTF("drop %d\n", neighbor->u8[0]);
00123 list_remove(*list->list, e);
00124 memb_free(list->memb, e);
00125 return;
00126 }
00127 } else if(mac_status == MAC_TX_OK) {
00128 e->noacks = 0;
00129 }
00130 } else {
00131
00132 if(mac_status == MAC_TX_OK && e == NULL) {
00133 e = memb_alloc(list->memb);
00134 if(e == NULL) {
00135 PRINTF("phase alloc NULL\n");
00136
00137
00138 e = list_chop(*list->list);
00139 }
00140 rimeaddr_copy(&e->neighbor, neighbor);
00141 e->time = time;
00142 e->noacks = 0;
00143 list_push(*list->list, e);
00144 }
00145 }
00146 }
00147
00148 static void
00149 send_packet(void *ptr)
00150 {
00151 struct phase_queueitem *p = ptr;
00152
00153 queuebuf_to_packetbuf(p->q);
00154 queuebuf_free(p->q);
00155 memb_free(&queued_packets_memb, p);
00156 NETSTACK_RDC.send(p->mac_callback, p->mac_callback_ptr);
00157 }
00158
00159 phase_status_t
00160 phase_wait(struct phase_list *list,
00161 const rimeaddr_t *neighbor, rtimer_clock_t cycle_time,
00162 rtimer_clock_t guard_time,
00163 mac_callback_t mac_callback, void *mac_callback_ptr)
00164 {
00165 struct phase *e;
00166
00167
00168
00169
00170
00171 e = find_neighbor(list, neighbor);
00172 if(e != NULL) {
00173 rtimer_clock_t wait, now, expected;
00174 clock_time_t ctimewait;
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 now = RTIMER_NOW();
00191 wait = (rtimer_clock_t)((e->time - now) &
00192 (cycle_time - 1));
00193 if(wait < guard_time) {
00194 wait += cycle_time;
00195 }
00196
00197 ctimewait = (CLOCK_SECOND * (wait - guard_time)) / RTIMER_ARCH_SECOND;
00198
00199 if(ctimewait > PHASE_DEFER_THRESHOLD) {
00200 struct phase_queueitem *p;
00201
00202 p = memb_alloc(&queued_packets_memb);
00203 if(p != NULL) {
00204 p->q = queuebuf_new_from_packetbuf();
00205 if(p->q != NULL) {
00206 p->mac_callback = mac_callback;
00207 p->mac_callback_ptr = mac_callback_ptr;
00208 ctimer_set(&p->timer, ctimewait, send_packet, p);
00209 return PHASE_DEFERRED;
00210 } else {
00211 memb_free(&queued_packets_memb, p);
00212 }
00213 }
00214 }
00215
00216 expected = now + wait - guard_time;
00217 if(!RTIMER_CLOCK_LT(expected, now)) {
00218
00219 while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected));
00220 }
00221 return PHASE_SEND_NOW;
00222 }
00223 return PHASE_UNKNOWN;
00224 }
00225
00226 void
00227 phase_init(struct phase_list *list)
00228 {
00229 list_init(*list->list);
00230 memb_init(list->memb);
00231 memb_init(&queued_packets_memb);
00232 }
00233