nes-proj/cpu/avr/radio/rf230/frame.c

345 lines
9.8 KiB
C

/*
*
* Copyright (c) 2008, Swedish Institute of Computer Science
* All rights reserved.
*
* Additional fixes for AVR contributed by:
*
* Colin O'Flynn coflynn@newae.com
* Eric Gnoske egnoske@gmail.com
* Blake Leverett bleverett@gmail.com
* Mike Vidales mavida404@gmail.com
* Kevin Brown kbrown3@uccs.edu
* Nate Bohlmann nate@elfwerks.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: frame.c,v 1.4 2008/12/10 21:26:05 c_oflynn Exp $
*/
/*
* \brief This file is where the main functions that relate to frame
* manipulation will reside.
*/
/**
* \addtogroup wireless
* @{
*/
/**
* \defgroup frame RF230 Frame handling
* @{
*/
/**
* \file
* \brief 802.15.4 frame creation and parsing functions
*
* This file converts to and from a structure to a packed 802.15.4
* frame.
*/
/* Includes */
#if defined( __GNUC__ )
#include <avr/io.h>
#include <util/delay.h>
#else /* IAR */
#include <iom1284.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "at86rf230_registermap.h"
#include "radio.h"
#include "frame.h"
//#include "mac_event.h"
#include "zmac.h"
#include "process.h"
#include "sicslowmac.h"
/* Macros & Defines */
/* Some version of radio chip need this set to 2, so define it in Makefile */
#ifndef AUTO_CRC_PADDING
#define AUTO_CRC_PADDING 0
#endif
/* Protoypes */
/* Globals */
/* Frame handling global variables. */
//FRAME_t rx_frame; /**< Structure that holds received frames. */
static uint8_t tx_frame_buffer[130];
/* Implementation */
/*----------------------------------------------------------------------------*/
/**
* \brief Creates a frame for transmission over the air. This function is
* meant to be called by a higher level function, that interfaces to a MAC.
*
* \param p Pointer to frame_create_params_t struct, which specifies the
* frame to send.
*
* \param frame_result Pointer to frame_result_t struct, which will
* receive the results of this function, a pointer to the frame
* created, and the length of the frame.
*
* \return Nothing directly, though the frame_result structure will be filled
* in with a pointer to the frame and the frame length.
*/
void
frame_tx_create(frame_create_params_t *p,frame_result_t *frame_result)
{
field_length_t flen;
uint8_t index=0;
/* init flen to zeros */
memset(&flen, 0, sizeof(field_length_t));
/* Determine lengths of each field based on fcf and other args */
if (p->fcf.destAddrMode){
flen.dest_pid_len = 2;
}
if (p->fcf.srcAddrMode){
flen.src_pid_len = 2;
}
/* Set PAN ID compression bit it src pan if matches dest pan id. */
if(p->fcf.destAddrMode == p->fcf.srcAddrMode){
p->fcf.panIdCompression = 1;
}
if (p->fcf.panIdCompression){
/* compressed header, only do dest pid */
flen.src_pid_len = 0;
}
/* determine address lengths */
switch (p->fcf.destAddrMode){
case 2: /* 16-bit address */
flen.dest_addr_len = 2;
break;
case 3: /* 64-bit address */
flen.dest_addr_len = 8;
break;
default:
break;
}
switch (p->fcf.srcAddrMode){
case 2: /* 16-bit address */
flen.src_addr_len = 2;
break;
case 3: /* 64-bit address */
flen.src_addr_len = 8;
break;
default:
break;
}
/* Aux security header */
if (p->fcf.securityEnabled){
switch (p->aux_hdr.security_control.key_id_mode){
case 0:
flen.aux_sec_len = 5; /* minimum value */
break;
case 1:
flen.aux_sec_len = 6;
break;
case 2:
flen.aux_sec_len = 10;
break;
case 3:
flen.aux_sec_len = 14;
break;
default:
break;
}
}
/* OK, now we have field lengths. Time to actually construct */
/* the outgoing frame, and store it in tx_frame_buffer */
*(uint16_t *)tx_frame_buffer = p->fcf.word_val; /* FCF */
index = 2;
tx_frame_buffer[index++] = p->seq; /* sequence number */
/* Destination PAN ID */
if (flen.dest_pid_len == 2){
*(uint16_t *)&tx_frame_buffer[index] = p->dest_pid;
index += 2;
}
/* Destination address */
switch (flen.dest_addr_len){
case 2: /* two-byte address */
*(uint16_t *)&tx_frame_buffer[index] = p->dest_addr.addr16;
index += 2;
break;
case 8: /* 8-byte address */
*(uint64_t *)&tx_frame_buffer[index] = p->dest_addr.addr64;
index += 8;
break;
case 0:
default:
break;
}
/* Source PAN ID */
if (flen.src_pid_len == 2){
*(uint16_t *)&tx_frame_buffer[index] = p->src_pid;
index += 2;
}
/* Source address */
switch (flen.src_addr_len){
case 2: /* two-byte address */
*(uint16_t *)&tx_frame_buffer[index] = p->src_addr.addr16;
index += 2;
break;
case 8: /* 8-byte address */
*(uint64_t *)&tx_frame_buffer[index] = p->src_addr.addr64;
index += 8;
break;
case 0:
default:
break;
}
/* Aux header */
if (flen.aux_sec_len){
memcpy((char *)&tx_frame_buffer[index],
(char *)&p->aux_hdr,
flen.aux_sec_len);
index += flen.aux_sec_len;
}
/* Frame payload */
memcpy((char *)&tx_frame_buffer[index],
(char *)p->payload,
p->payload_len);
index += p->payload_len;
/* return results */
frame_result->length = index + AUTO_CRC_PADDING;
frame_result->frame = tx_frame_buffer;
return;
}
/*----------------------------------------------------------------------------*/
/**
* \brief Parses an input frame. Scans the input frame to find each
* section, and stores the resulting addresses of each section in a
* parsed_frame_t structure.
*
* \param rx_frame The input data from the radio chip.
* \param pf The parsed_frame_t struct that stores a pointer to each
* section of the frame payload.
*/
void rx_frame_parse(hal_rx_frame_t *rx_frame, parsed_frame_t *pf)
{
/* Pointer to start of AT86RF2xx frame */
uint8_t *p = rx_frame->data;
fcf_t *fcf = (fcf_t *)&rx_frame->data;
static uint8_t frame_dropped = 0;
/* Uh-oh... please don't overwrite me! */
if (pf->in_use) {
/* Only post this once when buffer is busy, otherwise you get many postings... */
if (!frame_dropped) {
event_object_t event;
event.event = MAC_EVENT_DROPPED;
event.data = NULL;
mac_put_event(&event);
process_post(&mac_process, event.event, event.data);
}
frame_dropped = 1;
return;
}
pf->fcf = (fcf_t *)p;
pf->seqNum = p+2;
p += 3; /* Skip first three bytes */
if (fcf->frameType == ACKFRAME) {
//ACK frames have no addresses and no payload!
pf->payload_length = 0;
} else {
/* Destination PID, if any */
if (fcf->frameType != BEACONFRAME){ /* No destination addresses in Beacon frame */
pf->dest_pid = (uint16_t *)p;
p += 2;
/* Destination address */
pf->dest_addr = 0;
if (fcf->destAddrMode == SHORTADDRMODE ||
fcf->destAddrMode == LONGADDRMODE){
pf->dest_addr = (addr_t *)p;
/* Update pointer to account for possible missing addr field */
if (fcf->destAddrMode == SHORTADDRMODE){
p += 2;
}
if (fcf->destAddrMode == LONGADDRMODE){
p += 8;
}
}
}
/* Source PANID */
pf->src_pid = 0;
if (!fcf->panIdCompression){
pf->src_pid = (uint16_t *)p;
p += 2;
} else {
pf->src_pid = pf->dest_pid;
}
/* Source address */
pf->src_addr = (addr_t *)p;
if (fcf->srcAddrMode == SHORTADDRMODE){
p += 2;
}
if (fcf->srcAddrMode == LONGADDRMODE){
p += 8;
}
/* aux security header, not yet implemented */
pf->aux_sec_hdr = 0;
/* payload length */
pf->payload_length = rx_frame->length - (p - (uint8_t*)&rx_frame->data) - 2;
/* payload */
pf->payload = p;
}
pf->lqi = rx_frame->lqi;
pf->fcs = rx_frame->crc;
/* pass frame to sicslowmac layer */
event_object_t event;
event.event = MAC_EVENT_RX;
event.data = (uint8_t*)pf;
pf->in_use = 1;
mac_put_event(&event);
process_poll(&mac_process);
}
/** \} */
/** \} */