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/csma.h"
00042 #include "net/packetbuf.h"
00043 #include "net/queuebuf.h"
00044
00045 #include "sys/ctimer.h"
00046
00047 #include "lib/random.h"
00048
00049 #include "net/netstack.h"
00050
00051 #include "lib/list.h"
00052 #include "lib/memb.h"
00053
00054 #include <string.h>
00055
00056 #include <stdio.h>
00057
00058 #define DEBUG 0
00059 #if DEBUG
00060 #include <stdio.h>
00061 #define PRINTF(...) printf(__VA_ARGS__)
00062 #else
00063 #define PRINTF(...)
00064 #endif
00065
00066 #ifndef CSMA_MAX_MAC_TRANSMISSIONS
00067 #ifdef CSMA_CONF_MAX_MAC_TRANSMISSIONS
00068 #define CSMA_MAX_MAC_TRANSMISSIONS CSMA_CONF_MAX_MAC_TRANSMISSIONS
00069 #else
00070 #define CSMA_MAX_MAC_TRANSMISSIONS 3
00071 #endif
00072 #endif
00073
00074 #if CSMA_MAX_MAC_TRANSMISSIONS < 1
00075 #error CSMA_CONF_MAX_MAC_TRANSMISSIONS must be at least 1.
00076 #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
00077 #endif
00078
00079 struct queued_packet {
00080 struct queued_packet *next;
00081 struct queuebuf *buf;
00082
00083 mac_callback_t sent;
00084 void *cptr;
00085 uint8_t transmissions, max_transmissions;
00086 uint8_t collisions, deferrals;
00087 };
00088
00089 #define MAX_QUEUED_PACKETS 6
00090 MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
00091 LIST(queued_packet_list);
00092
00093 static struct ctimer transmit_timer;
00094
00095 static uint8_t rdc_is_transmitting;
00096
00097 static void packet_sent(void *ptr, int status, int num_transmissions);
00098
00099
00100 static clock_time_t
00101 default_timebase(void)
00102 {
00103 clock_time_t time;
00104
00105
00106 time = NETSTACK_RDC.channel_check_interval();
00107
00108
00109
00110
00111 if(time == 0) {
00112 time = CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE;
00113 }
00114 return time;
00115 }
00116
00117 static void
00118 transmit_queued_packet(void *ptr)
00119 {
00120
00121 struct queued_packet *q;
00122
00123
00124
00125 if(rdc_is_transmitting) {
00126 return;
00127 }
00128
00129
00130
00131 q = list_head(queued_packet_list);
00132
00133 if(q != NULL) {
00134 queuebuf_to_packetbuf(q->buf);
00135 PRINTF("csma: sending number %d %p, queue len %d\n", q->transmissions, q,
00136 list_length(queued_packet_list));
00137
00138 rdc_is_transmitting = 1;
00139 NETSTACK_RDC.send(packet_sent, q);
00140 }
00141 }
00142
00143 static void
00144 start_transmission_timer(void)
00145 {
00146 PRINTF("csma: start_transmission_timer, queue len %d\n",
00147 list_length(queued_packet_list));
00148 if(list_length(queued_packet_list) > 0) {
00149 if(ctimer_expired(&transmit_timer)) {
00150 ctimer_set(&transmit_timer, 0,
00151 transmit_queued_packet, NULL);
00152 }
00153 }
00154 }
00155
00156 static void
00157 free_queued_packet(void)
00158 {
00159 struct queued_packet *q;
00160
00161
00162
00163 q = list_head(queued_packet_list);
00164
00165 if(q != NULL) {
00166 queuebuf_free(q->buf);
00167 list_remove(queued_packet_list, q);
00168 memb_free(&packet_memb, q);
00169 PRINTF("csma: free_queued_packet, queue length %d\n",
00170 list_length(queued_packet_list));
00171 if(list_length(queued_packet_list) > 0) {
00172 ctimer_set(&transmit_timer, default_timebase(), transmit_queued_packet, NULL);
00173 }
00174 }
00175 }
00176
00177 static void
00178 packet_sent(void *ptr, int status, int num_transmissions)
00179 {
00180 struct queued_packet *q = ptr;
00181 clock_time_t time = 0;
00182 mac_callback_t sent;
00183 void *cptr;
00184 int num_tx;
00185 int backoff_transmissions;
00186
00187 rdc_is_transmitting = 0;
00188
00189 switch(status) {
00190 case MAC_TX_OK:
00191 case MAC_TX_NOACK:
00192 q->transmissions++;
00193 break;
00194 case MAC_TX_COLLISION:
00195 q->collisions++;
00196 break;
00197 case MAC_TX_DEFERRED:
00198 q->deferrals++;
00199 break;
00200 }
00201
00202 sent = q->sent;
00203 cptr = q->cptr;
00204 num_tx = q->transmissions;
00205
00206 if(status == MAC_TX_COLLISION ||
00207 status == MAC_TX_NOACK) {
00208
00209
00210
00211
00212 switch(status) {
00213 case MAC_TX_COLLISION:
00214 PRINTF("csma: rexmit collision %d\n", q->transmissions);
00215 break;
00216 case MAC_TX_NOACK:
00217 PRINTF("csma: rexmit noack %d\n", q->transmissions);
00218 break;
00219 default:
00220 PRINTF("csma: rexmit err %d, %d\n", status, q->transmissions);
00221 }
00222
00223
00224
00225 time = default_timebase();
00226
00227
00228
00229
00230 backoff_transmissions = q->transmissions + 1;
00231
00232
00233
00234
00235 if(backoff_transmissions > 3) {
00236 backoff_transmissions = 3;
00237 }
00238 time = time + (random_rand() % (backoff_transmissions * time));
00239
00240 if(q->transmissions < q->max_transmissions) {
00241 PRINTF("csma: retransmitting with time %lu %p\n", time, q);
00242 ctimer_set(&transmit_timer, time,
00243 transmit_queued_packet, NULL);
00244 } else {
00245 PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
00246 status, q->transmissions, q->collisions);
00247
00248 free_queued_packet();
00249 mac_call_sent_callback(sent, cptr, status, num_tx);
00250 }
00251 } else {
00252 if(status == MAC_TX_OK) {
00253 PRINTF("csma: rexmit ok %d\n", q->transmissions);
00254 } else {
00255 PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
00256 }
00257
00258 free_queued_packet();
00259 mac_call_sent_callback(sent, cptr, status, num_tx);
00260 }
00261 }
00262
00263 static void
00264 send_packet(mac_callback_t sent, void *ptr)
00265 {
00266 struct queued_packet *q;
00267 static uint16_t seqno;
00268
00269 packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
00270
00271
00272
00273 if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00274 &rimeaddr_null)) {
00275
00276
00277 q = memb_alloc(&packet_memb);
00278 if(q != NULL) {
00279 q->buf = queuebuf_new_from_packetbuf();
00280 if(q->buf != NULL) {
00281 if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
00282
00283 q->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
00284 } else {
00285 q->max_transmissions =
00286 packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
00287 }
00288 q->transmissions = 0;
00289 q->collisions = 0;
00290 q->deferrals = 0;
00291 q->sent = sent;
00292 q->cptr = ptr;
00293 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
00294 PACKETBUF_ATTR_PACKET_TYPE_ACK) {
00295 list_push(queued_packet_list, q);
00296 } else {
00297 list_add(queued_packet_list, q);
00298 }
00299 start_transmission_timer();
00300 return;
00301 }
00302 memb_free(&packet_memb, q);
00303 PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
00304 }
00305 PRINTF("csma: could not allocate memb, will drop if collision or noack\n");
00306 } else {
00307 PRINTF("csma: send broadcast (%d) or without retransmissions (%d)\n",
00308 !rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
00309 &rimeaddr_null),
00310 packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS));
00311 }
00312 NETSTACK_RDC.send(sent, ptr);
00313 }
00314
00315 static void
00316 input_packet(void)
00317 {
00318 NETSTACK_NETWORK.input();
00319 }
00320
00321 static int
00322 on(void)
00323 {
00324 return NETSTACK_RDC.on();
00325 }
00326
00327 static int
00328 off(int keep_radio_on)
00329 {
00330 return NETSTACK_RDC.off(keep_radio_on);
00331 }
00332
00333 static unsigned short
00334 channel_check_interval(void)
00335 {
00336 if(NETSTACK_RDC.channel_check_interval) {
00337 return NETSTACK_RDC.channel_check_interval();
00338 }
00339 return 0;
00340 }
00341
00342 static void
00343 init(void)
00344 {
00345 memb_init(&packet_memb);
00346 rdc_is_transmitting = 0;
00347 }
00348
00349 const struct mac_driver csma_driver = {
00350 "CSMA",
00351 init,
00352 send_packet,
00353 input_packet,
00354 on,
00355 off,
00356 channel_check_interval,
00357 };
00358