2 * Copyright (c) 2008, 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: sicslowmac.c,v 1.8 2009/07/17 13:47:10 dak664 Exp $
37 * Example glue code between the existing MAC code and the
38 * Contiki mac interface
41 * Adam Dunkels <adam@sics.se>
42 * Eric Gnoske <egnoske@gmail.com>
43 * Blake Leverett <bleverett@gmail.com>
45 * \addtogroup rf230mac
52 #include <avr/eeprom.h>
53 #include <util/delay.h>
54 #include "net/rime/packetbuf.h"
60 #include "sicslowmac.h"
61 #include "sicslowpan.h"
62 #include "ieee-15-4-manager.h"
69 #define PRINTF(...) printf(__VA_ARGS__)
70 #define SICSLOW_CORRECTION_DELAY 70
73 #define SICSLOW_CORRECTION_DELAY 7
77 #include "sicslow_ethernet.h"
78 #define LOG_FRAME(x,y) mac_logTXtoEthernet(x,y)
80 #define LOG_FRAME(x,y)
84 static struct mac_driver mac_driver_struct
;
85 static struct mac_driver
*pmac_driver
= &mac_driver_struct
;
86 extern ieee_15_4_manager_t ieee15_4ManagerAddress
;
87 static parsed_frame_t
*parsed_frame
;
89 /* The core mac layer has a pointer to the driver name in the first field.
90 * It calls the radio driver with radio->send, which is the first field of the radio driver.
91 * This glue directs radio->send to the custom mac layer.
93 const struct mac_driver sicslowmac_driver
= {
94 (char *)sicslowmac_dataRequest
, //Remove compiler warning.
96 /* set_receive_function, */
104 event_object_t event_object
[MAX_EVENTS
];
108 static void setinput(void (*r
)(const struct mac_driver
*d
));
109 void (*pinput
)(const struct mac_driver
*r
);
110 void sicslowmac_unknownIndication(void);
113 void (*sicslowmac_snifferhook
)(const struct mac_driver
*r
) = NULL
;
116 /*---------------------------------------------------------------------------*/
118 * \brief Checks for any pending events in the queue.
120 * \return True if there is a pending event, else false.
123 mac_event_pending(void)
125 return (event_queue
.head
!= event_queue
.tail
);
127 /*---------------------------------------------------------------------------*/
129 * \brief Puts an event into the queue of events.
131 * \param object is a pointer to the event to add to queue.
134 mac_put_event(event_object_t
*object
)
138 if ((event_queue
.head
+ 1) % MAX_EVENTS
== event_queue
.tail
){
139 /* queue full, get outta here */
143 newhead
= event_queue
.head
;
146 event_queue
.event_object
[newhead
] = *object
;
148 /* calculate new head index */
150 if (newhead
>= MAX_EVENTS
){
153 event_queue
.head
= newhead
;
155 /*---------------------------------------------------------------------------*/
157 * \brief Pulls an event from the event queue.
158 * Assumes that there is an event in the queue. See mac_event_pending().
160 * \return Pointer to the event object, or NULL in the event of empty queue.
165 event_object_t
*object
= NULL
;
166 volatile uint8_t newtail
;
168 newtail
= event_queue
.tail
;
170 object
= &(event_queue
.event_object
[newtail
]);
172 /* calculate new tail */
174 if (newtail
>= MAX_EVENTS
){
178 event_queue
.tail
= newtail
;
183 void mac_pollhandler(void)
188 /*---------------------------------------------------------------------------*/
190 * \brief This is the main loop task for the MAC. Called by the
191 * main application loop.
194 mac_task(process_event_t ev
, process_data_t data
)
196 /* check for event in queue */
197 event_object_t
*event
;
199 if(mac_event_pending()){
201 event
= mac_get_event();
203 /* Handle events from radio */
206 if (event
->event
== MAC_EVENT_RX
){
207 /* got a frame, find out with kind of frame */
208 parsed_frame
= (parsed_frame_t
*)event
->data
;
209 if (parsed_frame
->fcf
->frameType
== DATAFRAME
){
210 sicslowmac_dataIndication();
213 /* Hook to cath unknown frames */
214 sicslowmac_unknownIndication();
218 /* Frame no longer in use */
219 parsed_frame
->in_use
= false;
222 if (event
->event
== MAC_EVENT_DROPPED
){
223 /* Frame was dropped */
224 PRINTF("sicslowmac: Frame Dropped!\n");
229 /*---------------------------------------------------------------------------*/
231 setinput(void (*r
)(const struct mac_driver
*d
))
235 /*---------------------------------------------------------------------------*/
236 static uint8_t dest_reversed
[UIP_LLADDR_LEN
];
237 static uint8_t src_reversed
[UIP_LLADDR_LEN
];
239 # define MSB(u16) (((uint8_t* )&u16)[1])
240 # define LSB(u16) (((uint8_t* )&u16)[0])
243 sicslowmac_dataIndication(void)
248 #if UIP_LLADDR_LEN == 8
249 /* Finally, get the stuff into the rime buffer.... */
250 packetbuf_copyfrom(parsed_frame
->payload
, parsed_frame
->payload_length
);
251 packetbuf_set_datalen(parsed_frame
->payload_length
);
253 memcpy(dest_reversed
, (uint8_t *)parsed_frame
->dest_addr
, UIP_LLADDR_LEN
);
254 memcpy(src_reversed
, (uint8_t *)parsed_frame
->src_addr
, UIP_LLADDR_LEN
);
256 /* Change addresses to expected byte order */
257 byte_reverse((uint8_t *)dest_reversed
, UIP_LLADDR_LEN
);
258 byte_reverse((uint8_t *)src_reversed
, UIP_LLADDR_LEN
);
260 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
, (const rimeaddr_t
*)dest_reversed
);
261 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, (const rimeaddr_t
*)src_reversed
);
263 #elif UIP_CONF_USE_RUM
264 /* Finally, get the stuff into the rime buffer.... */
265 packetbuf_copyfrom(parsed_frame
->payload
+ UIP_DATA_RUM_OFFSET
, parsed_frame
->payload_length
- UIP_DATA_RUM_OFFSET
);
266 packetbuf_set_datalen(parsed_frame
->payload_length
+ UIP_DATA_RUM_OFFSET
);
268 dest_reversed
[0] = MSB(parsed_frame
->dest_pid
);
269 dest_reversed
[1] = LSB(parsed_frame
->dest_pid
);
270 dest_reversed
[2] = 0;
271 dest_reversed
[3] = 0;
272 dest_reversed
[4] = MSB(parsed_frame
->payload
[0]); //FinalDestAddr
273 dest_reversed
[5] = LSB(parsed_frame
->payload
[1]);
275 src_reversed
[0] = MSB(parsed_frame
->src_pid
);
276 src_reversed
[1] = LSB(parsed_frame
->src_pid
);
279 src_reversed
[4] = MSB(parsed_frame
->payload
[2]); //originAddr
280 src_reversed
[5] = LSB(parsed_frame
->payload
[3]);
283 /* Finally, get the stuff into the rime buffer.... */
284 packetbuf_copyfrom(parsed_frame
->payload
, parsed_frame
->payload_length
);
285 packetbuf_set_datalen(parsed_frame
->payload_length
);
287 dest_reversed
[0] = MSB(parsed_frame
->dest_pid
);
288 dest_reversed
[1] = LSB(parsed_frame
->dest_pid
);
289 dest_reversed
[2] = 0;
290 dest_reversed
[3] = 0;
291 dest_reversed
[4] = MSB(parsed_frame
->dest_addr
->addr16
);
292 dest_reversed
[5] = LSB(parsed_frame
->dest_addr
->addr16
);
294 src_reversed
[0] = MSB(parsed_frame
->src_pid
);
295 src_reversed
[1] = LSB(parsed_frame
->src_pid
);
298 src_reversed
[4] = MSB(parsed_frame
->src_addr
->addr16
);
299 src_reversed
[5] = LSB(parsed_frame
->src_addr
->addr16
);
301 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
, (const rimeaddr_t
*)dest_reversed
);
302 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, (const rimeaddr_t
*)src_reversed
);
306 PRINTF("sicslowmac: hand off frame to sicslowpan \n");
311 sicslowmac_unknownIndication(void)
313 if (sicslowmac_snifferhook
) {
317 /* Finally, get the stuff into the rime buffer.... */
318 packetbuf_copyfrom(parsed_frame
->payload
, parsed_frame
->payload_length
);
319 packetbuf_set_datalen(parsed_frame
->payload_length
);
321 #if UIP_LLADDR_LEN == 8
322 memcpy(dest_reversed
, (uint8_t *)parsed_frame
->dest_addr
, UIP_LLADDR_LEN
);
323 memcpy(src_reversed
, (uint8_t *)parsed_frame
->src_addr
, UIP_LLADDR_LEN
);
325 /* Change addresses to expected byte order */
326 byte_reverse((uint8_t *)dest_reversed
, UIP_LLADDR_LEN
);
327 byte_reverse((uint8_t *)src_reversed
, UIP_LLADDR_LEN
);
329 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
, (const rimeaddr_t
*)dest_reversed
);
330 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, (const rimeaddr_t
*)src_reversed
);
332 #elif UIP_CONF_USE_RUM
334 dest_reversed
[0] = MSB(parsed_frame
->dest_pid
);
335 dest_reversed
[1] = LSB(parsed_frame
->dest_pid
);
336 dest_reversed
[2] = 0;
337 dest_reversed
[3] = 0;
338 dest_reversed
[4] = MSB(parsed_frame
->payload
[0]); //FinalDestAddr
339 dest_reversed
[5] = LSB(parsed_frame
->payload
[1]);
341 src_reversed
[0] = MSB(parsed_frame
->src_pid
);
342 src_reversed
[1] = LSB(parsed_frame
->src_pid
);
345 src_reversed
[4] = MSB(parsed_frame
->payload
[2]); //originAddr
346 src_reversed
[5] = LSB(parsed_frame
->payload
[3]);
350 dest_reversed
[0] = MSB(parsed_frame
->dest_pid
);
351 dest_reversed
[1] = LSB(parsed_frame
->dest_pid
);
352 dest_reversed
[2] = 0;
353 dest_reversed
[3] = 0;
354 dest_reversed
[4] = MSB(parsed_frame
->dest_addr
->addr16
);
355 dest_reversed
[5] = LSB(parsed_frame
->dest_addr
->addr16
);
357 src_reversed
[0] = MSB(parsed_frame
->src_pid
);
358 src_reversed
[1] = LSB(parsed_frame
->src_pid
);
361 src_reversed
[4] = MSB(parsed_frame
->src_addr
->addr16
);
362 src_reversed
[5] = LSB(parsed_frame
->src_addr
->addr16
);
364 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER
, (const rimeaddr_t
*)dest_reversed
);
365 packetbuf_set_addr(PACKETBUF_ADDR_SENDER
, (const rimeaddr_t
*)src_reversed
);
369 PRINTF("sicslowmac: hand off frame to sniffer \n");
371 sicslowmac_snifferhook(pmac_driver
);
376 /*---------------------------------------------------------------------------*/
378 * \brief This is the implementation of the 15.4 MAC Data Request
381 * \return Integer denoting success or failure.
385 * The data request primitive creates the frame header based
386 * on static and dynamic data. The static data will be refined
387 * in phase II of the project. The frame payload and length are
388 * retrieved from the rime buffer and rime length respectively.
390 * When the header and payload are assembled into the
391 * frame_create_params structure, the frame is created
392 * by a call to frame_tx_create and then transmited via
395 /*---------------------------------------------------------------------------*/
397 sicslowmac_dataRequest(void)
400 _delay_ms(SICSLOW_CORRECTION_DELAY
);
402 /* create structure to store result. */
403 frame_create_params_t params
;
404 frame_result_t result
;
406 /* Save the msduHandle in a global variable. */
407 msduHandle
= packetbuf_attr(PACKETBUF_ATTR_PACKET_ID
);
410 params
.fcf
.frameType
= DATAFRAME
;
411 params
.fcf
.securityEnabled
= false;
412 params
.fcf
.framePending
= false;
413 params
.fcf
.ackRequired
= packetbuf_attr(PACKETBUF_ATTR_RELIABLE
);
414 params
.fcf
.panIdCompression
= false;
416 /* Insert IEEE 802.15.4 (2003) version bit. */
417 params
.fcf
.frameVersion
= IEEE802154_2003
;
419 /* Increment and set the data sequence number. */
420 params
.seq
= macDSN
++;
422 /* Complete the addressing fields. */
424 \todo For phase 1 the addresses are all long. We'll need a mechanism
425 in the rime attributes to tell the mac to use long or short for phase 2.
427 params
.fcf
.srcAddrMode
= LONGADDRMODE
;
428 params
.dest_pid
= ieee15_4ManagerAddress
.get_dst_panid();
431 * If the output address is NULL in the Rime buf, then it is broadcast
432 * on the 802.15.4 network.
434 if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER
), &rimeaddr_null
) ) {
435 /* Broadcast requires short address mode. */
436 params
.fcf
.destAddrMode
= SHORTADDRMODE
;
437 params
.dest_pid
= BROADCASTPANDID
;
438 params
.dest_addr
.addr16
= BROADCASTADDR
;
442 /* Phase 1.5 - end nodes send to anyone? */
443 memcpy(¶ms
.dest_addr
, (uint8_t *)packetbuf_addr(PACKETBUF_ADDR_RECEIVER
), LONG_ADDR_LEN
);
445 /* Change from sicslowpan byte arrangement to sicslowmac */
446 byte_reverse((uint8_t*)¶ms
.dest_addr
.addr64
, LONG_ADDR_LEN
);
448 /* Phase 1 - end nodes only sends to pan coordinator node. */
449 /* params.dest_addr.addr64 = ieee15_4ManagerAddress.get_coord_long_addr(); */
450 params
.fcf
.destAddrMode
= LONGADDRMODE
;
453 /* Set the source PAN ID to the global variable. */
454 params
.src_pid
= ieee15_4ManagerAddress
.get_src_panid();
457 * Set up the source address using only the long address mode for
460 params
.src_addr
.addr64
= ieee15_4ManagerAddress
.get_long_addr();
462 /* Copy the payload data. */
463 params
.payload_len
= packetbuf_datalen();
464 params
.payload
= packetbuf_dataptr();
466 /* Create transmission frame. */
467 frame_tx_create(¶ms
, &result
);
470 LOG_FRAME(¶ms
, &result
);
472 /* Retry up to this many times to send the packet if radio is busy */
473 uint8_t retry_count
= 3;
477 PRINTF("sicslowmac: sending packet of length %d to radio, result:", result
.length
);
481 /* Send data to radio. */
482 radio_status_t rv
= radio_send_data(result
.length
, result
.frame
);
484 if (rv
== RADIO_SUCCESS
) {
485 PRINTF(" Success\n");
487 return 1; /* True says that the packet could be sent */
491 if (rv
!= RADIO_WRONG_STATE
) {
496 PRINTF(" Radio busy, retrying\n");
498 /** \todo: Fix delay in sicslowmac so they do not block receiving */
500 //We have blocking delay here, it is safest this way. BUT doesn't solve the
501 //problem of TX when you are RXing.. as the RX code can't execute!
502 if (retry_count
== 3) {
504 } else if (retry_count
== 2) {
506 } else if (retry_count
== 1) {
513 PRINTF("sicslowmac: Unable to send packet, dropped\n");
517 /*---------------------------------------------------------------------------*/
519 * \brief Stub function that will be implemented in phase 2 to cause
520 * end nodes to sleep.
527 /*---------------------------------------------------------------------------*/
529 * \brief Stub function that will be implemented in phase 2 to cause
530 * end nodes to sleep.
537 /*---------------------------------------------------------------------------*/
538 const struct mac_driver
*
539 sicslowmac_init(const struct radio_driver
*d
)
541 /* AD: commented out the radio_driver code for now.*/
543 radio->set_receive_function(input_packet);
546 return &sicslowmac_driver
;
548 /*---------------------------------------------------------------------------*/
550 * \brief This is the implementation of the 15.4 MAC Reset Request
552 * \param setDefaultPIB True if the default PIB values should be set.
553 * \return Integer denoting success or failure.
557 * Sets all PIB values to default.
560 sicslowmac_resetRequest (bool setDefaultPIB
)
563 /* initialize all of the MAC PIB variables to their default values */
564 macCoordShortAddress
= 0xffff;
565 macDSN
= rand() % 256;
566 macSrcPANId
= SOURCE_PAN_ID
;
567 macDstPANId
= DEST_PAN_ID
;
568 macShortAddress
= 0xffff;
569 /* Setup the address of this device by reading a stored address from eeprom. */
570 /** \todo This might be read from the serial eeprom onboard Raven. */
571 AVR_ENTER_CRITICAL_REGION();
572 eeprom_read_block ((void *)&macLongAddr
, EEPROMMACADDRESS
, 8);
574 byte_reverse((uint8_t *) &macLongAddr
, 8);
577 AVR_LEAVE_CRITICAL_REGION();
581 parsed_frame_t
* sicslowmac_get_frame(void)
586 /*---------------------------------------------------------------------------*/
587 struct mac_driver
* sicslowmac_get_driver(void)
591 /*---------------------------------------------------------------------------*/
592 PROCESS(mac_process
, "802.15.4 MAC process");
593 PROCESS_THREAD(mac_process
, ev
, data
)
596 PROCESS_POLLHANDLER(mac_pollhandler());
601 radio_status_t return_value
;
604 /** \todo: this screws up if calosc is set to TRUE, find out why? */
605 return_value
= radio_init(false, NULL
, NULL
, NULL
);
608 if (return_value
== RADIO_SUCCESS
) {
609 printf("Radio init successful.\n");
611 printf("Radio init failed with return: %d\n", return_value
);
615 uint8_t eeprom_channel
;
616 uint8_t eeprom_check
;
618 eeprom_channel
= eeprom_read_byte((uint8_t *)9);
619 eeprom_check
= eeprom_read_byte((uint8_t *)10);
621 if ((eeprom_channel
< 11) || (eeprom_channel
> 26) || ((uint8_t)eeprom_channel
!= (uint8_t)~eeprom_check
)) {
623 eeprom_channel
= 19; //Default
625 eeprom_channel
= 24; //Default
629 radio_set_operating_channel(eeprom_channel
);
630 radio_use_auto_tx_crc(true);
631 radio_set_trx_state(TRX_OFF
);
635 /* Set up MAC function pointers and sicslowpan callback. */
636 pmac_driver
->set_receive_function
= setinput
;
637 pmac_driver
->send
= sicslowmac_dataRequest
;
638 sicslowpan_init(pmac_driver
);
640 ieee_15_4_init(&ieee15_4ManagerAddress
);
642 radio_set_trx_state(RX_AACK_ON
);
653 void byte_reverse(uint8_t * bytes
, uint8_t num
)