2 * Copyright (c) 2007, Swedish Institute of Computer Science.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
29 * This file is part of the Contiki operating system.
31 * $Id: cxmac.c,v 1.14 2010/08/01 21:18:07 dak664 Exp $
36 * A simple power saving MAC protocol based on X-MAC [SenSys 2006]
38 * Adam Dunkels <adam@sics.se>
39 * Niclas Finne <nfi@sics.se>
40 * Joakim Eriksson <joakime@sics.se>
44 #include "dev/radio.h"
45 #include "dev/watchdog.h"
46 #include "net/netstack.h"
47 #include "lib/random.h"
48 #include "net/mac/cxmac.h"
50 #include "net/rime/timesynch.h"
51 #include "sys/compower.h"
53 #include "sys/rtimer.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
{
81 /* The maximum number of announcements in a single announcement
82 message - may need to be increased in the future. */
83 #define ANNOUNCEMENT_MAX 10
85 /* The structure of the announcement messages. */
86 struct announcement_msg
{
88 struct announcement_data data
[ANNOUNCEMENT_MAX
];
91 /* The length of the header of the announcement message, i.e., the
92 "num" field in the struct. */
93 #define ANNOUNCEMENT_MSG_HEADERLEN (sizeof (uint16_t))
96 #define TYPE_STROBE 0x10
97 /* #define TYPE_DATA 0x11 */
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 / MAC_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
124 /* On some platforms, we may end up with a DEFAULT_PERIOD that is 0
125 which will make compilation fail due to a modulo operation in the
126 code. To ensure that DEFAULT_PERIOD is greater than zero, we use
127 the construct below. */
128 #if DEFAULT_PERIOD == 0
129 #undef DEFAULT_PERIOD
130 #define DEFAULT_PERIOD 1
133 /* The cycle time for announcements. */
134 #define ANNOUNCEMENT_PERIOD 4 * CLOCK_SECOND
136 /* The time before sending an announcement within one announcement
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
184 /* Timers for keeping track of when to send announcements. */
185 static struct ctimer announcement_cycle_ctimer
, announcement_ctimer
;
187 static int announcement_radio_txpower
;
188 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
190 /* Flag that is used to keep track of whether or not we are listening
191 for announcements from neighbors. */
192 static uint8_t is_listening
;
194 #if CXMAC_CONF_COMPOWER
195 static struct compower_activity current_packet
;
196 #endif /* CXMAC_CONF_COMPOWER */
198 #if WITH_ENCOUNTER_OPTIMIZATION
200 #include "lib/list.h"
201 #include "lib/memb.h"
204 struct encounter
*next
;
209 #define MAX_ENCOUNTERS 4
210 LIST(encounter_list
);
211 MEMB(encounter_memb
, struct encounter
, MAX_ENCOUNTERS
);
212 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
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))
223 /*---------------------------------------------------------------------------*/
227 if(cxmac_is_on
&& radio_is_on
== 0) {
233 /*---------------------------------------------------------------------------*/
237 if(cxmac_is_on
&& radio_is_on
!= 0 && is_listening
== 0 &&
240 NETSTACK_RADIO
.off();
244 /*---------------------------------------------------------------------------*/
246 powercycle_turn_radio_off(void)
248 if(we_are_sending
== 0 &&
249 waiting_for_packet
== 0) {
252 #if CXMAC_CONF_COMPOWER
253 compower_accumulate(&compower_idle_activity
);
254 #endif /* CXMAC_CONF_COMPOWER */
257 powercycle_turn_radio_on(void)
259 if(we_are_sending
== 0 &&
260 waiting_for_packet
== 0) {
264 /*---------------------------------------------------------------------------*/
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
)
276 ctimer_set(&cpowercycle_ctimer
, time
,
277 (void (*)(void *))cpowercycle
, NULL
);
280 /*---------------------------------------------------------------------------*/
282 cpowercycle(void *ptr
)
285 if(!RTIMER_CLOCK_LT(RTIMER_NOW(), stream_until
)) {
287 rimeaddr_copy(&is_streaming_to
, &rimeaddr_null
);
288 rimeaddr_copy(&is_streaming_to_too
, &rimeaddr_null
);
295 /* Only wait for some cycles to pass for someone to start sending */
296 if(someone_is_sending
> 0) {
297 someone_is_sending
--;
300 /* If there were a strobe in the air, turn radio on */
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) {
310 /* We should not be awake for more than two consecutive
311 power cycles without having heard a packet, so we turn off
313 waiting_for_packet
= 0;
314 powercycle_turn_radio_off();
317 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME
);
324 /*---------------------------------------------------------------------------*/
325 #if CXMAC_CONF_ANNOUNCEMENTS
327 parse_announcements(const rimeaddr_t
*from
)
329 /* Parse incoming announcements */
330 struct announcement_msg adata
;
333 memcpy(&adata
, packetbuf_dataptr(), MIN(packetbuf_datalen(), sizeof(adata
)));
335 /* printf("%d.%d: probe from %d.%d with %d announcements\n",
336 rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
337 from->u8[0], from->u8[1], adata->num);*/
338 /* for(i = 0; i < packetbuf_datalen(); ++i) {
339 printf("%02x ", ((uint8_t *)packetbuf_dataptr())[i]);
343 for(i
= 0; i
< adata
.num
; ++i
) {
344 /* printf("%d.%d: announcement %d: %d\n",
345 rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
347 adata->data[i].value);*/
349 announcement_heard(from
,
351 adata
.data
[i
].value
);
355 /*---------------------------------------------------------------------------*/
357 format_announcement(char *hdr
)
359 struct announcement_msg adata
;
360 struct announcement
*a
;
362 /* Construct the announcements */
363 /* adata = (struct announcement_msg *)hdr;*/
366 for(a
= announcement_list();
367 a
!= NULL
&& adata
.num
< ANNOUNCEMENT_MAX
;
368 a
= list_item_next(a
)) {
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
;
383 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
384 /*---------------------------------------------------------------------------*/
385 #if WITH_ENCOUNTER_OPTIMIZATION
387 register_encounter(const rimeaddr_t
*neighbor
, rtimer_clock_t time
)
391 /* If we have an entry for this neighbor already, we renew it. */
392 for(e
= list_head(encounter_list
); e
!= NULL
; e
= list_item_next(e
)) {
393 if(rimeaddr_cmp(neighbor
, &e
->neighbor
)) {
398 /* No matching encounter was found, so we allocate a new one. */
400 e
= memb_alloc(&encounter_memb
);
402 /* We could not allocate memory for this encounter, so we just drop it. */
405 rimeaddr_copy(&e
->neighbor
, neighbor
);
407 list_add(encounter_list
, e
);
410 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
411 /*---------------------------------------------------------------------------*/
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;
431 /* Create the X-MAC header for the data packet. */
432 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, &rimeaddr_node_addr
);
433 if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
), &rimeaddr_null
)) {
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]);
451 #endif /* UIP_CONF_IPV6 */
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
> sizeof(strobe
)) {
459 PRINTF("cxmac: send failed, too large header\n");
460 return MAC_TX_ERR_FATAL
;
462 memcpy(strobe
, packetbuf_hdrptr(), len
);
463 strobe
[len
] = DISPATCH
; /* dispatch */
464 strobe
[len
+ 1] = TYPE_STROBE
; /* type */
467 packet
= queuebuf_new_from_packetbuf();
469 /* No buffer available */
470 PRINTF("cxmac: send failed, no queue buffer available (of %u)\n",
476 if(is_streaming
== 1 &&
477 (rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
479 rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
480 &is_streaming_to_too
))) {
481 is_already_streaming
= 1;
483 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE
) ==
484 PACKETBUF_ATTR_PACKET_TYPE_STREAM
) {
486 if(rimeaddr_cmp(&is_streaming_to
, &rimeaddr_null
)) {
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
;
493 #endif /* WITH_STREAMING */
497 #if WITH_ENCOUNTER_OPTIMIZATION
498 /* We go through the list of encounters to find if we have recorded
499 an encounter with this particular neighbor. If so, we can compute
500 the time for the next expected encounter and setup a ctimer to
501 switch on the radio just before the encounter. */
502 for(e
= list_head(encounter_list
); e
!= NULL
; e
= list_item_next(e
)) {
503 const rimeaddr_t
*neighbor
= packetbuf_addr(PACKETBUF_ADDR_RECEIVER
);
505 if(rimeaddr_cmp(neighbor
, &e
->neighbor
)) {
506 rtimer_clock_t wait
, now
, expected
;
508 /* We expect encounters to happen every DEFAULT_PERIOD time
509 units. The next expected encounter is at time e->time +
510 DEFAULT_PERIOD. To compute a relative offset, we subtract
511 with clock_time(). Because we are only interested in turning
512 on the radio within the DEFAULT_PERIOD period, we compute the
513 waiting time with modulo DEFAULT_PERIOD. */
516 wait
= ((rtimer_clock_t
)(e
->time
- now
)) % (DEFAULT_PERIOD
);
517 expected
= now
+ wait
- 2 * DEFAULT_ON_TIME
;
519 #if WITH_ACK_OPTIMIZATION
520 /* Wait until the receiver is expected to be awake */
521 if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE
) !=
522 PACKETBUF_ATTR_PACKET_TYPE_ACK
&&
524 /* Do not wait if we are sending an ACK, because then the
525 receiver will already be awake. */
526 while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected
));
528 #else /* WITH_ACK_OPTIMIZATION */
529 /* Wait until the receiver is expected to be awake */
530 while(RTIMER_CLOCK_LT(RTIMER_NOW(), expected
));
531 #endif /* WITH_ACK_OPTIMIZATION */
534 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
536 /* By setting we_are_sending to one, we ensure that the rtimer
537 powercycle interrupt do not interfere with us sending the packet. */
545 /* Send a train of strobes until the receiver answers with an ACK. */
547 /* Turn on the radio to listen for the strobe ACK. */
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
)) {
561 rtimer_clock_t now
= RTIMER_NOW();
563 /* See if we got an ACK */
565 len
= NETSTACK_RADIO
.read(packetbuf_dataptr(), PACKETBUF_SIZE
);
567 packetbuf_set_datalen(len
);
568 if(NETSTACK_FRAMER
.parse()) {
569 hdr
= packetbuf_dataptr();
570 if(hdr
->dispatch
== DISPATCH
&& hdr
->type
== TYPE_STROBE_ACK
) {
571 if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
572 &rimeaddr_node_addr
)) {
573 /* We got an ACK from the receiver, so we can immediately send
576 encounter_time
= now
;
578 PRINTDEBUG("cxmac: strobe ack for someone else\n");
580 } else /*if(hdr->dispatch == DISPATCH && hdr->type == TYPE_STROBE)*/ {
581 PRINTDEBUG("cxmac: strobe from someone else\n");
585 PRINTF("cxmac: send failed to parse %u\n", len
);
591 /* Send the strobe packet. */
592 if(got_strobe_ack
== 0 && collisions
== 0) {
594 #if WITH_STROBE_BROADCAST
595 NETSTACK_RADIO
.send(strobe
, strobe_len
);
597 /* restore the packet to send */
598 queuebuf_to_packetbuf(packet
);
599 NETSTACK_RADIO
.send(packetbuf_hdrptr(), packetbuf_totlen());
603 NETSTACK_RADIO
.send(strobe
, strobe_len
);
605 /* Turn off the radio for a while to let the other side
606 respond. We don't need to keep our radio on when we know
607 that the other side needs some time to produce a reply. */
609 rtimer_clock_t wt
= RTIMER_NOW();
610 while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt
+ WAIT_TIME_BEFORE_STROBE_ACK
));
618 #if WITH_ACK_OPTIMIZATION
619 /* If we have received the strobe ACK, and we are sending a packet
620 that will need an upper layer ACK (as signified by the
621 PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
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
)) {
626 on(); /* Wait for ACK packet */
627 waiting_for_packet
= 1;
631 #else /* WITH_ACK_OPTIMIZATION */
633 #endif /* WITH_ACK_OPTIMIZATION */
635 /* restore the packet to send */
636 queuebuf_to_packetbuf(packet
);
637 queuebuf_free(packet
);
639 /* Send the data packet. */
640 if((is_broadcast
|| got_strobe_ack
|| is_streaming
) && collisions
== 0) {
641 NETSTACK_RADIO
.send(packetbuf_hdrptr(), packetbuf_totlen());
644 #if WITH_ENCOUNTER_OPTIMIZATION
645 if(got_strobe_ack
&& !is_streaming
) {
646 register_encounter(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
), encounter_time
);
648 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
651 PRINTF("cxmac: send (strobes=%u,len=%u,%s), done\n", strobes
,
652 packetbuf_totlen(), got_strobe_ack
? "ack" : "no ack");
654 #if CXMAC_CONF_COMPOWER
655 /* Accumulate the power consumption for the packet transmission. */
656 compower_accumulate(¤t_packet
);
658 /* Convert the accumulated power consumption for the transmitted
659 packet to packet attributes so that the higher levels can keep
660 track of the amount of energy spent on transmitting the
662 compower_attrconv(¤t_packet
);
664 /* Clear the accumulated power consumption so that it is ready for
666 compower_clear(¤t_packet
);
667 #endif /* CXMAC_CONF_COMPOWER */
672 if(collisions
== 0) {
673 if(!is_broadcast
&& !got_strobe_ack
) {
679 someone_is_sending
++;
680 return MAC_TX_COLLISION
;
684 /*---------------------------------------------------------------------------*/
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
);
693 ret
= MAC_TX_COLLISION
;
695 PRINTF("cxmac: send immediately.\n");
699 mac_call_sent_callback(sent
, ptr
, ret
, 1);
701 /*---------------------------------------------------------------------------*/
705 struct cxmac_hdr
*hdr
;
707 if(NETSTACK_FRAMER
.parse()) {
708 hdr
= packetbuf_dataptr();
710 if(hdr
->dispatch
!= DISPATCH
) {
711 someone_is_sending
= 0;
712 if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
713 &rimeaddr_node_addr
) ||
714 rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
716 /* This is a regular packet that is destined to us or to the
717 broadcast address. */
719 /* We have received the final packet, so we can go back to being
723 #if CXMAC_CONF_COMPOWER
724 /* Accumulate the power consumption for the packet reception. */
725 compower_accumulate(¤t_packet
);
726 /* Convert the accumulated power consumption for the received
727 packet to packet attributes so that the higher levels can
728 keep track of the amount of energy spent on receiving the
730 compower_attrconv(¤t_packet
);
732 /* Clear the accumulated power consumption so that it is ready
733 for the next packet. */
734 compower_clear(¤t_packet
);
735 #endif /* CXMAC_CONF_COMPOWER */
737 waiting_for_packet
= 0;
739 PRINTDEBUG("cxmac: data(%u)\n", packetbuf_datalen());
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
),
750 &rimeaddr_node_addr
)) {
751 /* This is a strobe packet for us. */
753 /* If the sender address is someone else, we should
754 acknowledge the strobe and wait for the packet. By using
755 the same address as both sender and receiver, we flag the
756 message is a strobe ack. */
757 hdr
->type
= TYPE_STROBE_ACK
;
758 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
,
759 packetbuf_addr(PACKETBUF_ADDR_SENDER
));
760 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, &rimeaddr_node_addr
);
762 if(NETSTACK_FRAMER
.create()) {
763 /* We turn on the radio in anticipation of the incoming
765 someone_is_sending
= 1;
766 waiting_for_packet
= 1;
768 NETSTACK_RADIO
.send(packetbuf_hdrptr(), packetbuf_totlen());
769 PRINTDEBUG("cxmac: send strobe ack %u\n", packetbuf_totlen());
771 PRINTF("cxmac: failed to send strobe ack\n");
773 } else if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
),
775 /* If the receiver address is null, the strobe is sent to
776 prepare for an incoming broadcast packet. If this is the
777 case, we turn on the radio and wait for the incoming
779 waiting_for_packet
= 1;
782 PRINTDEBUG("cxmac: strobe not for us\n");
785 /* We are done processing the strobe and we therefore return
788 #if CXMAC_CONF_ANNOUNCEMENTS
789 } else if(hdr
->type
== TYPE_ANNOUNCEMENT
) {
790 packetbuf_hdrreduce(sizeof(struct cxmac_hdr
));
791 parse_announcements(packetbuf_addr(PACKETBUF_ADDR_SENDER
));
792 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
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
,
797 packetbuf_datalen());
800 PRINTF("cxmac: failed to parse (%u)\n", packetbuf_totlen());
803 /*---------------------------------------------------------------------------*/
804 #if CXMAC_CONF_ANNOUNCEMENTS
806 send_announcement(void *ptr
)
808 struct cxmac_hdr
*hdr
;
809 int announcement_len
;
811 /* Set up the probe header. */
813 hdr
= packetbuf_dataptr();
815 announcement_len
= format_announcement((char *)hdr
+
816 sizeof(struct cxmac_hdr
));
818 if(announcement_len
> 0) {
819 packetbuf_set_datalen(sizeof(struct cxmac_hdr
) + announcement_len
);
820 hdr
->dispatch
= DISPATCH
;
821 hdr
->type
= TYPE_ANNOUNCEMENT
;
823 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, &rimeaddr_node_addr
);
824 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
, &rimeaddr_null
);
825 packetbuf_set_attr(PACKETBUF_ATTR_RADIO_TXPOWER
, announcement_radio_txpower
);
826 if(NETSTACK_FRAMER
.create()) {
827 NETSTACK_RADIO
.send(packetbuf_hdrptr(), packetbuf_totlen());
831 /*---------------------------------------------------------------------------*/
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) {
841 /* printf("is_listening %d\n", is_listening);*/
844 /*---------------------------------------------------------------------------*/
846 listen_callback(int periods
)
848 is_listening
= periods
+ 1;
850 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
851 /*---------------------------------------------------------------------------*/
853 cxmac_set_announcement_radio_txpower(int txpower
)
855 #if CXMAC_CONF_ANNOUNCEMENTS
856 announcement_radio_txpower
= txpower
;
857 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
859 /*---------------------------------------------------------------------------*/
864 waiting_for_packet
= 0;
866 /* rtimer_set(&rt, RTIMER_NOW() + cxmac_config.off_time, 1,
867 (void (*)(struct rtimer *, void *))powercycle, NULL);*/
871 #if WITH_ENCOUNTER_OPTIMIZATION
872 list_init(encounter_list
);
873 memb_init(&encounter_memb
);
874 #endif /* WITH_ENCOUNTER_OPTIMIZATION */
876 #if CXMAC_CONF_ANNOUNCEMENTS
877 announcement_register_listen_callback(listen_callback
);
878 ctimer_set(&announcement_cycle_ctimer
, ANNOUNCEMENT_TIME
,
879 cycle_announcement
, NULL
);
880 #endif /* CXMAC_CONF_ANNOUNCEMENTS */
882 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME
);
884 /*---------------------------------------------------------------------------*/
889 /* rtimer_set(&rt, RTIMER_NOW() + cxmac_config.off_time, 1,
890 (void (*)(struct rtimer *, void *))powercycle, NULL);*/
891 CSCHEDULE_POWERCYCLE(DEFAULT_OFF_TIME
);
894 /*---------------------------------------------------------------------------*/
896 turn_off(int keep_radio_on
)
900 return NETSTACK_RADIO
.on();
902 return NETSTACK_RADIO
.off();
905 /*---------------------------------------------------------------------------*/
906 static unsigned short
907 channel_check_interval(void)
909 return (1ul * CLOCK_SECOND
* DEFAULT_PERIOD
) / RTIMER_ARCH_SECOND
;
911 /*---------------------------------------------------------------------------*/
912 const struct rdc_driver cxmac_driver
=
920 channel_check_interval
,