45 #include "dev/watchdog.h"
47 #include "lib/random.h"
55 #include "contiki-conf.h"
57 #ifdef EXPERIMENT_SETUP
58 #include "experiment-setup.h"
63 #ifndef WITH_ACK_OPTIMIZATION
64 #define WITH_ACK_OPTIMIZATION 1
66 #ifndef WITH_ENCOUNTER_OPTIMIZATION
67 #define WITH_ENCOUNTER_OPTIMIZATION 1
69 #ifndef WITH_STREAMING
70 #define WITH_STREAMING 1
72 #ifndef WITH_STROBE_BROADCAST
73 #define WITH_STROBE_BROADCAST 0
76 struct announcement_data {
83 #define ANNOUNCEMENT_MAX 10
86 struct announcement_msg {
88 struct announcement_data data[ANNOUNCEMENT_MAX];
93 #define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t))
96 #define TYPE_STROBE 0x10
98 #define TYPE_ANNOUNCEMENT 0x12
99 #define TYPE_STROBE_ACK 0x13
106 #define MAX_STROBE_SIZE 50
108 #ifdef CXMAC_CONF_ON_TIME
109 #define DEFAULT_ON_TIME (CXMAC_CONF_ON_TIME)
111 #define DEFAULT_ON_TIME (RTIMER_ARCH_SECOND / 160)
114 #ifdef CXMAC_CONF_OFF_TIME
115 #define DEFAULT_OFF_TIME (CXMAC_CONF_OFF_TIME)
117 #define DEFAULT_OFF_TIME (RTIMER_ARCH_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE - DEFAULT_ON_TIME)
120 #define DEFAULT_PERIOD (DEFAULT_OFF_TIME + DEFAULT_ON_TIME)
122 #define WAIT_TIME_BEFORE_STROBE_ACK RTIMER_ARCH_SECOND / 1000
128 #if DEFAULT_PERIOD == 0
129 #undef DEFAULT_PERIOD
130 #define DEFAULT_PERIOD 1
134 #define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND
138 #define ANNOUNCEMENT_TIME (random_rand() % (ANNOUNCEMENT_PERIOD))
140 #define DEFAULT_STROBE_WAIT_TIME (7 * DEFAULT_ON_TIME / 8)
142 struct cxmac_config cxmac_config = {
145 4 * DEFAULT_ON_TIME + DEFAULT_OFF_TIME,
146 DEFAULT_STROBE_WAIT_TIME
153 static volatile uint8_t cxmac_is_on = 0;
155 static volatile unsigned char waiting_for_packet = 0;
156 static volatile unsigned char someone_is_sending = 0;
157 static volatile unsigned char we_are_sending = 0;
158 static volatile unsigned char radio_is_on = 0;
164 #define LEDS_ON(x) leds_on(x)
165 #define LEDS_OFF(x) leds_off(x)
166 #define LEDS_TOGGLE(x) leds_toggle(x)
170 #define PRINTF(...) printf(__VA_ARGS__)
171 #define PRINTDEBUG(...) printf(__VA_ARGS__)
178 #define LEDS_TOGGLE(x)
180 #define PRINTDEBUG(...)
183 #if CXMAC_CONF_ANNOUNCEMENTS
185 static struct ctimer announcement_cycle_ctimer, announcement_ctimer;
187 static int announcement_radio_txpower;
192 static uint8_t is_listening;
194 #if CXMAC_CONF_COMPOWER
198 #if WITH_ENCOUNTER_OPTIMIZATION
204 struct encounter *
next;
209 #define MAX_ENCOUNTERS 4
210 LIST(encounter_list);
211 MEMB(encounter_memb,
struct encounter, MAX_ENCOUNTERS);
214 static uint8_t is_streaming;
215 static rimeaddr_t is_streaming_to, is_streaming_to_too;
216 static rtimer_clock_t stream_until;
217 #define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
220 #define MIN(a, b) ((a) < (b)? (a) : (b))
227 if(cxmac_is_on && radio_is_on == 0) {
237 if(cxmac_is_on && radio_is_on != 0 && is_listening == 0 &&
240 NETSTACK_RADIO.off();
246 powercycle_turn_radio_off(
void)
248 if(we_are_sending == 0 &&
249 waiting_for_packet == 0) {
252 #if CXMAC_CONF_COMPOWER
257 powercycle_turn_radio_on(
void)
259 if(we_are_sending == 0 &&
260 waiting_for_packet == 0) {
265 static struct ctimer cpowercycle_ctimer;
266 #define CSCHEDULE_POWERCYCLE(rtime) cschedule_powercycle((1ul * CLOCK_SECOND * (rtime)) / RTIMER_ARCH_SECOND)
267 static char cpowercycle(
void *ptr);
269 cschedule_powercycle(clock_time_t time)
277 (
void (*)(
void *))cpowercycle,
NULL);
282 cpowercycle(
void *ptr)
285 if(!RTIMER_CLOCK_LT(
RTIMER_NOW(), stream_until)) {
296 if(someone_is_sending > 0) {
297 someone_is_sending--;
301 powercycle_turn_radio_on();
302 CSCHEDULE_POWERCYCLE(DEFAULT_ON_TIME);
305 if(cxmac_config.off_time > 0) {
306 powercycle_turn_radio_off();
307 if(waiting_for_packet != 0) {
308 waiting_for_packet++;
309 if(waiting_for_packet > 2) {
313 waiting_for_packet = 0;
314 powercycle_turn_radio_off();
317 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
325 #if CXMAC_CONF_ANNOUNCEMENTS
327 parse_announcements(
const rimeaddr_t *from)
330 struct announcement_msg adata;
343 for(i = 0; i < adata.num; ++i) {
351 adata.data[i].value);
357 format_announcement(
char *hdr)
359 struct announcement_msg adata;
367 a !=
NULL && adata.num < ANNOUNCEMENT_MAX;
369 adata.data[adata.num].id = a->id;
370 adata.data[adata.num].value = a->value;
374 memcpy(hdr, &adata,
sizeof(
struct announcement_msg));
377 return ANNOUNCEMENT_MSG_HEADERLEN +
378 sizeof(
struct announcement_data) * adata.num;
385 #if WITH_ENCOUNTER_OPTIMIZATION
387 register_encounter(
const rimeaddr_t *neighbor, rtimer_clock_t time)
417 rtimer_clock_t encounter_time = 0;
419 struct cxmac_hdr *hdr;
420 int got_strobe_ack = 0;
421 uint8_t strobe[MAX_STROBE_SIZE];
423 int is_broadcast = 0;
426 struct queuebuf *packet;
427 int is_already_streaming = 0;
435 PRINTDEBUG(
"cxmac: send broadcast\n");
438 PRINTDEBUG(
"cxmac: send unicast to %02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
439 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
440 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1],
441 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[2],
442 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[3],
443 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[4],
444 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[5],
445 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[6],
446 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[7]);
448 PRINTDEBUG(
"cxmac: send unicast to %u.%u\n",
449 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0],
450 packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
453 is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
454 packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);
455 len = NETSTACK_FRAMER.create();
456 strobe_len = len +
sizeof(
struct cxmac_hdr);
457 if(len == 0 || strobe_len > (
int)
sizeof(strobe)) {
459 PRINTF(
"cxmac: send failed, too large header\n");
460 return MAC_TX_ERR_FATAL;
463 strobe[len] = DISPATCH;
464 strobe[len + 1] = TYPE_STROBE;
467 packet = queuebuf_new_from_packetbuf();
470 PRINTF(
"cxmac: send failed, no queue buffer available (of %u)\n",
476 if(is_streaming == 1 &&
480 &is_streaming_to_too))) {
481 is_already_streaming = 1;
483 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
484 PACKETBUF_ATTR_PACKET_TYPE_STREAM) {
487 rimeaddr_copy(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
488 }
else if(!
rimeaddr_cmp(&is_streaming_to, packetbuf_addr(PACKETBUF_ADDR_RECEIVER))) {
489 rimeaddr_copy(&is_streaming_to_too, packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
491 stream_until =
RTIMER_NOW() + DEFAULT_STREAM_TIME;
497 #if WITH_ENCOUNTER_OPTIMIZATION
503 const rimeaddr_t *neighbor = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
506 rtimer_clock_t wait, now, expected;
516 wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
517 expected = now + wait - 2 * DEFAULT_ON_TIME;
519 #if WITH_ACK_OPTIMIZATION
521 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
522 PACKETBUF_ATTR_PACKET_TYPE_ACK &&
526 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), expected));
530 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), expected));
550 if(!is_already_streaming) {
554 for(strobes = 0, collisions = 0;
555 got_strobe_ack == 0 && collisions == 0 &&
556 RTIMER_CLOCK_LT(
RTIMER_NOW(), t0 + cxmac_config.strobe_time);
559 while(got_strobe_ack == 0 &&
560 RTIMER_CLOCK_LT(
RTIMER_NOW(), t + cxmac_config.strobe_wait_time)) {
568 if(NETSTACK_FRAMER.parse()) {
570 if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE_ACK) {
571 if(
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
576 encounter_time = now;
578 PRINTDEBUG(
"cxmac: strobe ack for someone else\n");
581 PRINTDEBUG(
"cxmac: strobe from someone else\n");
585 PRINTF(
"cxmac: send failed to parse %u\n", len);
592 if(got_strobe_ack == 0 && collisions == 0) {
594 #if WITH_STROBE_BROADCAST
595 NETSTACK_RADIO.send(strobe, strobe_len);
598 queuebuf_to_packetbuf(packet);
603 NETSTACK_RADIO.send(strobe, strobe_len);
610 while(RTIMER_CLOCK_LT(
RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
618 #if WITH_ACK_OPTIMIZATION
622 if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
623 packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
624 packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
625 PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
627 waiting_for_packet = 1;
636 queuebuf_to_packetbuf(packet);
637 queuebuf_free(packet);
640 if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
644 #if WITH_ENCOUNTER_OPTIMIZATION
645 if(got_strobe_ack && !is_streaming) {
646 register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), encounter_time);
651 PRINTF(
"cxmac: send (strobes=%u,len=%u,%s), done\n", strobes,
654 #if CXMAC_CONF_COMPOWER
672 if(collisions == 0) {
673 if(!is_broadcast && !got_strobe_ack) {
679 someone_is_sending++;
686 qsend_packet(mac_callback_t sent,
void *ptr)
689 if(someone_is_sending) {
690 PRINTF(
"cxmac: should queue packet, now just dropping %d %d %d %d.\n",
691 waiting_for_packet, someone_is_sending, we_are_sending, radio_is_on);
692 RIMESTATS_ADD(sendingdrop);
695 PRINTF(
"cxmac: send immediately.\n");
699 mac_call_sent_callback(sent, ptr, ret, 1);
705 struct cxmac_hdr *hdr;
707 if(NETSTACK_FRAMER.parse()) {
710 if(hdr->dispatch != DISPATCH) {
711 someone_is_sending = 0;
712 if(
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
723 #if CXMAC_CONF_COMPOWER
737 waiting_for_packet = 0;
740 NETSTACK_MAC.input();
743 PRINTDEBUG(
"cxmac: data not for us\n");
746 }
else if(hdr->type == TYPE_STROBE) {
747 someone_is_sending = 2;
749 if(
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
757 hdr->type = TYPE_STROBE_ACK;
758 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER,
759 packetbuf_addr(PACKETBUF_ADDR_SENDER));
762 if(NETSTACK_FRAMER.create()) {
765 someone_is_sending = 1;
766 waiting_for_packet = 1;
771 PRINTF(
"cxmac: failed to send strobe ack\n");
773 }
else if(
rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
779 waiting_for_packet = 1;
782 PRINTDEBUG(
"cxmac: strobe not for us\n");
788 #if CXMAC_CONF_ANNOUNCEMENTS
789 }
else if(hdr->type == TYPE_ANNOUNCEMENT) {
791 parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER));
793 }
else if(hdr->type == TYPE_STROBE_ACK) {
794 PRINTDEBUG(
"cxmac: stray strobe ack\n");
796 PRINTF(
"cxmac: unknown type %u (%u)\n", hdr->type,
804 #if CXMAC_CONF_ANNOUNCEMENTS
806 send_announcement(
void *ptr)
808 struct cxmac_hdr *hdr;
809 int announcement_len;
815 announcement_len = format_announcement((
char *)hdr +
816 sizeof(
struct cxmac_hdr));
818 if(announcement_len > 0) {
820 hdr->dispatch = DISPATCH;
821 hdr->type = TYPE_ANNOUNCEMENT;
825 packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER, announcement_radio_txpower);
826 if(NETSTACK_FRAMER.create()) {
833 cycle_announcement(
void *ptr)
835 ctimer_set(&announcement_ctimer, ANNOUNCEMENT_TIME,
836 send_announcement,
NULL);
837 ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_PERIOD,
838 cycle_announcement,
NULL);
839 if(is_listening > 0) {
846 listen_callback(
int periods)
848 is_listening = periods + 1;
853 cxmac_set_announcement_radio_txpower(
int txpower)
855 #if CXMAC_CONF_ANNOUNCEMENTS
856 announcement_radio_txpower = txpower;
864 waiting_for_packet = 0;
871 #if WITH_ENCOUNTER_OPTIMIZATION
876 #if CXMAC_CONF_ANNOUNCEMENTS
878 ctimer_set(&announcement_cycle_ctimer, ANNOUNCEMENT_TIME,
879 cycle_announcement,
NULL);
882 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
891 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME);
896 turn_off(
int keep_radio_on)
900 return NETSTACK_RADIO.on();
902 return NETSTACK_RADIO.off();
906 static unsigned short
907 channel_check_interval(
void)
909 return (1ul *
CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;