Add useful comment, fix compiler warnings
[contiki-2.x.git] / cpu / avr / radio / mac / sicslowmac.c
blob398183faceb9ae968cff916361b99eef4a3b6d9b
1 /*
2 * Copyright (c) 2008, Swedish Institute of Computer Science.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
27 * SUCH DAMAGE.
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 $
35 /**
36 * \file
37 * Example glue code between the existing MAC code and the
38 * Contiki mac interface
40 * \author
41 * Adam Dunkels <adam@sics.se>
42 * Eric Gnoske <egnoske@gmail.com>
43 * Blake Leverett <bleverett@gmail.com>
45 * \addtogroup rf230mac
48 #include <stdlib.h>
49 #include <stdbool.h>
50 #include <string.h>
51 #include <stdio.h>
52 #include <avr/eeprom.h>
53 #include <util/delay.h>
54 #include "net/rime/packetbuf.h"
55 #include "zmac.h"
56 #include "mac.h"
57 #include "frame.h"
58 #include "radio.h"
59 #include "tcpip.h"
60 #include "sicslowmac.h"
61 #include "sicslowpan.h"
62 #include "ieee-15-4-manager.h"
64 /* Macros */
65 #define DEBUG 0
66 #define MAX_EVENTS 10
68 #if DEBUG
69 #define PRINTF(...) printf(__VA_ARGS__)
70 #define SICSLOW_CORRECTION_DELAY 70
71 #else
72 #define PRINTF(...)
73 #define SICSLOW_CORRECTION_DELAY 7
74 #endif
76 #ifdef JACKDAW
77 #include "sicslow_ethernet.h"
78 #define LOG_FRAME(x,y) mac_logTXtoEthernet(x,y)
79 #else
80 #define LOG_FRAME(x,y)
81 #endif
83 /* Globals */
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.
95 /* read_packet, */
96 /* set_receive_function, */
97 /* on, */
98 /* off, */
101 static struct {
102 uint8_t head;
103 uint8_t tail;
104 event_object_t event_object[MAX_EVENTS];
105 } event_queue;
107 /* Prototypes */
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.
122 uint8_t
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.
133 void
134 mac_put_event(event_object_t *object)
136 uint8_t newhead;
138 if ((event_queue.head + 1) % MAX_EVENTS == event_queue.tail){
139 /* queue full, get outta here */
140 return;
143 newhead = event_queue.head;
145 /* store in queue */
146 event_queue.event_object[newhead] = *object;
148 /* calculate new head index */
149 newhead++;
150 if (newhead >= MAX_EVENTS){
151 newhead = 0;
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.
162 event_object_t
163 *mac_get_event(void)
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 */
173 newtail++;
174 if (newtail >= MAX_EVENTS){
175 newtail = 0;
178 event_queue.tail = newtail;
180 return(object);
183 void mac_pollhandler(void)
185 mac_task(0, NULL);
188 /*---------------------------------------------------------------------------*/
190 * \brief This is the main loop task for the MAC. Called by the
191 * main application loop.
193 void
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 */
204 if (event){
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();
211 } else {
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 /*---------------------------------------------------------------------------*/
230 void
231 setinput(void (*r)(const struct mac_driver *d))
233 pinput = r;
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])
242 void
243 sicslowmac_dataIndication(void)
245 packetbuf_clear();
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);
277 src_reversed[2] = 0;
278 src_reversed[3] = 0;
279 src_reversed[4] = MSB(parsed_frame->payload[2]); //originAddr
280 src_reversed[5] = LSB(parsed_frame->payload[3]);
282 #else
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);
296 src_reversed[2] = 0;
297 src_reversed[3] = 0;
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);
304 #endif
306 PRINTF("sicslowmac: hand off frame to sicslowpan \n");
307 pinput(pmac_driver);
310 void
311 sicslowmac_unknownIndication(void)
313 if (sicslowmac_snifferhook) {
315 packetbuf_clear();
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);
343 src_reversed[2] = 0;
344 src_reversed[3] = 0;
345 src_reversed[4] = MSB(parsed_frame->payload[2]); //originAddr
346 src_reversed[5] = LSB(parsed_frame->payload[3]);
348 #else
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);
359 src_reversed[2] = 0;
360 src_reversed[3] = 0;
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);
367 #endif
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
379 * primitive.
381 * \return Integer denoting success or failure.
382 * \retval 0 Failure.
383 * \retval 1 Success.
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
393 * radio_send_data.
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);
409 /* Build the FCF. */
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;
440 } else {
442 /* Phase 1.5 - end nodes send to anyone? */
443 memcpy(&params.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*)&params.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
458 * phase 1.
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(&params, &result);
469 /* Log if needed */
470 LOG_FRAME(&params, &result);
472 /* Retry up to this many times to send the packet if radio is busy */
473 uint8_t retry_count = 3;
475 while(retry_count) {
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) {
492 PRINTF(" Failed\n");
493 return 0;
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) {
503 _delay_ms(10);
504 } else if (retry_count == 2) {
505 _delay_ms(50);
506 } else if (retry_count == 1) {
507 _delay_ms(200);
510 retry_count--;
513 PRINTF("sicslowmac: Unable to send packet, dropped\n");
514 return 0;
517 /*---------------------------------------------------------------------------*/
519 * \brief Stub function that will be implemented in phase 2 to cause
520 * end nodes to sleep.
523 mac_wake(void)
525 return 1;
527 /*---------------------------------------------------------------------------*/
529 * \brief Stub function that will be implemented in phase 2 to cause
530 * end nodes to sleep.
533 mac_sleep(void)
535 return 1;
537 /*---------------------------------------------------------------------------*/
538 const struct mac_driver *
539 sicslowmac_init(const struct radio_driver *d)
541 /* AD: commented out the radio_driver code for now.*/
542 /* radio = d;
543 radio->set_receive_function(input_packet);
544 radio->on();*/
546 return &sicslowmac_driver;
548 /*---------------------------------------------------------------------------*/
550 * \brief This is the implementation of the 15.4 MAC Reset Request
551 * primitive.
552 * \param setDefaultPIB True if the default PIB values should be set.
553 * \return Integer denoting success or failure.
554 * \retval 0 Failure.
555 * \retval 1 Success.
557 * Sets all PIB values to default.
559 void
560 sicslowmac_resetRequest (bool setDefaultPIB)
562 if(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)
583 return parsed_frame;
586 /*---------------------------------------------------------------------------*/
587 struct mac_driver * sicslowmac_get_driver(void)
589 return pmac_driver;
591 /*---------------------------------------------------------------------------*/
592 PROCESS(mac_process, "802.15.4 MAC process");
593 PROCESS_THREAD(mac_process, ev, data)
596 PROCESS_POLLHANDLER(mac_pollhandler());
599 PROCESS_BEGIN();
601 radio_status_t return_value;
603 /* init radio */
604 /** \todo: this screws up if calosc is set to TRUE, find out why? */
605 return_value = radio_init(false, NULL, NULL, NULL);
607 #if DEBUG
608 if (return_value == RADIO_SUCCESS) {
609 printf("Radio init successful.\n");
610 } else {
611 printf("Radio init failed with return: %d\n", return_value);
613 #endif
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)) {
622 #if UIP_CONF_USE_RUM
623 eeprom_channel = 19; //Default
624 #else
625 eeprom_channel = 24; //Default
626 #endif
629 radio_set_operating_channel(eeprom_channel);
630 radio_use_auto_tx_crc(true);
631 radio_set_trx_state(TRX_OFF);
633 mac_init();
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);
644 while(1) {
645 PROCESS_YIELD();
646 mac_task(ev, data);
650 PROCESS_END();
653 void byte_reverse(uint8_t * bytes, uint8_t num)
655 uint8_t tempbyte;
657 uint8_t i, j;
659 i = 0;
660 j = num - 1;
662 while(i < j) {
663 tempbyte = bytes[i];
664 bytes[i] = bytes[j];
665 bytes[j] = tempbyte;
667 j--;
668 i++;
671 return;