diff --git a/cpu/avr/radio/ieee-manager/Makefile.ieee-manager b/cpu/avr/radio/ieee-manager/Makefile.ieee-manager new file mode 100644 index 000000000..44fae196e --- /dev/null +++ b/cpu/avr/radio/ieee-manager/Makefile.ieee-manager @@ -0,0 +1,5 @@ + +CONTIKI_TARGET_SOURCEFILES += ieee-15-4-manager.c + +APPDIRS += $(CONTIKI)/cpu/avr/radio/ieee-manager + diff --git a/cpu/avr/radio/ieee-manager/ieee-15-4-manager.c b/cpu/avr/radio/ieee-manager/ieee-15-4-manager.c new file mode 100644 index 000000000..79dd6257d --- /dev/null +++ b/cpu/avr/radio/ieee-manager/ieee-15-4-manager.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + * $Id: ieee-15-4-manager.c,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ + +/** + * + * \addtogroup rf230mac + * \{ + */ + +/** + * \file + * \brief Interfaces the 802.15.4 MAC to upper network layers. + * + * \author + * Mike Vidales + */ + +#include "mac.h" +#include "radio.h" +#include "ieee-15-4-manager.h" + +/*---------------------------------------------------------------------------*/ +static int +wake(void) +{ + /* Wake the radio. */ + return radio_leave_sleep_mode(); +} +/*---------------------------------------------------------------------------*/ +static int +sleep(void) +{ + /* Sleep the radio. */ + return radio_enter_sleep_mode(); +} +/*---------------------------------------------------------------------------*/ +static void +set_channel(int channel) +{ + /* Set the channel. */ + phyCurrentChannel = channel; + radio_set_operating_channel(phyCurrentChannel); +} +/*---------------------------------------------------------------------------*/ +static int +get_channel(void) +{ + /* Reads the current channel. */ + phyCurrentChannel = radio_get_operating_channel(); + return phyCurrentChannel; +} +/*---------------------------------------------------------------------------*/ +static void +set_dst_panid(int panid) +{ + macDstPANId = panid; +} +/*---------------------------------------------------------------------------*/ +static int +get_dst_panid(void) +{ + return macDstPANId; +} +/*---------------------------------------------------------------------------*/ +static void +set_src_panid(int panid) +{ + /* Writes the PAN_ID to the radio. */ + macSrcPANId = panid; + radio_set_pan_id(macSrcPANId); +} +/*---------------------------------------------------------------------------*/ +static int +get_src_panid(void) +{ + /* Gets the PAN_ID from the radio. */ + macSrcPANId = radio_get_pan_id(); + return macSrcPANId; +} +/*---------------------------------------------------------------------------*/ +static void +set_auto_mode(bool mode) +{ + autoModes = mode; +} +/*---------------------------------------------------------------------------*/ +static bool +get_auto_mode(void) +{ + return autoModes; +} +/*---------------------------------------------------------------------------*/ +static void +set_long_addr(uint64_t address) +{ + /* Set the Long address in the radio. */ + macLongAddr = address; + radio_set_extended_address((uint8_t *)&macLongAddr); +} +/*---------------------------------------------------------------------------*/ +static uint64_t +get_long_addr(void) +{ + /* Get the Long address from the radio. */ + radio_get_extended_address((uint8_t *)&macLongAddr); + return macLongAddr; +} +/*---------------------------------------------------------------------------*/ +static void +set_short_addr(int address) +{ + /* Set the Short address in the radio. */ + macShortAddress = address; + radio_set_short_address(macShortAddress); +} +/*---------------------------------------------------------------------------*/ +static int +get_short_addr(void) +{ + /* Get the Short address from the radio. */ + macShortAddress = radio_get_short_address(); + return macShortAddress; +} +/*---------------------------------------------------------------------------*/ +static void +set_iamcoord_bit(bool iamcoord) +{ + /** Set the iAmCoord bit. */ + iAmCoord = iamcoord; + radio_set_device_role(iAmCoord); +} +/*---------------------------------------------------------------------------*/ +static bool +get_iamcoord_bit(void) +{ + /** Get the iAmCoord bit. */ + iAmCoord = radio_get_device_role(); + return iAmCoord; +} +/*---------------------------------------------------------------------------*/ +static void +set_coord_long_addr(uint64_t address) +{ + macCoordExtendedAddress = address; +} +/*---------------------------------------------------------------------------*/ +static uint64_t +get_coord_long_addr(void) +{ + return macCoordExtendedAddress; +} +/*---------------------------------------------------------------------------*/ +static void +set_coord_short_addr(int address) +{ + macCoordShortAddress = address; +} +/*---------------------------------------------------------------------------*/ +static int +get_coord_short_addr(void) +{ + return macCoordShortAddress; +} +/*---------------------------------------------------------------------------*/ +static void +set_dest_long_addr(uint64_t address) +{ + macDestAddress = address; +} +/*---------------------------------------------------------------------------*/ +static uint64_t +get_dest_long_addr(void) +{ + return macDestAddress; +} +/*---------------------------------------------------------------------------*/ +/** \brief initializes the 802.15.4 manager layer. + * \param pieee_15_4_manager Pointer to \ref ieee_15_4_manager + */ +void ieee_15_4_init(ieee_15_4_manager_t *pieee_15_4_manager) +{ +/* Initialize the IEEE 15.4 manager. */ + pieee_15_4_manager->wake = wake; + pieee_15_4_manager->sleep = sleep; + pieee_15_4_manager->set_channel = set_channel; + pieee_15_4_manager->get_channel = get_channel; + pieee_15_4_manager->set_dst_panid = set_dst_panid; + pieee_15_4_manager->get_dst_panid = get_dst_panid; + pieee_15_4_manager->set_src_panid = set_src_panid; + pieee_15_4_manager->get_src_panid = get_src_panid; + pieee_15_4_manager->set_auto_mode = set_auto_mode; + pieee_15_4_manager->get_auto_mode = get_auto_mode; + pieee_15_4_manager->set_long_addr = set_long_addr; + pieee_15_4_manager->get_long_addr = get_long_addr; + pieee_15_4_manager->set_short_addr = set_short_addr; + pieee_15_4_manager->get_short_addr = get_short_addr; + pieee_15_4_manager->set_iamcoord_bit = set_iamcoord_bit; + pieee_15_4_manager->get_iamcoord_bit = get_iamcoord_bit; + pieee_15_4_manager->set_coord_long_addr = set_coord_long_addr; + pieee_15_4_manager->get_coord_long_addr = get_coord_long_addr; + pieee_15_4_manager->set_coord_short_addr = set_coord_short_addr; + pieee_15_4_manager->get_coord_short_addr = get_coord_short_addr; + pieee_15_4_manager->set_dest_long_addr = set_dest_long_addr; + pieee_15_4_manager->get_dest_long_addr = get_dest_long_addr; +} + +/** \} */ diff --git a/cpu/avr/radio/ieee-manager/ieee-15-4-manager.h b/cpu/avr/radio/ieee-manager/ieee-15-4-manager.h new file mode 100644 index 000000000..2669492fb --- /dev/null +++ b/cpu/avr/radio/ieee-manager/ieee-15-4-manager.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + * $Id: ieee-15-4-manager.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ +/** + * \addtogroup rf230mac + * \{ + */ + +/** + * \file + * \brief Example glue code between the existing MAC code and the + * Contiki mac interface + * + * \author + * Mike Vidales + * + * \ingroup ieee_15_4 + * + */ + +#ifndef __IEEEMANAGER_H__ +#define __IEEEMANAGER_H__ + +/** \brief The interface structure for the 802.15.4 quasi-MAC. */ +typedef struct ieee_15_4_manager{ + /** Turn the MAC layer on. */ + int (* wake)(void); + /** Turn the MAC layer off. */ + int (* sleep)(void); + + /** Set the operating channel. */ + void (* set_channel)(int channel); + /** Get the operating channel. */ + int (* get_channel)(void); + + /** Set the Destination PAN_ID. */ + void (* set_dst_panid)(int panid); + /** Get the Destination PAN_ID. */ + int (* get_dst_panid)(void); + + /** Set the Source PAN_ID. */ + void (* set_src_panid)(int panid); + /** Get the Source PAN_ID. */ + int (* get_src_panid)(void); + + /** Set the Automatic TRX modes. */ + void (* set_auto_mode)(bool mode); + /** Get the current state of Automatic TRX modes. */ + bool (* get_auto_mode)(void); + + /** Set the Long Address. */ + void (* set_long_addr)(uint64_t address); + /** Get the Long Address. */ + uint64_t (* get_long_addr)(void); + + /** Set the Short Address. */ + void (* set_short_addr)(int address); + /** Get the short Address. */ + int (* get_short_addr)(void); + + /** Set the iAmCoord bit. */ + void (* set_iamcoord_bit)(bool iamcoord); + /** Get the iAmCoord bit. */ + bool (* get_iamcoord_bit)(void); + + /** Set the Coordinator Long address. */ + void (* set_coord_long_addr)(uint64_t address); + /** Get the Coordinator Long address. */ + uint64_t (* get_coord_long_addr)(void); + + /** Set the Coordinator Long address. */ + void (* set_coord_short_addr)(int address); + /** Get the Coordinator Long address. */ + int (* get_coord_short_addr)(void); + + /** Set the Destination address. */ + void (* set_dest_long_addr)(uint64_t address); + /** Get the Destination address. */ + uint64_t (* get_dest_long_addr)(void); +} ieee_15_4_manager_t; + + +void ieee_15_4_init(struct ieee_15_4_manager *pieee_15_4_manager); + +#endif /* __IEEEMANAGER_H__ */ +/** \} */ diff --git a/cpu/avr/radio/mac/Makefile.mac b/cpu/avr/radio/mac/Makefile.mac new file mode 100644 index 000000000..139f51c15 --- /dev/null +++ b/cpu/avr/radio/mac/Makefile.mac @@ -0,0 +1,4 @@ +CONTIKI_TARGET_SOURCEFILES += mac.c sicslowmac.c + +APPDIRS += $(CONTIKI)/cpu/avr/radio/mac + diff --git a/cpu/avr/radio/mac/mac.c b/cpu/avr/radio/mac/mac.c new file mode 100644 index 000000000..c0b2b3f5d --- /dev/null +++ b/cpu/avr/radio/mac/mac.c @@ -0,0 +1,193 @@ +/* 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. + **/ +/** + * \addtogroup wireless + * @{ + */ +/** + * \defgroup rf230mac RF230 MAC + * @{ + */ +/** + * \file + * \brief The IEEE 802.15.4 (2003/2006) MAC utility functions. + * + * $Id: mac.c,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + * + */ + +/** + * \author + * Eric Gnoske + * Blake Leverett + * Mike Vidales + * Colin O'Flynn + * + */ + +/* Includes */ + +#include +#include +#include "mac.h" +#include "radio.h" +#include "hal.h" +#include "tcpip.h" +#include "uip.h" +#include "sicslowpan.h" +#include "sicslowmac.h" + +/* Globals */ +/** \brief Interface structure for this module */ +ieee_15_4_manager_t ieee15_4ManagerAddress; + +//dataRequest_t dataRequestStructAddress; + +/* Macros & Defines */ + +uint8_t msduHandle; +bool iAmCoord; +bool autoModes; + + +/** \brief The RF channel to use for all following transmissions and + * receptions (see 6.1.2). Allowable values are 0-26 + */ +uint8_t phyCurrentChannel; + +/** \brief The 64-bit address of the coordinator/router through which + * the network layer wishes to communicate. + */ +uint64_t macCoordExtendedAddress; + +/** \brief The 16-bit short address assigned to the coordinator + * through which the network layer wishes to communicate. A value + * of 0xfffe indicates th the coordinator is only using it's 64-bit + * extended address. A value of 0xffff indicates that this value is + * unknown. The default value is 0xfff. + */ +uint16_t macCoordShortAddress; + +/** \brief This address is the 64-bit address that will be used as + * the mechanism to provide a destination to the upper layers. The + * default value is 0xfff. + */ +uint64_t macDestAddress; + +/** \brief The sequence number (0x00 - 0xff) added to the transmitted + * data or MAC command frame. The default is a random value within + * the range. + */ +uint8_t macDSN; + +/** \brief The 16-bit identifier of the PAN on which the device is + * sending to. If this value is 0xffff, the device is not + * associated. The default value is 0xffff. + */ +uint16_t macDstPANId; + +/** \brief The 16-bit identifier of the PAN on which the device is + * operating. If this value is 0xffff, the device is not + * associated. The default value is 0xffff. + */ +uint16_t macSrcPANId; + +/** \brief The 16-bit address that the device uses to communicate in + * the PAN. If the device is the PAN coordinator, this value shall + * be chosen before a PAN is started. Otherwise, the address is + * allocated by a coordinator during association. A value of 0xfffe + * indicates that the device has associated but has not been + * allocated an address. A value of 0xffff indicates that the + * device does not have a short address. The default value is + * 0xffff. + */ +uint16_t macShortAddress; + + +/** \brief Our own long address. This needs to be read from EEPROM or + * other secure memory storage. + */ +uint64_t macLongAddr; + +/* Implementation */ + +/** \brief Initializes the (quasi) 802.15.4 MAC. This function should + * be called only once on startup. + */ +void +mac_init(void) +{ + volatile uint8_t buf[8]; + + sicslowmac_resetRequest(true); + + /* Set up the radio for auto mode operation. */ + hal_subregister_write( SR_MAX_FRAME_RETRIES, 2 ); + + /* Need to laod PANID for auto modes */ + radio_set_pan_id(DEST_PAN_ID); + + /* Buffer the uint64_t address for easy loading and debug. */ + /** \todo Find a better location to load the IEEE address. */ + buf[0] = macLongAddr & 0xFF; + buf[1] = (macLongAddr >> 8) & 0xFF; + buf[2] = (macLongAddr >> 16) & 0xFF; + buf[3] = (macLongAddr >> 24) & 0xFF; + buf[4] = (macLongAddr >> 32) & 0xFF; + buf[5] = (macLongAddr >> 40) & 0xFF; + buf[6] = (macLongAddr >> 48) & 0xFF; + buf[7] = (macLongAddr >> 56) & 0xFF; + /* Load the long address into the radio. This is required for auto mode */ + /* operation. */ + radio_set_extended_address((uint8_t *)&macLongAddr); + + srand(1234 ); + msduHandle = rand(); + + /* Ping6 debug */ + memcpy(uip_lladdr.addr, &macLongAddr, 8); + + /* Convert expected byte order */ + byte_reverse((uint8_t *)uip_lladdr.addr, 8); +} + + +/** @} */ +/** @} */ diff --git a/cpu/avr/radio/mac/mac.h b/cpu/avr/radio/mac/mac.h new file mode 100644 index 000000000..f5b13f038 --- /dev/null +++ b/cpu/avr/radio/mac/mac.h @@ -0,0 +1,241 @@ +/* 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. + */ +/** + * \brief The equivalent IEEE 802.15.4 (2003/2006) header file for + * the mac primitives. + * + * $Id: mac.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + * + */ +/** + * \addtogroup rf230mac + * @{ +*/ +/** + * \file + * \brief The IEEE 802.15.4 (2003/2006) MAC utility functions. + */ + +#ifndef MAC_H +#define MAC_H + +/* Includes */ +#include +#include +#include "frame.h" +#include "ieee-15-4-manager.h" + +#define EEPROMMACADDRESS ((void*)0) +#define EEPROMDSTADDRESS ((void*)8) +#define EEPROMCHANADDRESS ((void*)16) +#define EEPROMPANIDADDRESS ((void*)17) +#define EEPROMROLEADDRESS ((void*)19) +#define SUCCESS (0) +#define CHANNEL_PAGE_0 (0) + + + + +/* MAC command frames codes */ + +/* MAC enumerations */ +/** \brief Pre-defined data frame control field (FCF) values. + * \name FCF Values + * @{ +*/ +#define FCF_NO_ACK (0x8841) +#define FCF_ACK_REQ (0x8861) +/** @} */ + +/** \brief Hardcoded various "network" addresses, for use when testing. + * \name Pre-defined network addresses + * @{ + */ +#define DEST_PAN_ID (0xABCD) +#define SOURCE_PAN_ID (0xABCD) +#define LONG_ADDR_1 (0xFFEEDDCCBBAA1100LL) +#define LONG_ADDR_2 (0x1122334455667788LL) +#define LONG_ADDR_3 (0xDDEEAADDBBEEEEFFLL) +#define LONG_ADDR_4 (0x0123456789ABCDEFLL) +#define SOURCE_ADDR (0x1234) +#define FCF_ACK (0x0002) +#define TX_OPTION_NOACK (0) +#define TX_OPTION_ACK (1) +#define LONG_ADDR_LEN (8) +/** @} */ + +#define MPDU_OVERHEAD (11) /**< This overhead includes FCF, DSN, DEST_PAN_ID, DEST_ADDR, SOURCE_ADDR, & FCS */ + + +/** \brief These are some definitions of values used in the FCF. See the 802.15.4 spec for details. + * \name FCF element values definitions + * @{ + */ +#define BEACONFRAME (0x00) +#define DATAFRAME (0x01) +#define ACKFRAME (0x02) +#define CMDFRAME (0x03) + +#define BEACONREQ (0x07) + +#define IEEERESERVED (0x00) +#define NOADDR (0x00) /**< Only valid for ACK or Beacon frames. */ +#define SHORTADDRMODE (0x02) +#define LONGADDRMODE (0x03) + +#define NOBEACONS (0x0F) + +#define BROADCASTADDR (0xFFFF) +#define BROADCASTPANDID (0xFFFF) + +#define IEEE802154_2003 (0x00) +#define IEEE802154_2006 (0x01) + +#define SECURITY_LEVEL_NONE (0) +#define SECURITY_LEVEL_128 (3) + +#define PSDULEN (127) +/** @} */ + + +/* typedef enum {TRUE, FALSE} bool; */ + +typedef struct dataRequest { + uint8_t srcAddrMode; + uint8_t dstAddrMode; + uint16_t dstPANId; + addr_t dstAddr; + uint8_t msduLength; + uint8_t *msdu; + uint8_t msduHandle; + uint8_t txOptions; + uint8_t securityLevel; + uint8_t keyIdMode; + uint8_t *keySource; + uint8_t keyIndex; +} dataRequest_t; + + +/* Macros & Defines */ +extern ieee_15_4_manager_t ieee15_4ManagerAddress; +extern dataRequest_t dataRequestStructAddress; +#define ieee15_4Struct (&ieee15_4ManagerAddress) +#define dataRequestStruct (&dataRequestStructAddress) + + +/** + * \name Scan variables + * \brief Global variables and defines for scan. + * \{ +*/ +extern uint8_t msduHandle; +extern bool iAmCoord; +extern bool autoModes; +extern uint16_t macShortAddr; +extern uint64_t macLongAddr; +/** @} */ + +/* PHY PIB Attributes */ + +/* uint8_t phyCurrentChannel Integer 0-26 + * The RF channel to use for all following transmissions and receptions (see6.1.2). + */ +extern uint8_t phyCurrentChannel; + +/* uint64_t macCoordExtendedAddress -- no default + * + * The 64-bit address of the coordinator/router through which the network layer wishes to communicate + */ +extern uint64_t macCoordExtendedAddress; + +/* uint16_t macCoordShortAddress -- default 0xffff + * + * The 16-bit short address assigned to the coordinator through which the network layer wishes + * to communicate. A value of 0xfffe indicates th the coordinator is only using it's 64-bit + * extended address. A value of 0xffff indicates that this value is unknown. + */ +extern uint16_t macCoordShortAddress; + +/* uint64_t macDestAddress -- default 0xffff + * + * This address is the 64-bit address that will be used as the mechanism to + * provide a destination to the upper layers. + */ +extern uint64_t macDestAddress; + +/* uint8_t macDSN -- default is random value within the range + * + * The sequence number (0x00 - 0xff) added to the transmitted data or MAC command frame. + */ +extern uint8_t macDSN; + +/* uint16_t macDstPANId -- default 0xffff + * + * The 16-bit identifier of the PAN on which the device is sending to. If this value + * is 0xffff, the device is not associated. + */ +extern uint16_t macDstPANId; + +/* uint16_t macSrcPANId -- default 0xffff + * + * The 16-bit identifier of the PAN on which the device is operating. If this value + * is 0xffff, the device is not associated. + */ +extern uint16_t macSrcPANId; + +/* uint16_t macShortAddress -- default 0xffff + * + * The 16-bit address that the device uses to communicate in the PAN. If the device is the + * PAN coordinator, this value shall be chosen before a PAN is started. Otherwise, the + * address is allocated by a coordinator during association. A value of 0xfffe indicates + * that the device has associated but has not been allocated an address. A value of 0xffff + * indicates that the device does not have a short address. + */ +extern uint16_t macShortAddress; + +/* Scan defines */ + + +/* Protoypes */ +void mac_init(void); + +#endif + +/** @} */ diff --git a/cpu/avr/radio/mac/sicslowmac.c b/cpu/avr/radio/mac/sicslowmac.c new file mode 100644 index 000000000..eefb64727 --- /dev/null +++ b/cpu/avr/radio/mac/sicslowmac.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + * $Id: sicslowmac.c,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ + + +/** + * \file + * Example glue code between the existing MAC code and the + * Contiki mac interface + * + * \author + * Adam Dunkels + * Eric Gnoske + * Blake Leverett + * + * \addtogroup rf230mac + */ + +#include +#include +#include +#include +#include +#include +#include "net/rime/rimebuf.h" +#include "mac.h" +#include "frame.h" +#include "radio.h" +#include "tcpip.h" +#include "sicslowmac.h" +#include "sicslowpan.h" +#include "ieee-15-4-manager.h" + +/* Macros */ +#define DEBUG 0 +#define MAX_EVENTS 10 + +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/* Globals */ +static mac_driver_t mac_driver; +static mac_driver_t *pmac_driver = &mac_driver; +extern ieee_15_4_manager_t ieee15_4ManagerAddress; +static parsed_frame_t *parsed_frame; + + +const mac_driver_t sicslowmac_driver = { + sicslowmac_dataRequest, + /* read_packet, */ + /* set_receive_function, */ + /* on, */ + /* off, */ +}; + +static struct { + uint8_t head; + uint8_t tail; + event_object_t event_object[MAX_EVENTS]; +} event_queue; + +/* Prototypes */ +static void setinput(void (*r)(const mac_driver_t *d)); +static void (*pinput)(const mac_driver_t *r); + +/*---------------------------------------------------------------------------*/ +/** + * \brief Checks for any pending events in the queue. + * + * \return True if there is a pending event, else false. + */ +uint8_t +mac_event_pending(void) +{ + return (event_queue.head != event_queue.tail); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Puts an event into the queue of events. + * + * \param object is a pointer to the event to add to queue. + */ +void +mac_put_event(event_object_t *object) +{ + uint8_t newhead; + + if ((event_queue.head + 1) % MAX_EVENTS == event_queue.tail){ + /* queue full, get outta here */ + return; + } + + newhead = event_queue.head; + + /* store in queue */ + event_queue.event_object[newhead] = *object; + + /* calculate new head index */ + newhead++; + if (newhead >= MAX_EVENTS){ + newhead = 0; + } + event_queue.head = newhead; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Pulls an event from the event queue. + * Assumes that there is an event in the queue. See mac_event_pending(). + * + * \return Pointer to the event object, or NULL in the event of empty queue. + */ +event_object_t +*mac_get_event(void) +{ + event_object_t *object = NULL; + volatile uint8_t newtail; + + newtail = event_queue.tail; + + object = &(event_queue.event_object[newtail]); + + /* calculate new tail */ + newtail++; + if (newtail >= MAX_EVENTS){ + newtail = 0; + } + + event_queue.tail = newtail; + + return(object); +} + +void mac_pollhandler(void) +{ + mac_task(NULL, NULL); +} + +/*---------------------------------------------------------------------------*/ +/** + * \brief This is the main loop task for the MAC. Called by the + * main application loop. + */ +void +mac_task(process_event_t ev, process_data_t data) +{ + /* check for event in queue */ + event_object_t *event; + + if(mac_event_pending()){ + + event = mac_get_event(); + + /* Handle events from radio */ + if (event){ + if (event->event == MAC_EVENT_RX){ + /* got a frame, find out with kind of frame */ + parsed_frame = (parsed_frame_t *)event->data; + if (parsed_frame->fcf->frameType == DATAFRAME){ + sicslowmac_dataIndication(); + } + + /* Frame no longer in use */ + parsed_frame->in_use = false; + } + + if (event->event == MAC_EVENT_DROPPED){ + /* Frame was dropped */ + printf("sicslowmac: Frame Dropped!\n"); + } + } + } +} +/*---------------------------------------------------------------------------*/ +static void +setinput(void (*r)(const mac_driver_t *d)) +{ + pinput = r; +} +/*---------------------------------------------------------------------------*/ +void +sicslowmac_dataIndication(void) +{ + rimebuf_clear(); + + /* Finally, get the stuff into the rime buffer.... */ + rimebuf_copyfrom(parsed_frame->payload, parsed_frame->payload_length); + rimebuf_set_datalen(parsed_frame->payload_length); + + /* Change addresses to expected byte order */ + byte_reverse((uint8_t *)parsed_frame->dest_addr, 8); + byte_reverse((uint8_t *)parsed_frame->src_addr, 8); + + rimebuf_set_addr(RIMEBUF_ADDR_RECEIVER, (const rimeaddr_t *)parsed_frame->dest_addr); + rimebuf_set_addr(RIMEBUF_ADDR_SENDER, (const rimeaddr_t *)parsed_frame->src_addr); + + PRINTF("sicslowmac: hand off frame to sicslowpan \n"); + pinput(pmac_driver); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief This is the implementation of the 15.4 MAC Data Request + * primitive. + * + * \return Integer denoting success or failure. + * \retval 0 Failure. + * \retval 1 Success. + * + * The data request primitive creates the frame header based + * on static and dynamic data. The static data will be refined + * in phase II of the project. The frame payload and length are + * retrieved from the rime buffer and rime length respectively. + * + * When the header and payload are assembled into the + * frame_create_params structure, the frame is created + * by a call to frame_tx_create and then transmited via + * radio_send_data. + */ +/*---------------------------------------------------------------------------*/ +int +sicslowmac_dataRequest(void) +{ + + /* create structure to store result. */ + frame_create_params_t params; + frame_result_t result; + + /* Save the msduHandle in a global variable. */ + msduHandle = rimebuf_attr(RIMEBUF_ATTR_PACKET_ID); + + /* Build the FCF. */ + params.fcf.frameType = DATAFRAME; + params.fcf.securityEnabled = false; + params.fcf.framePending = false; + params.fcf.ackRequired = rimebuf_attr(RIMEBUF_ATTR_RELIABLE); + params.fcf.panIdCompression = false; + + /* Insert IEEE 802.15.4 (2003) version bit. */ + params.fcf.frameVersion = IEEE802154_2003; + + /* Increment and set the data sequence number. */ + params.seq = macDSN++; + + /* Complete the addressing fields. */ + /** + \todo For phase 1 the addresses are all long. We'll need a mechanism + in the rime attributes to tell the mac to use long or short for phase 2. + */ + params.fcf.srcAddrMode = LONGADDRMODE; + params.dest_pid = ieee15_4ManagerAddress.get_dst_panid(); + + /* + * If the output address is NULL in the Rime buf, then it is broadcast + * on the 802.15.4 network. + */ + if(rimeaddr_cmp(rimebuf_addr(RIMEBUF_ADDR_RECEIVER), &rimeaddr_null) ) { + /* Broadcast requires short address mode. */ + params.fcf.destAddrMode = SHORTADDRMODE; + params.dest_pid = BROADCASTPANDID; + params.dest_addr.addr16 = BROADCASTADDR; + + } else { + + /* Phase 1.5 - end nodes send to anyone? */ + memcpy(¶ms.dest_addr, (uint8_t *)rimebuf_addr(RIMEBUF_ADDR_RECEIVER), LONG_ADDR_LEN); + + /* Hack to allow Ethernet to send us data, we have to limit addresses to have zero in upper */ + /* two bytes */ + /* params.dest_addr.addr64 &= 0x0000ffffffffffffUL; */ + + /* Phase 1 - end nodes only sends to pan coordinator node. */ + /* params.dest_addr.addr64 = ieee15_4ManagerAddress.get_coord_long_addr(); */ + params.fcf.destAddrMode = LONGADDRMODE; + } + + /* Set the source PAN ID to the global variable. */ + params.src_pid = ieee15_4ManagerAddress.get_src_panid(); + + /* + * Set up the source address using only the long address mode for + * phase 1. + */ + params.src_addr.addr64 = ieee15_4ManagerAddress.get_long_addr(); + + /* Copy the payload data. */ + params.payload_len = rimebuf_datalen(); + params.payload = rimebuf_dataptr(); + + /* Create transmission frame. */ + frame_tx_create(¶ms, &result); + + /* Retry up to this many times to send the packet if radio is busy */ + uint8_t retry_count = 3; + + while(retry_count) { + + PRINTF("sicslowmac: sending packet of length %d to radio, result:", result.length); + + /* Send data to radio. */ + radio_status_t rv = radio_send_data(result.length, result.frame); + + if (rv == RADIO_SUCCESS) { + PRINTF(" Success\n"); + + return 1; /* True says that the packet could be sent */ + } + + + if (rv != RADIO_WRONG_STATE) { + PRINTF(" Failed\n"); + return 0; + } + + PRINTF(" Radio busy, retrying\n"); + + _delay_ms(10); //We have blocking delay here, it is safest this way + + retry_count--; + } + + PRINTF("sicslowmac: Unable to send packet, dropped\n"); + return 0; + +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Stub function that will be implemented in phase 2 to cause + * end nodes to sleep. + */ +int +mac_wake(void) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Stub function that will be implemented in phase 2 to cause + * end nodes to sleep. + */ +int +mac_sleep(void) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +const mac_driver_t * +sicslowmac_init(const struct radio_driver *d) +{ + /* AD: commented out the radio_driver code for now.*/ + /* radio = d; + radio->set_receive_function(input_packet); + radio->on();*/ + + return &sicslowmac_driver; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief This is the implementation of the 15.4 MAC Reset Request + * primitive. + * \param setDefaultPIB True if the default PIB values should be set. + * \return Integer denoting success or failure. + * \retval 0 Failure. + * \retval 1 Success. + * + * Sets all PIB values to default. + */ +void +sicslowmac_resetRequest (bool setDefaultPIB) +{ + if(setDefaultPIB){ + /* initialize all of the MAC PIB variables to their default values */ + macCoordShortAddress = 0xffff; + macDSN = rand() % 256; + macSrcPANId = SOURCE_PAN_ID; + macDstPANId = DEST_PAN_ID; + macShortAddress = 0xffff; + /* Setup the address of this device by reading a stored address from eeprom. */ + /** \todo This might be read from the serial eeprom onboard Raven. */ + AVR_ENTER_CRITICAL_REGION(); + eeprom_read_block ((void *)&macLongAddr, EEPROMMACADDRESS, 8); + + byte_reverse((uint8_t *) &macLongAddr, 8); + + + AVR_LEAVE_CRITICAL_REGION(); + } +} +/*---------------------------------------------------------------------------*/ +PROCESS(mac_process, "802.15.4 MAC process"); +PROCESS_THREAD(mac_process, ev, data) +{ + + PROCESS_POLLHANDLER(mac_pollhandler()); + + + PROCESS_BEGIN(); + + radio_status_t return_value; + + /* init radio */ + /** \todo: this screws up if calosc is set to TRUE, find out why? */ + return_value = radio_init(false, NULL, NULL, NULL); + +#if DEBUG + if (return_value == RADIO_SUCCESS) { + printf("Radio init successful.\n"); + } else { + printf("Radio init failed with return: %d\n", return_value); + } +#endif + + radio_set_operating_channel(24); + radio_use_auto_tx_crc(true); + radio_set_trx_state(TRX_OFF); + + mac_init(); + + /* Set up MAC function pointers and sicslowpan callback. */ + pmac_driver->set_receive_function = setinput; + pmac_driver->send = sicslowmac_dataRequest; + pmac_driver->wake = mac_wake; + pmac_driver->sleep = mac_sleep; + sicslowpan_init(pmac_driver); + + ieee_15_4_init(&ieee15_4ManagerAddress); + + radio_set_trx_state(RX_AACK_ON); + + while(1) { + PROCESS_YIELD(); + mac_task(ev, data); + + } + + PROCESS_END(); +} + +void byte_reverse(uint8_t * bytes, uint8_t num) +{ + uint8_t tempbyte; + + uint8_t i, j; + + i = 0; + j = num - 1; + + while(i < j) { + tempbyte = bytes[i]; + bytes[i] = bytes[j]; + bytes[j] = tempbyte; + + j--; + i++; + } + + return; +} diff --git a/cpu/avr/radio/mac/sicslowmac.h b/cpu/avr/radio/mac/sicslowmac.h new file mode 100644 index 000000000..7c581a614 --- /dev/null +++ b/cpu/avr/radio/mac/sicslowmac.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + * + * $Id: sicslowmac.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ + +/** + * \file + * Example glue code between the existing MAC code and the + * Contiki mac interface + * \author + * Adam Dunkels + * Eric Gnoske + * Blake Leverett + */ + +/** + \addtogroup rf230mac +*/ + +#ifndef __SICSLOWMAC_H__ +#define __SICSLOWMAC_H__ + +#include +#include +#include "contiki.h" +#include "dev/radio.h" + +/** + * The structure of a device driver for a radio in Contiki. + */ +typedef struct mac_driver_s{ + /** Send a packet from the Rime buffer */ + int (* send)(void); + + /** Read a received packet into the Rime buffer. */ +/* int (* read)(void); */ + + /** Set a function to be called when a packet has been received. */ + void (* set_receive_function)(void (*f)(const struct mac_driver_s *d)); + + /** Wake the radio up. */ + int (* wake)(void); + + /** Put the radio to sleep. */ + int (* sleep)(void); +}mac_driver_t; + +/* Macros & Defines */ + +typedef enum { + MAC_EVENT_RX=0x10, + MAC_EVENT_ACK, + MAC_EVENT_NACK, + MAC_EVENT_SCAN, + MAC_EVENT_BEACON_REQ, + MAC_EVENT_DROPPED, + MAC_EVENT_TX + /* MAC_EVENT_TIMER */ +} event_t; + +typedef struct { + event_t event; /**< Event type, see event_t for details. */ + uint8_t *data; /**< Associated data that goes with the event. Depends on event type. */ +} event_object_t; + +extern const mac_driver_t sicslowmac_driver; + +/* Prototypes */ +PROCESS_NAME(mac_process); + +uint8_t mac_event_pending(void); +void mac_put_event(event_object_t *object); +event_object_t *mac_get_event(void); +void mac_task(process_event_t ev, process_data_t data); +uint8_t nwk_dataIndication(void); +const mac_driver_t *sicslowmac_init(const struct radio_driver *r); +/* void sicslowmac_input_packet(const struct radio_driver *d); */ +int sicslowmac_dataRequest(void); +void sicslowmac_dataIndication(void); +void sicslowmac_resetRequest (bool setDefaultPIB); +int sicsloread(void); +void byte_reverse(uint8_t * bytes, uint8_t num); + +#endif /* __SICSLOWMAC_H__ */ diff --git a/cpu/avr/radio/rf230/Makefile.rf230 b/cpu/avr/radio/rf230/Makefile.rf230 new file mode 100644 index 000000000..70600266e --- /dev/null +++ b/cpu/avr/radio/rf230/Makefile.rf230 @@ -0,0 +1,6 @@ + +CONTIKI_TARGET_SOURCEFILES += radio.c hal.c frame.c +# timer.c + +APPDIRS += $(CONTIKI)/cpu/avr/radio/rf230 + diff --git a/cpu/avr/radio/rf230/at86rf230_registermap.h b/cpu/avr/radio/rf230/at86rf230_registermap.h new file mode 100644 index 000000000..e05b8c38e --- /dev/null +++ b/cpu/avr/radio/rf230/at86rf230_registermap.h @@ -0,0 +1,351 @@ +/** + * @file + * @brief This file contains the register definitions for the AT86RF230. + * $Id: at86rf230_registermap.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ +/* 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. +*/ + +#ifndef PHY230_REGISTERMAP_EXTERNAL_H +#define PHY230_REGISTERMAP_EXTERNAL_H + +#define HAVE_REGISTER_MAP (1) +/** Offset for register TRX_STATUS */ +#define RG_TRX_STATUS (0x01) +/** Access parameters for sub-register CCA_DONE in register @ref RG_TRX_STATUS */ +#define SR_CCA_DONE 0x01, 0x80, 7 +/** Access parameters for sub-register CCA_STATUS in register @ref RG_TRX_STATUS */ +#define SR_CCA_STATUS 0x01, 0x40, 6 +#define SR_reserved_01_3 0x01, 0x20, 5 +/** Access parameters for sub-register TRX_STATUS in register @ref RG_TRX_STATUS */ +#define SR_TRX_STATUS 0x01, 0x1f, 0 +/** Constant P_ON for sub-register @ref SR_TRX_STATUS */ +#define P_ON (0) +/** Constant BUSY_RX for sub-register @ref SR_TRX_STATUS */ +#define BUSY_RX (1) +/** Constant BUSY_TX for sub-register @ref SR_TRX_STATUS */ +#define BUSY_TX (2) +/** Constant RX_ON for sub-register @ref SR_TRX_STATUS */ +#define RX_ON (6) +/** Constant TRX_OFF for sub-register @ref SR_TRX_STATUS */ +#define TRX_OFF (8) +/** Constant PLL_ON for sub-register @ref SR_TRX_STATUS */ +#define PLL_ON (9) +/** Constant SLEEP for sub-register @ref SR_TRX_STATUS */ +#define SLEEP (15) +/** Constant BUSY_RX_AACK for sub-register @ref SR_TRX_STATUS */ +#define BUSY_RX_AACK (17) +/** Constant BUSY_TX_ARET for sub-register @ref SR_TRX_STATUS */ +#define BUSY_TX_ARET (18) +/** Constant RX_AACK_ON for sub-register @ref SR_TRX_STATUS */ +#define RX_AACK_ON (22) +/** Constant TX_ARET_ON for sub-register @ref SR_TRX_STATUS */ +#define TX_ARET_ON (25) +/** Constant RX_ON_NOCLK for sub-register @ref SR_TRX_STATUS */ +#define RX_ON_NOCLK (28) +/** Constant RX_AACK_ON_NOCLK for sub-register @ref SR_TRX_STATUS */ +#define RX_AACK_ON_NOCLK (29) +/** Constant BUSY_RX_AACK_NOCLK for sub-register @ref SR_TRX_STATUS */ +#define BUSY_RX_AACK_NOCLK (30) +/** Offset for register TRX_STATE */ +#define RG_TRX_STATE (0x02) +/** Access parameters for sub-register TRAC_STATUS in register @ref RG_TRX_STATE */ +#define SR_TRAC_STATUS 0x02, 0xe0, 5 +/** Access parameters for sub-register TRX_CMD in register @ref RG_TRX_STATE */ +#define SR_TRX_CMD 0x02, 0x1f, 0 +/** Constant CMD_NOP for sub-register @ref SR_TRX_CMD */ +#define CMD_NOP (0) +/** Constant CMD_TX_START for sub-register @ref SR_TRX_CMD */ +#define CMD_TX_START (2) +/** Constant CMD_FORCE_TRX_OFF for sub-register @ref SR_TRX_CMD */ +#define CMD_FORCE_TRX_OFF (3) +/** Constant CMD_RX_ON for sub-register @ref SR_TRX_CMD */ +#define CMD_RX_ON (6) +/** Constant CMD_TRX_OFF for sub-register @ref SR_TRX_CMD */ +#define CMD_TRX_OFF (8) +/** Constant CMD_PLL_ON for sub-register @ref SR_TRX_CMD */ +#define CMD_PLL_ON (9) +/** Constant CMD_RX_AACK_ON for sub-register @ref SR_TRX_CMD */ +#define CMD_RX_AACK_ON (22) +/** Constant CMD_TX_ARET_ON for sub-register @ref SR_TRX_CMD */ +#define CMD_TX_ARET_ON (25) +/** Offset for register TRX_CTRL_0 */ +#define RG_TRX_CTRL_0 (0x03) +/** Offset for register TRX_CTRL_1 */ +#define RG_TRX_CTRL_1 (0x04) +/** Access parameters for sub-register PAD_IO in register @ref RG_TRX_CTRL_0 */ +#define SR_PAD_IO 0x03, 0xc0, 6 +/** Access parameters for sub-register PAD_IO_CLKM in register @ref RG_TRX_CTRL_0 */ +#define SR_PAD_IO_CLKM 0x03, 0x30, 4 +/** Constant CLKM_2mA for sub-register @ref SR_PAD_IO_CLKM */ +#define CLKM_2mA (0) +/** Constant CLKM_4mA for sub-register @ref SR_PAD_IO_CLKM */ +#define CLKM_4mA (1) +/** Constant CLKM_6mA for sub-register @ref SR_PAD_IO_CLKM */ +#define CLKM_6mA (2) +/** Constant CLKM_8mA for sub-register @ref SR_PAD_IO_CLKM */ +#define CLKM_8mA (3) +/** Access parameters for sub-register CLKM_SHA_SEL in register @ref RG_TRX_CTRL_0 */ +#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 +/** Access parameters for sub-register CLKM_CTRL in register @ref RG_TRX_CTRL_0 */ +#define SR_CLKM_CTRL 0x03, 0x07, 0 +/** Constant CLKM_no_clock for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_no_clock (0) +/** Constant CLKM_1MHz for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_1MHz (1) +/** Constant CLKM_2MHz for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_2MHz (2) +/** Constant CLKM_4MHz for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_4MHz (3) +/** Constant CLKM_8MHz for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_8MHz (4) +/** Constant CLKM_16MHz for sub-register @ref SR_CLKM_CTRL */ +#define CLKM_16MHz (5) +/** Offset for register PHY_TX_PWR */ +#define RG_PHY_TX_PWR (0x05) +/** Access parameters for sub-register TX_AUTO_CRC_ON in register @ref RG_PHY_TX_PWR */ +#define SR_TX_AUTO_CRC_ON 0x05, 0x80, 7 +#define SR_reserved_05_2 0x05, 0x70, 4 +/** Access parameters for sub-register TX_PWR in register @ref RG_PHY_TX_PWR */ +#define SR_TX_PWR 0x05, 0x0f, 0 +/** Offset for register PHY_RSSI */ +#define RG_PHY_RSSI (0x06) +#define SR_reserved_06_1 0x06, 0xe0, 5 +/** Access parameters for sub-register RSSI in register @ref RG_PHY_RSSI */ +#define SR_RSSI 0x06, 0x1f, 0 +/** Offset for register PHY_ED_LEVEL */ +#define RG_PHY_ED_LEVEL (0x07) +/** Access parameters for sub-register ED_LEVEL in register @ref RG_PHY_ED_LEVEL */ +#define SR_ED_LEVEL 0x07, 0xff, 0 +/** Offset for register PHY_CC_CCA */ +#define RG_PHY_CC_CCA (0x08) +/** Access parameters for sub-register CCA_REQUEST in register @ref RG_PHY_CC_CCA */ +#define SR_CCA_REQUEST 0x08, 0x80, 7 +/** Access parameters for sub-register CCA_MODE in register @ref RG_PHY_CC_CCA */ +#define SR_CCA_MODE 0x08, 0x60, 5 +/** Access parameters for sub-register CHANNEL in register @ref RG_PHY_CC_CCA */ +#define SR_CHANNEL 0x08, 0x1f, 0 +/** Offset for register CCA_THRES */ +#define RG_CCA_THRES (0x09) +/** Access parameters for sub-register CCA_CS_THRES in register @ref RG_CCA_THRES */ +#define SR_CCA_CS_THRES 0x09, 0xf0, 4 +/** Access parameters for sub-register CCA_ED_THRES in register @ref RG_CCA_THRES */ +#define SR_CCA_ED_THRES 0x09, 0x0f, 0 +/** Offset for register IRQ_MASK */ +#define RG_IRQ_MASK (0x0e) +/** Access parameters for sub-register IRQ_MASK in register @ref RG_IRQ_MASK */ +#define SR_IRQ_MASK 0x0e, 0xff, 0 +/** Offset for register IRQ_STATUS */ +#define RG_IRQ_STATUS (0x0f) +/** Access parameters for sub-register IRQ_7_BAT_LOW in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 +/** Access parameters for sub-register IRQ_6_TRX_UR in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 +/** Access parameters for sub-register IRQ_5 in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_5 0x0f, 0x20, 5 +/** Access parameters for sub-register IRQ_4 in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_4 0x0f, 0x10, 4 +/** Access parameters for sub-register IRQ_3_TRX_END in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 +/** Access parameters for sub-register IRQ_2_RX_START in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 +/** Access parameters for sub-register IRQ_1_PLL_UNLOCK in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 +/** Access parameters for sub-register IRQ_0_PLL_LOCK in register @ref RG_IRQ_STATUS */ +#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 +/** Offset for register VREG_CTRL */ +#define RG_VREG_CTRL (0x10) +/** Access parameters for sub-register AVREG_EXT in register @ref RG_VREG_CTRL */ +#define SR_AVREG_EXT 0x10, 0x80, 7 +/** Access parameters for sub-register AVDD_OK in register @ref RG_VREG_CTRL */ +#define SR_AVDD_OK 0x10, 0x40, 6 +/** Access parameters for sub-register AVREG_TRIM in register @ref RG_VREG_CTRL */ +#define SR_AVREG_TRIM 0x10, 0x30, 4 +/** Constant AVREG_1_80V for sub-register @ref SR_AVREG_TRIM */ +#define AVREG_1_80V (0) +/** Constant AVREG_1_75V for sub-register @ref SR_AVREG_TRIM */ +#define AVREG_1_75V (1) +/** Constant AVREG_1_84V for sub-register @ref SR_AVREG_TRIM */ +#define AVREG_1_84V (2) +/** Constant AVREG_1_88V for sub-register @ref SR_AVREG_TRIM */ +#define AVREG_1_88V (3) +/** Access parameters for sub-register DVREG_EXT in register @ref RG_VREG_CTRL */ +#define SR_DVREG_EXT 0x10, 0x08, 3 +/** Access parameters for sub-register DVDD_OK in register @ref RG_VREG_CTRL */ +#define SR_DVDD_OK 0x10, 0x04, 2 +/** Access parameters for sub-register DVREG_TRIM in register @ref RG_VREG_CTRL */ +#define SR_DVREG_TRIM 0x10, 0x03, 0 +/** Constant DVREG_1_80V for sub-register @ref SR_DVREG_TRIM */ +#define DVREG_1_80V (0) +/** Constant DVREG_1_75V for sub-register @ref SR_DVREG_TRIM */ +#define DVREG_1_75V (1) +/** Constant DVREG_1_84V for sub-register @ref SR_DVREG_TRIM */ +#define DVREG_1_84V (2) +/** Constant DVREG_1_88V for sub-register @ref SR_DVREG_TRIM */ +#define DVREG_1_88V (3) +/** Offset for register BATMON */ +#define RG_BATMON (0x11) +#define SR_reserved_11_1 0x11, 0xc0, 6 +/** Access parameters for sub-register BATMON_OK in register @ref RG_BATMON */ +#define SR_BATMON_OK 0x11, 0x20, 5 +/** Access parameters for sub-register BATMON_HR in register @ref RG_BATMON */ +#define SR_BATMON_HR 0x11, 0x10, 4 +/** Access parameters for sub-register BATMON_VTH in register @ref RG_BATMON */ +#define SR_BATMON_VTH 0x11, 0x0f, 0 +/** Offset for register XOSC_CTRL */ +#define RG_XOSC_CTRL (0x12) +/** Offset for register RX_SYN */ +#define RG_RX_SYN 0x15 +/** Offset for register XAH_CTRL_1 */ +#define RG_XAH_CTRL_1 0x17 +/** Access parameters for sub-register XTAL_MODE in register @ref RG_XOSC_CTRL */ +#define SR_XTAL_MODE 0x12, 0xf0, 4 +/** Access parameters for sub-register XTAL_TRIM in register @ref RG_XOSC_CTRL */ +#define SR_XTAL_TRIM 0x12, 0x0f, 0 +/** Offset for register FTN_CTRL */ +#define RG_FTN_CTRL (0x18) +/** Access parameters for sub-register FTN_START in register @ref RG_FTN_CTRL */ +#define SR_FTN_START 0x18, 0x80, 7 +#define SR_reserved_18_2 0x18, 0x40, 6 +/** Access parameters for sub-register FTNV in register @ref RG_FTN_CTRL */ +#define SR_FTNV 0x18, 0x3f, 0 +/** Offset for register PLL_CF */ +#define RG_PLL_CF (0x1a) +/** Access parameters for sub-register PLL_CF_START in register @ref RG_PLL_CF */ +#define SR_PLL_CF_START 0x1a, 0x80, 7 +#define SR_reserved_1a_2 0x1a, 0x70, 4 +/** Access parameters for sub-register PLL_CF in register @ref RG_PLL_CF */ +#define SR_PLL_CF 0x1a, 0x0f, 0 +/** Offset for register PLL_DCU */ +#define RG_PLL_DCU (0x1b) +/** Access parameters for sub-register PLL_DCU_START in register @ref RG_PLL_DCU */ +#define SR_PLL_DCU_START 0x1b, 0x80, 7 +#define SR_reserved_1b_2 0x1b, 0x40, 6 +/** Access parameters for sub-register PLL_DCUW in register @ref RG_PLL_DCU */ +#define SR_PLL_DCUW 0x1b, 0x3f, 0 +/** Offset for register PART_NUM */ +#define RG_PART_NUM (0x1c) +/** Access parameters for sub-register PART_NUM in register @ref RG_PART_NUM */ +#define SR_PART_NUM 0x1c, 0xff, 0 +/** Constant RF230 for sub-register @ref SR_PART_NUM */ +#define RF230 (2) +/** Offset for register VERSION_NUM */ +#define RG_VERSION_NUM (0x1d) +/** Access parameters for sub-register VERSION_NUM in register @ref RG_VERSION_NUM */ +#define SR_VERSION_NUM 0x1d, 0xff, 0 +/** Offset for register MAN_ID_0 */ +#define RG_MAN_ID_0 (0x1e) +/** Access parameters for sub-register MAN_ID_0 in register @ref RG_MAN_ID_0 */ +#define SR_MAN_ID_0 0x1e, 0xff, 0 +/** Offset for register MAN_ID_1 */ +#define RG_MAN_ID_1 (0x1f) +/** Access parameters for sub-register MAN_ID_1 in register @ref RG_MAN_ID_1 */ +#define SR_MAN_ID_1 0x1f, 0xff, 0 +/** Offset for register SHORT_ADDR_0 */ +#define RG_SHORT_ADDR_0 (0x20) +/** Access parameters for sub-register SHORT_ADDR_0 in register @ref RG_SHORT_ADDR_0 */ +#define SR_SHORT_ADDR_0 0x20, 0xff, 0 +/** Offset for register SHORT_ADDR_1 */ +#define RG_SHORT_ADDR_1 (0x21) +/** Access parameters for sub-register SHORT_ADDR_1 in register @ref RG_SHORT_ADDR_1 */ +#define SR_SHORT_ADDR_1 0x21, 0xff, 0 +/** Offset for register PAN_ID_0 */ +#define RG_PAN_ID_0 (0x22) +/** Access parameters for sub-register PAN_ID_0 in register @ref RG_PAN_ID_0 */ +#define SR_PAN_ID_0 0x22, 0xff, 0 +/** Offset for register PAN_ID_1 */ +#define RG_PAN_ID_1 (0x23) +/** Access parameters for sub-register PAN_ID_1 in register @ref RG_PAN_ID_1 */ +#define SR_PAN_ID_1 0x23, 0xff, 0 +/** Offset for register IEEE_ADDR_0 */ +#define RG_IEEE_ADDR_0 (0x24) +/** Access parameters for sub-register IEEE_ADDR_0 in register @ref RG_IEEE_ADDR_0 */ +#define SR_IEEE_ADDR_0 0x24, 0xff, 0 +/** Offset for register IEEE_ADDR_1 */ +#define RG_IEEE_ADDR_1 (0x25) +/** Access parameters for sub-register IEEE_ADDR_1 in register @ref RG_IEEE_ADDR_1 */ +#define SR_IEEE_ADDR_1 0x25, 0xff, 0 +/** Offset for register IEEE_ADDR_2 */ +#define RG_IEEE_ADDR_2 (0x26) +/** Access parameters for sub-register IEEE_ADDR_2 in register @ref RG_IEEE_ADDR_2 */ +#define SR_IEEE_ADDR_2 0x26, 0xff, 0 +/** Offset for register IEEE_ADDR_3 */ +#define RG_IEEE_ADDR_3 (0x27) +/** Access parameters for sub-register IEEE_ADDR_3 in register @ref RG_IEEE_ADDR_3 */ +#define SR_IEEE_ADDR_3 0x27, 0xff, 0 +/** Offset for register IEEE_ADDR_4 */ +#define RG_IEEE_ADDR_4 (0x28) +/** Access parameters for sub-register IEEE_ADDR_4 in register @ref RG_IEEE_ADDR_4 */ +#define SR_IEEE_ADDR_4 0x28, 0xff, 0 +/** Offset for register IEEE_ADDR_5 */ +#define RG_IEEE_ADDR_5 (0x29) +/** Access parameters for sub-register IEEE_ADDR_5 in register @ref RG_IEEE_ADDR_5 */ +#define SR_IEEE_ADDR_5 0x29, 0xff, 0 +/** Offset for register IEEE_ADDR_6 */ +#define RG_IEEE_ADDR_6 (0x2a) +/** Access parameters for sub-register IEEE_ADDR_6 in register @ref RG_IEEE_ADDR_6 */ +#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 +/** Offset for register IEEE_ADDR_7 */ +#define RG_IEEE_ADDR_7 (0x2b) +/** Access parameters for sub-register IEEE_ADDR_7 in register @ref RG_IEEE_ADDR_7 */ +#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 +/** Offset for register XAH_CTRL */ +#define RG_XAH_CTRL_0 (0x2c) +/** Access parameters for sub-register MAX_FRAME_RETRIES in register @ref RG_XAH_CTRL_0 */ +#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 +/** Access parameters for sub-register MAX_CSMA_RETRIES in register @ref RG_XAH_CTRL_0 */ +#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 +#define SR_reserved_2c_3 0x2c, 0x01, 0 +/** Offset for register CSMA_SEED_0 */ +#define RG_CSMA_SEED_0 (0x2d) +/** Access parameters for sub-register CSMA_SEED_0 in register @ref RG_CSMA_SEED_0 */ +#define SR_CSMA_SEED_0 0x2d, 0xff, 0 +/** Offset for register CSMA_SEED_1 */ +#define RG_CSMA_SEED_1 (0x2e) +/** Offset for register CSMA_BE */ +#define RG_CSMA_BE 0x2f +/** Access parameters for sub-register MIN_BE in register @ref RG_CSMA_SEED_1 */ +#define SR_MIN_BE 0x2e, 0xc0, 6 +#define SR_reserved_2e_2 0x2e, 0x30, 4 +/** Access parameters for sub-register I_AM_COORD in register @ref RG_CSMA_SEED_1 */ +#define SR_I_AM_COORD 0x2e, 0x08, 3 +/** Access parameters for sub-register CSMA_SEED_1 in register @ref RG_CSMA_SEED_1 */ +#define SR_CSMA_SEED_1 0x2e, 0x07, 0 +#endif /* PHY230_REGISTERMAP_EXTERNAL_H */ diff --git a/cpu/avr/radio/rf230/frame.c b/cpu/avr/radio/rf230/frame.c new file mode 100644 index 000000000..fd41269c9 --- /dev/null +++ b/cpu/avr/radio/rf230/frame.c @@ -0,0 +1,337 @@ +/* + * + * 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.1 2008/10/14 09:43:40 adamdunkels 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 +#include +#else /* IAR */ +#include +#endif + +#include +#include +#include +#include +#include "at86rf230_registermap.h" +#include "radio.h" +#include "frame.h" +//#include "mac_event.h" +#include "mac.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; + } + + + if (fcf->frameType == ACKFRAME) + return; /* Don't bother with ACK frames */ + + pf->fcf = (fcf_t *)p; + pf->seqNum = p+2; + p += 3; /* Skip first three bytes */ + /* 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; + } + /* 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); +} + +/** \} */ +/** \} */ diff --git a/cpu/avr/radio/rf230/frame.h b/cpu/avr/radio/rf230/frame.h new file mode 100644 index 000000000..cc3b6347a --- /dev/null +++ b/cpu/avr/radio/rf230/frame.h @@ -0,0 +1,226 @@ +/* + * 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. +*/ + +/** + * \addtogroup frame + * @{ + */ +/** + * \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. + * + * $Id: frame.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ +*/ + + + +/* Includes */ +#ifndef FRAME_UTILS_H +#define FRAME_UTILS_H + +#include "hal.h" + +/* Macros & Defines */ + + +/** + * \brief Defines the bitfields of the frame control field (FCF). + */ +typedef union{ + /** \brief Structure of bitfields for the FCF */ + struct{ + uint8_t frameType : 3; /**< Frame type field, see 802.15.4 */ + bool securityEnabled : 1; /**< True if security is used in this frame */ + bool framePending : 1; /**< True if sender has more data to send */ + bool ackRequired : 1; /**< Is an ack frame required? */ + bool panIdCompression : 1; /**< Is this a compressed header? */ + uint8_t reserved : 3; /**< Unused bits */ + uint8_t destAddrMode : 2; /**< Destination address mode, see 802.15.4 */ + uint8_t frameVersion : 2; /**< 802.15.4 frame version */ + uint8_t srcAddrMode : 2; /**< Source address mode, see 802.15.4 */ + }; + uint16_t word_val; /**< A word-wide value for the entire FCF */ +}fcf_t; + +/** + * \brief Structure that contains the lengths of the various addressing and security fields + * in the 802.15.4 header. This structure is used in \ref frame_tx_create() + */ +typedef struct{ + uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */ + uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */ + uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */ + uint8_t src_addr_len; /**< Length (in bytes) of source address field */ + uint8_t aux_sec_len; /**< Length (in bytes) of aux security header field */ +} field_length_t; + +/** \brief 802.15.4 security control bitfield. See section 7.6.2.2.1 in 802.15.4 specification */ +typedef struct{ + uint8_t security_level : 3; /**< security level */ + uint8_t key_id_mode : 2; /**< Key identifier mode */ + uint8_t reserved : 3; /**< Reserved bits */ +} scf_t; + +/** \brief 802.15.4 Aux security header */ +typedef struct{ + scf_t security_control; /**< Security control bitfield */ + uint32_t frame_counter; /**< Frame counter, used for security */ + uint8_t key[9]; /**< The key itself, or an index to the key */ +} aux_hdr_t; + +/** + * @brief Some constants for frame length calculations. + * The IEEE 802.15.4 frame has a number of constant/fixed fields that + * can be counted to make frame construction and max payload + * calculations easier. + * + * These include: + * 1. FCF - 2 bytes - Fixed + * 2. Sequence number - 1 byte - Fixed + * 3. Addressing fields - 4 - 20 bytes - Variable + * 4. Aux security header - 0 - 14 bytes - Variable + * 5. CRC - 2 bytes - Fixed +*/ +#define FIXEDFRAMEOVERHEAD (5) + +/** \brief A union of short and long address types. Although a node can have + * both long and short addresses a frame will contain + * only one of these. Therefore, a union is appropriate here. */ +typedef union{ + uint16_t shortAddr; /**< Short address, two bytes */ + uint64_t longAddr; /**< Long address, eight bytes */ +}ADDR_SIZE_SPEC_t; + +/** \brief Structure containing a PAN ID and an address */ +typedef struct{ + uint16_t panId; /**< PAN ID */ + ADDR_SIZE_SPEC_t addrSpec; /**< A short or long address */ +}PAN_ID_ADDR_SPEC_t; + +/** \brief Structure containing both source and destination addresses */ +typedef struct{ + PAN_ID_ADDR_SPEC_t destAddrFields; /**< Destination address */ + PAN_ID_ADDR_SPEC_t srcAddrFields; /**< Source address */ +}ADDR_FIELD_SPEC_t; + +/** \brief Union of both short and long addresses */ +typedef union{ + uint16_t addr16; /**< Short address */ + uint64_t addr64; /**< Long address */ +} addr_t; + +/** \brief Strucure used to return that status of the frame create process. + * See frame_tx_create() function.*/ +typedef struct{ + uint8_t *frame; /**< Pointer to created frame */ + uint8_t length; /**< Length (in bytes) of created frame */ +} frame_result_t; + +/** \brief Parameters used by the frame_tx_create() function. These + * parameters are used in the 802.15.4 frame header. See the 802.15.4 + * specification for details. + */ +typedef struct{ + fcf_t fcf; /**< Frame control field */ + uint8_t seq; /**< Sequence number */ + uint16_t dest_pid; /**< Destination PAN ID */ + addr_t dest_addr; /**< Destination address */ + uint16_t src_pid; /**< Source PAN ID */ + addr_t src_addr; /**< Source address */ + aux_hdr_t aux_hdr; /**< Aux security header */ + uint8_t *payload; /**< Pointer to 802.15.4 frame payload */ + uint8_t payload_len; /**< Length of payload field */ +} frame_create_params_t; + + + +/** + * \brief 802.15.4 frame structure, including the LQI, RSSI, and frame time + * fields. +*/ +/* typedef struct{ */ +/* fcf_t fcf; /\**< The FCF of the frame. *\/ */ +/* uint8_t seqNum; /\**< The sequence number of the frame. *\/ */ +/* uint16_t dest_pid; /\**< Destination PAN ID. *\/ */ +/* addr_t dest_addr; /\**< Destination address. *\/ */ +/* uint16_t src_pid; /\**< PAN ID *\/ */ +/* addr_t src_addr; /\**< Source address *\/ */ +/* uint8_t aux_sec_hdr[14]; /\**< 802.15.4 Aux security header *\/ */ +/* uint8_t payload_length; /\**< Length of payload section of frame *\/ */ +/* uint8_t payload[118]; /\**< Frame payload *\/ */ +/* uint8_t lqi; /\**< Link quality indication value *\/ */ +/* uint8_t rssi; /\**< Received signal strength indication value *\/ */ +/* uint32_t time; /\**< Time stamp of received frame *\/ */ +/* bool fcs:1; /\**< True if checksum has passed *\/ */ +/* bool in_use:1; /\**< Is this frame struct being used? *\/ */ +/* }FRAME_t; */ + +typedef struct{ + fcf_t * fcf; /**< The FCF of the frame. */ + uint8_t * seqNum; /**< The sequence number of the frame. */ + uint16_t * dest_pid; /**< Destination PAN ID. */ + addr_t * dest_addr; /**< Destination address. */ + uint16_t * src_pid; /**< PAN ID */ + addr_t * src_addr; /**< Source address */ + uint8_t * aux_sec_hdr; /**< 802.15.4 Aux security header */ + uint8_t * payload; /**< Frame payload */ + uint8_t payload_length; /**< Length of payload section of frame */ + uint8_t lqi; /**< Link quality indication value */ + uint8_t rssi; /**< Received signal strength indication value */ + uint32_t time; /**< Time stamp of received frame */ + bool fcs:1; /**< True if checksum has passed */ + bool in_use:1; /**< Is this frame struct being used? */ +} parsed_frame_t; + +/* Globals */ + +//extern FRAME_t rx_frame; + +/* Protoypes */ + +void frame_tx_create(frame_create_params_t *p,frame_result_t *frame_result); +void frame_rx_callback(uint16_t data); +void rx_frame_parse(hal_rx_frame_t *rx_frame, parsed_frame_t *pf); + +/** @} */ +#endif /* FRAME_UTILS_H */ diff --git a/cpu/avr/radio/rf230/hal.c b/cpu/avr/radio/rf230/hal.c new file mode 100644 index 000000000..559b0cba9 --- /dev/null +++ b/cpu/avr/radio/rf230/hal.c @@ -0,0 +1,729 @@ +/* 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: hal.c,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ +*/ + +/** + * \addtogroup wireless + * @{ +*/ + +/** + * \defgroup hal RF230 hardware level drivers + * @{ + */ + +/** + * \file + * This file contains low-level radio driver code. + */ + + + +/*============================ INCLUDE =======================================*/ +#include + +#include "hal.h" +#include "at86rf230_registermap.h" +/*============================ MACROS ========================================*/ + +/* + * Macros defined for the radio transceiver's access modes. + * + * These functions are implemented as macros since they are used very often. + */ +#define HAL_DUMMY_READ (0x00) /**< Dummy value for the SPI. */ + +#define HAL_TRX_CMD_RW (0xC0) /**< Register Write (short mode). */ +#define HAL_TRX_CMD_RR (0x80) /**< Register Read (short mode). */ +#define HAL_TRX_CMD_FW (0x60) /**< Frame Transmit Mode (long mode). */ +#define HAL_TRX_CMD_FR (0x20) /**< Frame Receive Mode (long mode). */ +#define HAL_TRX_CMD_SW (0x40) /**< SRAM Write. */ +#define HAL_TRX_CMD_SR (0x00) /**< SRAM Read. */ +#define HAL_TRX_CMD_RADDRM (0x7F) /**< Register Address Mask. */ + +#define HAL_CALCULATED_CRC_OK (0) /**< CRC calculated over the frame including the CRC field should be 0. */ +/*============================ TYPDEFS =======================================*/ +/*============================ VARIABLES =====================================*/ +/** \brief This is a file internal variable that contains the 16 MSB of the + * system time. + * + * The system time (32-bit) is the current time in microseconds. For the + * AVR microcontroller implementation this is solved by using a 16-bit + * timer (Timer1) with a clock frequency of 1MHz. The hal_system_time is + * incremented when the 16-bit timer overflows, representing the 16 MSB. + * The timer value it self (TCNT1) is then the 16 LSB. + * + * \see hal_get_system_time + */ +static uint16_t hal_system_time = 0; + +/*Flag section.*/ +static uint8_t volatile hal_bat_low_flag; /**< BAT_LOW flag. */ +static uint8_t volatile hal_pll_lock_flag; /**< PLL_LOCK flag. */ + +/*Callbacks.*/ + +/** \brief This function is called when a rx_start interrupt is signaled. + * + * If this function pointer is set to something else than NULL, it will + * be called when a RX_START event is signaled. The function takes two + * parameters: timestamp in IEEE 802.15.4 symbols (16 us resolution) and + * frame length. The event handler will be called in the interrupt domain, + * so the function must be kept short and not be blocking! Otherwise the + * system performance will be greatly degraded. + * + * \see hal_set_rx_start_event_handler + */ +static hal_rx_start_isr_event_handler_t rx_start_callback; + +/** \brief This function is called when a trx_end interrupt is signaled. + * + * If this function pointer is set to something else than NULL, it will + * be called when a TRX_END event is signaled. The function takes one + * parameter: timestamp in IEEE 802.15.4 symbols (16 us resolution). + * The event handler will be called in the interrupt domain, + * so the function must not block! + * + * \see hal_set_trx_end_event_handler + */ +static hal_trx_end_isr_event_handler_t trx_end_callback; +/*============================ PROTOTYPES ====================================*/ +/*============================ IMPLEMENTATION ================================*/ + +/** \brief This function initializes the Hardware Abstraction Layer. + */ +void +hal_init(void) +{ + /*Reset variables used in file.*/ + hal_system_time = 0; + hal_reset_flags(); + + /*IO Specific Initialization.*/ + DDR_SLP_TR |= (1 << SLP_TR); /* Enable SLP_TR as output. */ + DDR_RST |= (1 << RST); /* Enable RST as output. */ + + /*SPI Specific Initialization.*/ + /* Set SS, CLK and MOSI as output. */ + HAL_DDR_SPI |= (1 << HAL_DD_SS) | (1 << HAL_DD_SCK) | (1 << HAL_DD_MOSI); + HAL_PORT_SPI |= (1 << HAL_DD_SS) | (1 << HAL_DD_SCK); /* Set SS and CLK high */ + /* Run SPI at max speed */ + SPCR = (1 << SPE) | (1 << MSTR); /* Enable SPI module and master operation. */ + SPSR = (1 << SPI2X); /* Enable doubled SPI speed in master mode. */ + + /*TIMER1 Specific Initialization.*/ + TCCR1B = HAL_TCCR1B_CONFIG; /* Set clock prescaler */ + TIFR1 |= (1 << ICF1); /* Clear Input Capture Flag. */ + HAL_ENABLE_OVERFLOW_INTERRUPT(); /* Enable Timer1 overflow interrupt. */ + hal_enable_trx_interrupt(); /* Enable interrupts from the radio transceiver. */ +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function reset the interrupt flags and interrupt event handlers + * (Callbacks) to their default value. + */ +void +hal_reset_flags(void) +{ + AVR_ENTER_CRITICAL_REGION(); + + /* Reset Flags. */ + hal_bat_low_flag = 0; + hal_pll_lock_flag = 0; + + /* Reset Associated Event Handlers. */ + rx_start_callback = NULL; + trx_end_callback = NULL; + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current value of the BAT_LOW flag. + * + * The BAT_LOW flag is incremented each time a BAT_LOW event is signaled from the + * radio transceiver. This way it is possible for the end user to poll the flag + * for new event occurances. + */ +uint8_t +hal_get_bat_low_flag(void) +{ + return hal_bat_low_flag; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function clears the BAT_LOW flag. + */ +void +hal_clear_bat_low_flag(void) +{ + AVR_ENTER_CRITICAL_REGION(); + hal_bat_low_flag = 0; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function is used to set new TRX_END event handler, overriding + * old handler reference. + */ +hal_trx_end_isr_event_handler_t +hal_get_trx_end_event_handler(void) +{ + return trx_end_callback; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function is used to set new TRX_END event handler, overriding + * old handler reference. + */ +void +hal_set_trx_end_event_handler(hal_trx_end_isr_event_handler_t trx_end_callback_handle) +{ + AVR_ENTER_CRITICAL_REGION(); + trx_end_callback = trx_end_callback_handle; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief Remove event handler reference. + */ +void +hal_clear_trx_end_event_handler(void) +{ + AVR_ENTER_CRITICAL_REGION(); + trx_end_callback = NULL; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the active RX_START event handler + * + * \return Current RX_START event handler registered. + */ +hal_rx_start_isr_event_handler_t +hal_get_rx_start_event_handler(void) +{ + return rx_start_callback; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function is used to set new RX_START event handler, overriding + * old handler reference. + */ +void +hal_set_rx_start_event_handler(hal_rx_start_isr_event_handler_t rx_start_callback_handle) +{ + AVR_ENTER_CRITICAL_REGION(); + rx_start_callback = rx_start_callback_handle; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief Remove event handler reference. + */ +void +hal_clear_rx_start_event_handler(void) +{ + AVR_ENTER_CRITICAL_REGION(); + rx_start_callback = NULL; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current value of the PLL_LOCK flag. + * + * The PLL_LOCK flag is incremented each time a PLL_LOCK event is signaled from the + * radio transceiver. This way it is possible for the end user to poll the flag + * for new event occurances. + */ +uint8_t +hal_get_pll_lock_flag(void) +{ + return hal_pll_lock_flag; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function clears the PLL_LOCK flag. + */ +void +hal_clear_pll_lock_flag(void) +{ + AVR_ENTER_CRITICAL_REGION(); + hal_pll_lock_flag = 0; + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function reads data from one of the radio transceiver's registers. + * + * \param address Register address to read from. See datasheet for register + * map. + * + * \see Look at the at86rf230_registermap.h file for register address definitions. + * + * \returns The actual value of the read register. + */ +uint8_t +hal_register_read(uint8_t address) +{ + /* Add the register read command to the register address. */ + address &= HAL_TRX_CMD_RADDRM; + address |= HAL_TRX_CMD_RR; + + uint8_t register_value = 0; + + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); /* Start the SPI transaction by pulling the Slave Select low. */ + + /*Send Register address and read register content.*/ + SPDR = address; + while ((SPSR & (1 << SPIF)) == 0) {;} + register_value = SPDR; + + SPDR = register_value; + while ((SPSR & (1 << SPIF)) == 0) {;} + register_value = SPDR; + + HAL_SS_HIGH(); /* End the transaction by pulling the Slave Select High. */ + + AVR_LEAVE_CRITICAL_REGION(); + + return register_value; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function writes a new value to one of the radio transceiver's + * registers. + * + * \see Look at the at86rf230_registermap.h file for register address definitions. + * + * \param address Address of register to write. + * \param value Value to write. + */ +void +hal_register_write(uint8_t address, uint8_t value) +{ + /* Add the Register Write command to the address. */ + address = HAL_TRX_CMD_RW | (HAL_TRX_CMD_RADDRM & address); + + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); /* Start the SPI transaction by pulling the Slave Select low. */ + + /*Send Register address and write register content.*/ + SPDR = address; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t dummy_read = SPDR; + + SPDR = value; + while ((SPSR & (1 << SPIF)) == 0) {;} + dummy_read = SPDR; + + HAL_SS_HIGH(); /* End the transaction by pulling the Slave Slect High. */ + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function reads the value of a specific subregister. + * + * \see Look at the at86rf230_registermap.h file for register and subregister + * definitions. + * + * \param address Main register's address. + * \param mask Bit mask of the subregister. + * \param position Bit position of the subregister + * \retval Value of the read subregister. + */ +uint8_t +hal_subregister_read(uint8_t address, uint8_t mask, uint8_t position) +{ + /* Read current register value and mask out subregister. */ + uint8_t register_value = hal_register_read(address); + register_value &= mask; + register_value >>= position; /* Align subregister value. */ + + return register_value; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function writes a new value to one of the radio transceiver's + * subregisters. + * + * \see Look at the at86rf230_registermap.h file for register and subregister + * definitions. + * + * \param address Main register's address. + * \param mask Bit mask of the subregister. + * \param position Bit position of the subregister + * \param value Value to write into the subregister. + */ +void +hal_subregister_write(uint8_t address, uint8_t mask, uint8_t position, + uint8_t value) +{ + /* Read current register value and mask area outside the subregister. */ + uint8_t register_value = hal_register_read(address); + register_value &= ~mask; + + /* Start preparing the new subregister value. shift in place and mask. */ + value <<= position; + value &= mask; + + value |= register_value; /* Set the new subregister value. */ + + /* Write the modified register value. */ + hal_register_write(address, value); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will upload a frame from the radio transceiver's frame + * buffer. + * + * If the frame currently available in the radio transceiver's frame buffer + * is out of the defined bounds. Then the frame length, lqi value and crc + * be set to zero. This is done to indicate an error. + * + * \param rx_frame Pointer to the data structure where the frame is stored. + * \param rx_callback Pointer to callback function for receiving one byte at a time. + */ +void +hal_frame_read(hal_rx_frame_t *rx_frame, rx_callback_t rx_callback) +{ + uint8_t *rx_data=0; + + /* check that we have either valid frame pointer or callback pointer */ + if (!rx_frame && !rx_callback) + return; + + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); + + /*Send frame read command.*/ + SPDR = HAL_TRX_CMD_FR; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t frame_length = SPDR; + + /*Read frame length.*/ + SPDR = frame_length; + while ((SPSR & (1 << SPIF)) == 0) {;} + frame_length = SPDR; + + /*Check for correct frame length.*/ + if ((frame_length >= HAL_MIN_FRAME_LENGTH) && (frame_length <= HAL_MAX_FRAME_LENGTH)){ + uint16_t crc = 0; + if (rx_frame){ + rx_data = (rx_frame->data); + rx_frame->length = frame_length; /* Store frame length. */ + } else { + rx_callback(frame_length); + } + /*Upload frame buffer to data pointer. Calculate CRC.*/ + SPDR = frame_length; + while ((SPSR & (1 << SPIF)) == 0) {;} + + do{ + uint8_t tempData = SPDR; + SPDR = 0; /* dummy write */ + + if (rx_frame){ + *rx_data++ = tempData; + } else { + rx_callback(tempData); + } + + crc = _crc_ccitt_update(crc, tempData); + + while ((SPSR & (1 << SPIF)) == 0) {;} + + } while (--frame_length > 0); + + /*Read LQI value for this frame.*/ + if (rx_frame){ + rx_frame->lqi = SPDR; + } else { + rx_callback(SPDR); + } + + HAL_SS_HIGH(); + + /*Check calculated crc, and set crc field in hal_rx_frame_t accordingly.*/ + if (rx_frame){ + rx_frame->crc = (crc == HAL_CALCULATED_CRC_OK); + } else { + rx_callback(crc != HAL_CALCULATED_CRC_OK); + } + } else { + HAL_SS_HIGH(); + + if (rx_frame){ + rx_frame->length = 0; + rx_frame->lqi = 0; + rx_frame->crc = false; + } + } + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will download a frame to the radio transceiver's frame + * buffer. + * + * \param write_buffer Pointer to data that is to be written to frame buffer. + * \param length Length of data. The maximum length is 127 bytes. + */ +void +hal_frame_write(uint8_t *write_buffer, uint8_t length) +{ + length &= HAL_TRX_CMD_RADDRM; /* Truncate length to maximum frame length. */ + + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); /* Initiate the SPI transaction. */ + + /*SEND FRAME WRITE COMMAND AND FRAME LENGTH.*/ + SPDR = HAL_TRX_CMD_FW; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t dummy_read = SPDR; + + SPDR = length; + while ((SPSR & (1 << SPIF)) == 0) {;} + dummy_read = SPDR; + + /* Download to the Frame Buffer. */ + do{ + SPDR = *write_buffer++; + --length; + + while ((SPSR & (1 << SPIF)) == 0) {;} + + dummy_read = SPDR; + } while (length > 0); + + HAL_SS_HIGH(); /* Terminate SPI transaction. */ + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief Read SRAM + * + * This function reads from the SRAM of the radio transceiver. + * + * \param address Address in the TRX's SRAM where the read burst should start + * \param length Length of the read burst + * \param data Pointer to buffer where data is stored. + */ +void +hal_sram_read(uint8_t address, uint8_t length, uint8_t *data) +{ + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); /* Initiate the SPI transaction. */ + + /*Send SRAM read command.*/ + SPDR = HAL_TRX_CMD_SR; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t dummy_read = SPDR; + + /*Send address where to start reading.*/ + SPDR = address; + while ((SPSR & (1 << SPIF)) == 0) {;} + + dummy_read = SPDR; + + /*Upload the chosen memory area.*/ + do{ + SPDR = HAL_DUMMY_READ; + while ((SPSR & (1 << SPIF)) == 0) {;} + *data++ = SPDR; + } while (--length > 0); + + HAL_SS_HIGH(); + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief Write SRAM + * + * This function writes into the SRAM of the radio transceiver. + * + * \param address Address in the TRX's SRAM where the write burst should start + * \param length Length of the write burst + * \param data Pointer to an array of bytes that should be written + */ +void +hal_sram_write(uint8_t address, uint8_t length, uint8_t *data) +{ + AVR_ENTER_CRITICAL_REGION(); + + HAL_SS_LOW(); + + /*Send SRAM write command.*/ + SPDR = HAL_TRX_CMD_SW; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t dummy_read = SPDR; + + /*Send address where to start writing to.*/ + SPDR = address; + while ((SPSR & (1 << SPIF)) == 0) {;} + dummy_read = SPDR; + + /*Upload the chosen memory area.*/ + do{ + SPDR = *data++; + while ((SPSR & (1 << SPIF)) == 0) {;} + dummy_read = SPDR; + } while (--length > 0); + + HAL_SS_HIGH(); + + AVR_LEAVE_CRITICAL_REGION(); +} + +/*----------------------------------------------------------------------------*/ +/* This #if compile switch is used to provide a "standard" function body for the */ +/* doxygen documentation. */ +#if defined(DOXYGEN) +/** \brief ISR for the radio IRQ line, triggered by the input capture. + * This is the interrupt service routine for timer1.ICIE1 input capture. + * It is triggered of a rising edge on the radio transceivers IRQ line. + */ +void RADIO_VECT(void); +#else /* !DOXYGEN */ +ISR(RADIO_VECT) +{ + /*The following code reads the current system time. This is done by first + reading the hal_system_time and then adding the 16 LSB directly from the + TCNT1 register. + */ + uint32_t isr_timestamp = hal_system_time; + isr_timestamp <<= 16; + isr_timestamp |= TCNT1; + + /*Read Interrupt source.*/ + HAL_SS_LOW(); + + /*Send Register address and read register content.*/ + SPDR = RG_IRQ_STATUS | HAL_TRX_CMD_RR; + + /* This is the second part of the convertion of system time to a 16 us time + base. The division is moved here so we can spend less time waiting for SPI + data. + */ + isr_timestamp /= HAL_US_PER_SYMBOL; /* Divide so that we get time in 16us resolution. */ + isr_timestamp &= HAL_SYMBOL_MASK; + + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t interrupt_source = SPDR; /* The interrupt variable is used as a dummy read. */ + + SPDR = interrupt_source; + while ((SPSR & (1 << SPIF)) == 0) {;} + interrupt_source = SPDR; /* The interrupt source is read. */ + + HAL_SS_HIGH(); + + /*Handle the incomming interrupt. Prioritized.*/ + if ((interrupt_source & HAL_RX_START_MASK)){ + if(rx_start_callback != NULL){ + /* Read Frame length and call rx_start callback. */ + HAL_SS_LOW(); + + SPDR = HAL_TRX_CMD_FR; + while ((SPSR & (1 << SPIF)) == 0) {;} + uint8_t frame_length = SPDR; + + SPDR = frame_length; /* frame_length used for dummy data */ + while ((SPSR & (1 << SPIF)) == 0) {;} + frame_length = SPDR; + + HAL_SS_HIGH(); + + rx_start_callback(isr_timestamp, frame_length); + } + } else if (interrupt_source & HAL_TRX_END_MASK){ + if(trx_end_callback != NULL){ + trx_end_callback(isr_timestamp); + } + } else if (interrupt_source & HAL_TRX_UR_MASK){ + ; + } else if (interrupt_source & HAL_PLL_UNLOCK_MASK){ + ; + } else if (interrupt_source & HAL_PLL_LOCK_MASK){ + hal_pll_lock_flag++; + ; + } else if (interrupt_source & HAL_BAT_LOW_MASK){ + /* Disable BAT_LOW interrupt to prevent endless interrupts. The interrupt */ + /* will continously be asserted while the supply voltage is less than the */ + /* user-defined voltage threshold. */ + uint8_t trx_isr_mask = hal_register_read(RG_IRQ_MASK); + trx_isr_mask &= ~HAL_BAT_LOW_MASK; + hal_register_write(RG_IRQ_MASK, trx_isr_mask); + hal_bat_low_flag++; /* Increment BAT_LOW flag. */ + } else { + ; + } +} +# endif /* defined(DOXYGEN) */ + +/*----------------------------------------------------------------------------*/ +/* This #if compile switch is used to provide a "standard" function body for the */ +/* doxygen documentation. */ +#if defined(DOXYGEN) +/** \brief Timer Overflow ISR + * This is the interrupt service routine for timer1 overflow. + */ +void TIMER1_OVF_vect(void); +#else /* !DOXYGEN */ +ISR(TIMER1_OVF_vect) +{ + hal_system_time++; +} +#endif + +/** @} */ +/** @} */ + +/*EOF*/ diff --git a/cpu/avr/radio/rf230/hal.h b/cpu/avr/radio/rf230/hal.h new file mode 100644 index 000000000..7fdfc0358 --- /dev/null +++ b/cpu/avr/radio/rf230/hal.h @@ -0,0 +1,321 @@ +/* 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. + */ + +/** + * \addtogroup hal + * @{ + */ + +/** + * \file + * \brief This file contains low-level radio driver code. + * + * $Id: hal.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ +*/ + +#ifndef HAL_AVR_H +#define HAL_AVR_H +/*============================ INCLUDE =======================================*/ +#include +#include +#include +#include +#include +#include "contiki-conf.h" +/*============================ MACROS ========================================*/ + +// TEST CODE +#define TRIG1 DDRB |= 0x04, PINB |= 0x04 +#define TRIG2 DDRD |= 0x80, PIND |= 0x80 + +/** \name This is the list of pin configurations needed for a given platform. + * \brief Change these values to port to other platforms. + * \{ + */ +/* Define all possible revisions here */ +#define RAVEN_D 0 +#define RAVENUSB_C 1 + + +#if RAVEN_REVISION == RAVEN_D + +/* 1284 raven */ +# define SSPORT B +# define SSPIN (0x04) +# define SPIPORT B +# define MOSIPIN (0x05) +# define MISOPIN (0x06) +# define SCKPIN (0x07) +# define RSTPORT B +# define RSTPIN (0x01) +# define IRQPORT D +# define IRQPIN (0x06) +# define SLPTRPORT B +# define SLPTRPIN (0x03) +# define TXCWPORT B +# define TXCWPIN (0x00) +# define USART 1 +# define USARTVECT USART1_RX_vect +# define TICKTIMER 3 +# define HAS_CW_MODE +# define HAS_SPARE_TIMER + +#elif RAVEN_REVISION == RAVENUSB_C + +/* 1287USB raven */ +# define SSPORT B +# define SSPIN (0x00) +# define SPIPORT B +# define MOSIPIN (0x02) +# define MISOPIN (0x03) +# define SCKPIN (0x01) +# define RSTPORT B +# define RSTPIN (0x05) +# define IRQPORT D +# define IRQPIN (0x04) +# define SLPTRPORT B +# define SLPTRPIN (0x04) +# define TXCWPORT B +# define TXCWPIN (0x07) +# define USART 1 +# define USARTVECT USART1_RX_vect +# define TICKTIMER 3 +# define HAS_CW_MODE +# define HAS_SPARE_TIMER + +#else + +#error "RAVEN platform undefined in hal.h" + +#endif + +/** \} */ + +/** + * \name Macros used to generate read register names from platform-specific definitions of ports. + * \brief The various CAT macros (DDR, PORT, and PIN) are used to + * assign port/pin/DDR names to various macro variables. The + * variables are assigned based on the specific connections made in + * the hardware. For example TCCR(TICKTIMER,A) can be used in place of TCCR0A + * if TICKTIMER is defined as 0. + * \{ + */ +#define CAT(x, y) x##y +#define CAT2(x, y, z) x##y##z +#define DDR(x) CAT(DDR, x) +#define PORT(x) CAT(PORT, x) +#define PIN(x) CAT(PIN, x) +#define UCSR(num, let) CAT2(UCSR,num,let) +#define RXEN(x) CAT(RXEN,x) +#define TXEN(x) CAT(TXEN,x) +#define TXC(x) CAT(TXC,x) +#define RXC(x) CAT(RXC,x) +#define RXCIE(x) CAT(RXCIE,x) +#define UCSZ(x,y) CAT2(UCSZ,x,y) +#define UBRR(x,y) CAT2(UBRR,x,y) +#define UDRE(x) CAT(UDRE,x) +#define UDRIE(x) CAT(UDRIE,x) +#define UDR(x) CAT(UDR,x) +#define TCNT(x) CAT(TCNT,x) +#define TIMSK(x) CAT(TIMSK,x) +#define TCCR(x,y) CAT2(TCCR,x,y) +#define COM(x,y) CAT2(COM,x,y) +#define OCR(x,y) CAT2(OCR,x,y) +#define CS(x,y) CAT2(CS,x,y) +#define WGM(x,y) CAT2(WGM,x,y) +#define OCIE(x,y) CAT2(OCIE,x,y) +#define COMPVECT(x) CAT2(TIMER,x,_COMPA_vect) +#define UDREVECT(x) CAT2(USART,x,_UDRE_vect) +#define RXVECT(x) CAT2(USART,x,_RX_vect) +/** \} */ + +/** + * \name Pin macros + * \brief These macros convert the platform-specific pin defines into names and functions + * that the source code can directly use. + * \{ + */ +#define SLP_TR SLPTRPIN /**< Pin number that corresponds to the SLP_TR pin. */ +#define DDR_SLP_TR DDR( SLPTRPORT ) /**< Data Direction Register that corresponds to the port where SLP_TR is connected. */ +#define PORT_SLP_TR PORT( SLPTRPORT ) /**< Port (Write Access) where SLP_TR is connected. */ +#define PIN_SLP_TR PIN( SLPTRPORT ) /**< Pin (Read Access) where SLP_TR is connected. */ +#define hal_set_slptr_high( ) ( PORT_SLP_TR |= ( 1 << SLP_TR ) ) /**< This macro pulls the SLP_TR pin high. */ +#define hal_set_slptr_low( ) ( PORT_SLP_TR &= ~( 1 << SLP_TR ) ) /**< This macro pulls the SLP_TR pin low. */ +#define hal_get_slptr( ) ( ( PIN_SLP_TR & ( 1 << SLP_TR ) ) >> SLP_TR ) /**< Read current state of the SLP_TR pin (High/Low). */ +#define RST RSTPIN /**< Pin number that corresponds to the RST pin. */ +#define DDR_RST DDR( RSTPORT ) /**< Data Direction Register that corresponds to the port where RST is */ +#define PORT_RST PORT( RSTPORT ) /**< Port (Write Access) where RST is connected. */ +#define PIN_RST PIN( RSTPORT ) /**< Pin (Read Access) where RST is connected. */ +#define hal_set_rst_high( ) ( PORT_RST |= ( 1 << RST ) ) /**< This macro pulls the RST pin high. */ +#define hal_set_rst_low( ) ( PORT_RST &= ~( 1 << RST ) ) /**< This macro pulls the RST pin low. */ +#define hal_get_rst( ) ( ( PIN_RST & ( 1 << RST ) ) >> RST ) /**< Read current state of the RST pin (High/Low). */ +#define HAL_SS_PIN SSPIN /**< The slave select pin. */ +#define HAL_PORT_SPI PORT( SPIPORT ) /**< The SPI module is located on PORTB. */ +#define HAL_DDR_SPI DDR( SPIPORT ) /**< Data Direction Register for PORTB. */ +#define HAL_DD_SS SSPIN /**< Data Direction bit for SS. */ +#define HAL_DD_SCK SCKPIN /**< Data Direction bit for SCK. */ +#define HAL_DD_MOSI MOSIPIN /**< Data Direction bit for MOSI. */ +#define HAL_DD_MISO MISOPIN /**< Data Direction bit for MISO. */ +/** \} */ + + +#define HAL_SS_HIGH( ) (HAL_PORT_SPI |= ( 1 << HAL_SS_PIN )) /**< MACRO for pulling SS high. */ +#define HAL_SS_LOW( ) (HAL_PORT_SPI &= ~( 1 << HAL_SS_PIN )) /**< MACRO for pulling SS low. */ + +/** \brief Macros defined for HAL_TIMER1. + * + * These macros are used to define the correct setupt of the AVR's Timer1, and + * to ensure that the hal_get_system_time function returns the system time in + * symbols (16 us ticks). + */ + +#if ( F_CPU == 16000000UL ) + #define HAL_TCCR1B_CONFIG ( ( 1 << ICES1 ) | ( 1 << CS12 ) ) + #define HAL_US_PER_SYMBOL ( 1 ) + #define HAL_SYMBOL_MASK ( 0xFFFFffff ) +#elif ( F_CPU == 8000000UL ) + #define HAL_TCCR1B_CONFIG ( ( 1 << ICES1 ) | ( 1 << CS11 ) | ( 1 << CS10 ) ) + #define HAL_US_PER_SYMBOL ( 2 ) + #define HAL_SYMBOL_MASK ( 0x7FFFffff ) +#elif ( F_CPU == 4000000UL ) + #define HAL_TCCR1B_CONFIG ( ( 1 << ICES1 ) | ( 1 << CS11 ) | ( 1 << CS10 ) ) + #define HAL_US_PER_SYMBOL ( 1 ) + #define HAL_SYMBOL_MASK ( 0xFFFFffff ) +#elif ( F_CPU == 1000000UL ) + #define HAL_TCCR1B_CONFIG ( ( 1 << ICES1 ) | ( 1 << CS11 ) ) + #define HAL_US_PER_SYMBOL ( 2 ) + #define HAL_SYMBOL_MASK ( 0x7FFFffff ) +#else + #error "Clock speed not supported." +#endif + + +#define RADIO_VECT TIMER1_CAPT_vect +#define HAL_ENABLE_RADIO_INTERRUPT( ) ( TIMSK1 |= ( 1 << ICIE1 ) ) +#define HAL_DISABLE_RADIO_INTERRUPT( ) ( TIMSK1 &= ~( 1 << ICIE1 ) ) + +#define HAL_ENABLE_OVERFLOW_INTERRUPT( ) ( TIMSK1 |= ( 1 << TOIE1 ) ) +#define HAL_DISABLE_OVERFLOW_INTERRUPT( ) ( TIMSK1 &= ~( 1 << TOIE1 ) ) + +/** This macro will protect the following code from interrupts.*/ +#define AVR_ENTER_CRITICAL_REGION( ) {uint8_t volatile saved_sreg = SREG; cli( ) + +/** This macro must always be used in conjunction with AVR_ENTER_CRITICAL_REGION + so that interrupts are enabled again.*/ +#define AVR_LEAVE_CRITICAL_REGION( ) SREG = saved_sreg;} + + +/** \brief Enable the interrupt from the radio transceiver. + */ +#define hal_enable_trx_interrupt( ) HAL_ENABLE_RADIO_INTERRUPT( ) + +/** \brief Disable the interrupt from the radio transceiver. + * + * \retval 0 if the pin is low, 1 if the pin is high. + */ +#define hal_disable_trx_interrupt( ) HAL_DISABLE_RADIO_INTERRUPT( ) +/*============================ TYPDEFS =======================================*/ +/*============================ PROTOTYPES ====================================*/ +/*============================ MACROS ========================================*/ +/** \name Macros for radio operation. + * \{ + */ +#define HAL_BAT_LOW_MASK ( 0x80 ) /**< Mask for the BAT_LOW interrupt. */ +#define HAL_TRX_UR_MASK ( 0x40 ) /**< Mask for the TRX_UR interrupt. */ +#define HAL_TRX_END_MASK ( 0x08 ) /**< Mask for the TRX_END interrupt. */ +#define HAL_RX_START_MASK ( 0x04 ) /**< Mask for the RX_START interrupt. */ +#define HAL_PLL_UNLOCK_MASK ( 0x02 ) /**< Mask for the PLL_UNLOCK interrupt. */ +#define HAL_PLL_LOCK_MASK ( 0x01 ) /**< Mask for the PLL_LOCK interrupt. */ + +#define HAL_MIN_FRAME_LENGTH ( 0x03 ) /**< A frame should be at least 3 bytes. */ +#define HAL_MAX_FRAME_LENGTH ( 0x7F ) /**< A frame should no more than 127 bytes. */ +/** \} */ +/*============================ TYPDEFS =======================================*/ +/** \struct hal_rx_frame_t + * \brief This struct defines the rx data container. + * + * \see hal_frame_read + */ +typedef struct{ + uint8_t length; /**< Length of frame. */ + uint8_t data[ HAL_MAX_FRAME_LENGTH ]; /**< Actual frame data. */ + uint8_t lqi; /**< LQI value for received frame. */ + bool crc; /**< Flag - did CRC pass for received frame? */ +} hal_rx_frame_t; + +/** RX_START event handler callback type. Is called with timestamp in IEEE 802.15.4 symbols and frame length. See hal_set_rx_start_event_handler(). */ +typedef void (*hal_rx_start_isr_event_handler_t)(uint32_t const isr_timestamp, uint8_t const frame_length); + +/** RRX_END event handler callback type. Is called with timestamp in IEEE 802.15.4 symbols and frame length. See hal_set_trx_end_event_handler(). */ +typedef void (*hal_trx_end_isr_event_handler_t)(uint32_t const isr_timestamp); + +typedef void (*rx_callback_t) (uint16_t data); + +/*============================ PROTOTYPES ====================================*/ +void hal_init( void ); + +void hal_reset_flags( void ); +uint8_t hal_get_bat_low_flag( void ); +void hal_clear_bat_low_flag( void ); + +hal_trx_end_isr_event_handler_t hal_get_trx_end_event_handler( void ); +void hal_set_trx_end_event_handler( hal_trx_end_isr_event_handler_t trx_end_callback_handle ); +void hal_clear_trx_end_event_handler( void ); + +hal_rx_start_isr_event_handler_t hal_get_rx_start_event_handler( void ); +void hal_set_rx_start_event_handler( hal_rx_start_isr_event_handler_t rx_start_callback_handle ); +void hal_clear_rx_start_event_handler( void ); + +uint8_t hal_get_pll_lock_flag( void ); +void hal_clear_pll_lock_flag( void ); + +uint8_t hal_register_read( uint8_t address ); +void hal_register_write( uint8_t address, uint8_t value ); +uint8_t hal_subregister_read( uint8_t address, uint8_t mask, uint8_t position ); +void hal_subregister_write( uint8_t address, uint8_t mask, uint8_t position, + uint8_t value ); +void hal_frame_read(hal_rx_frame_t *rx_frame, rx_callback_t rx_callback); +void hal_frame_write( uint8_t *write_buffer, uint8_t length ); +void hal_sram_read( uint8_t address, uint8_t length, uint8_t *data ); +void hal_sram_write( uint8_t address, uint8_t length, uint8_t *data ); + +#endif +/** @} */ +/*EOF*/ diff --git a/cpu/avr/radio/rf230/radio.c b/cpu/avr/radio/rf230/radio.c new file mode 100644 index 000000000..e4a5d4cfd --- /dev/null +++ b/cpu/avr/radio/rf230/radio.c @@ -0,0 +1,1373 @@ +/* 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: radio.c,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ +*/ + +/** + * \brief This module contains the radio driver code for the Atmel + * AT86RF230, '231, and '212 chips. + * + * \author Blake Leverett + * Mike Vidales + * Eric Gnoske + * +*/ + +/** \addtogroup wireless + * @{ + */ + +/** + * \defgroup radiorf230 RF230 interface + * @{ + */ +/** + * \file + * This file contains radio driver code. + * + */ + + + +/*============================ INCLUDE =======================================*/ +#include +#include +#include "radio.h" +#include "hal.h" +#include "process.h" +#include "sicslowmac.h" +#include "frame.h" + +/*============================ MACROS ========================================*/ +#define RADIO_CCA_DONE_MASK (1 << 7) /**< Mask used to check the CCA_DONE bit. */ +#define RADIO_CCA_IDLE_MASK (1 << 6) /**< Mask used to check the CCA_STATUS bit. */ + +#define RADIO_START_CCA (1) /**< Value in the CCA_REQUEST subregister that initiate a cca. */ + +#define RADIO_TRANSMISSION_SUCCESS (0) +#define RADIO_BUSY_CHANNEL (3) +#define RADIO_MIN_IEEE_FRAME_LENGTH (5) +/*============================ TYPEDEFS ======================================*/ + +/** \brief This enumeration defines the necessary timing information for the + * AT86RF230 radio transceiver. All times are in microseconds. + * + * These constants are extracted from the datasheet. + */ +typedef enum{ + TIME_TO_ENTER_P_ON = 510, /**< Transition time from VCC is applied to P_ON. */ + TIME_P_ON_TO_TRX_OFF = 510, /**< Transition time from P_ON to TRX_OFF. */ + TIME_SLEEP_TO_TRX_OFF = 880, /**< Transition time from SLEEP to TRX_OFF. */ + TIME_RESET = 6, /**< Time to hold the RST pin low during reset */ + TIME_ED_MEASUREMENT = 140, /**< Time it takes to do a ED measurement. */ + TIME_CCA = 140, /**< Time it takes to do a CCA. */ + TIME_PLL_LOCK = 150, /**< Maximum time it should take for the PLL to lock. */ + TIME_FTN_TUNING = 25, /**< Maximum time it should take to do the filter tuning. */ + TIME_NOCLK_TO_WAKE = 6, /**< Transition time from *_NOCLK to being awake. */ + TIME_CMD_FORCE_TRX_OFF = 1, /**< Time it takes to execute the FORCE_TRX_OFF command. */ + TIME_TRX_OFF_TO_PLL_ACTIVE = 180, /**< Transition time from TRX_OFF to: RX_ON, PLL_ON, TX_ARET_ON and RX_AACK_ON. */ + TIME_STATE_TRANSITION_PLL_ACTIVE = 1, /**< Transition time from PLL active state to another. */ +}radio_trx_timing_t; + +/*============================ VARIABLES =====================================*/ +static hal_rx_start_isr_event_handler_t user_rx_event; +static hal_trx_end_isr_event_handler_t user_trx_end_event; +static radio_rx_callback rx_frame_callback; +static uint8_t rssi_val; +static uint8_t rx_mode; +uint8_t rxMode = RX_AACK_ON; +static hal_rx_frame_t rx_frame; +parsed_frame_t parsed_frame; + + +/*============================ PROTOTYPES ====================================*/ +bool radio_is_sleeping(void); +static void radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length); +static void radio_trx_end_event(uint32_t const isr_timestamp); + +/** \brief Initialize the Transceiver Access Toolbox and lower layers. + * + * If the initialization is successful the radio transceiver will be in + * TRX_OFF state. + * + * \note This function must be called prior to any of the other functions in + * this file! Can be called from any transceiver state. + * + * \param cal_rc_osc If true, the radio's accurate clock is used to calibrate the + * CPU's internal RC oscillator. + * + * \param rx_event Optional pointer to a user-defined function to be called on an + * RX_START interrupt. Use NULL for no handler. + * + * \param trx_end_event Optional pointer to a user-defined function to be called on an + * TRX_END interrupt. Use NULL for no handler. + * + * \param rx_callback Optional pointer to a user-defined function that receives + * a frame from the radio one byte at a time. If the index parameter to + * this callback is 0xff, then the function should reset its state and prepare + * for a frame from the radio, with one call per byte. + * + * \retval RADIO_SUCCESS The radio transceiver was successfully initialized + * and put into the TRX_OFF state. + * \retval RADIO_UNSUPPORTED_DEVICE The connected device is not an Atmel + * AT86RF230 radio transceiver. + * \retval RADIO_TIMED_OUT The radio transceiver was not able to initialize and + * enter TRX_OFF state within the specified time. + */ +radio_status_t +radio_init(bool cal_rc_osc, + hal_rx_start_isr_event_handler_t rx_event, + hal_trx_end_isr_event_handler_t trx_end_event, + radio_rx_callback rx_callback) +{ + radio_status_t init_status = RADIO_SUCCESS; + + delay_us(TIME_TO_ENTER_P_ON); + + /* calibrate oscillator */ + if (cal_rc_osc){ + calibrate_rc_osc_32k(); + } + + /* Initialize Hardware Abstraction Layer. */ + hal_init(); + + radio_reset_trx(); /* Do HW reset of radio transeiver. */ + + /* Force transition to TRX_OFF. */ + hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF); + delay_us(TIME_P_ON_TO_TRX_OFF); /* Wait for the transition to be complete. */ + + if (radio_get_trx_state() != TRX_OFF){ + init_status = RADIO_TIMED_OUT; + } else { + /* Read Version Number */ + uint8_t version_number = hal_register_read(RG_VERSION_NUM); + + if ((version_number != RF230_REVA) && (version_number != RF230_REVB)) + init_status = RADIO_UNSUPPORTED_DEVICE; + else { + if (hal_register_read(RG_MAN_ID_0) != SUPPORTED_MANUFACTURER_ID) + init_status = RADIO_UNSUPPORTED_DEVICE; + else + hal_register_write(RG_IRQ_MASK, RF230_SUPPORTED_INTERRUPT_MASK); + } + } + + /* set callbacks for events. Save user's rx_event, which we will */ + /* call from radio_rx_start_event(). Same with trx_end */ + user_rx_event = rx_event; + user_trx_end_event = trx_end_event; + hal_set_rx_start_event_handler(radio_rx_start_event); + hal_set_trx_end_event_handler(radio_trx_end_event); + + rx_frame_callback = rx_callback; + + return init_status; +} + +/*---------------------------------------------------------------------------*/ +static void +radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length) +{ + /* save away RSSI */ + rssi_val = hal_subregister_read( SR_RSSI ); + + /* call user's rx_start event handler */ + if (user_rx_event) + user_rx_event(isr_timestamp, frame_length); +} + +/*---------------------------------------------------------------------------*/ +uint8_t +radio_get_saved_rssi_value(void) +{ + return rssi_val; +} + +/*---------------------------------------------------------------------------*/ +static void +radio_trx_end_event(uint32_t const isr_timestamp) +{ + volatile uint8_t status; + + /* call user's trx_end event handler */ + if (user_trx_end_event){ + user_trx_end_event(isr_timestamp); + return; + } + if (rx_mode){ + /* radio has received frame, store it away */ + parsed_frame.time = isr_timestamp; + parsed_frame.rssi = rssi_val; + + hal_frame_read(&rx_frame, NULL); + rx_frame_parse(&rx_frame, &parsed_frame); + } + + if (!rx_mode){ + /* Put radio back into receive mode. */ + radio_set_trx_state(TRX_OFF); + radio_set_trx_state(rxMode); + + /* transmit mode, put end-of-transmit event in queue */ + event_object_t event; + event.event = 0; + event.data = 0; + status = hal_subregister_read(SR_TRAC_STATUS); + switch(status){ + case TRAC_SUCCESS: + case TRAC_SUCCESS_DATA_PENDING: + event.event = MAC_EVENT_ACK; + break; + case TRAC_NO_ACK: + case TRAC_CHANNEL_ACCESS_FAILURE: + event.event = MAC_EVENT_NACK; + break; + case TRAC_SUCCESS_WAIT_FOR_ACK: + /* should only happen in RX mode */ + case TRAC_INVALID: + /* should never happen here */ + default: + break; + } + if (event.event) + mac_put_event(&event); + process_post(&mac_process, event.event, event.data); + } +} +/*----------------------------------------------------------------------------*/ +/** \brief This function will return the channel used by the radio transceiver. + * + * \return Current channel, 11 to 26. + */ +uint8_t +radio_get_operating_channel(void) +{ + return hal_subregister_read(SR_CHANNEL); +} +/*----------------------------------------------------------------------------*/ +/** \brief This function will change the operating channel. + * + * \param channel New channel to operate on. Must be between 11 and 26. + * + * \retval RADIO_SUCCESS New channel set. + * \retval RADIO_WRONG_STATE Transceiver is in a state where the channel cannot + * be changed (SLEEP). + * \retval RADIO_INVALID_ARGUMENT Channel argument is out of bounds. + * \retval RADIO_TIMED_OUT The PLL did not lock within the specified time. + */ +radio_status_t +radio_set_operating_channel(uint8_t channel) +{ + /*Do function parameter and state check.*/ + if ((channel < RF230_MIN_CHANNEL) || + (channel > RF230_MAX_CHANNEL)){ + return RADIO_INVALID_ARGUMENT; + } + + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + if (radio_get_operating_channel() == channel){ + return RADIO_SUCCESS; + } + + /*Set new operating channel.*/ + hal_subregister_write(SR_CHANNEL, channel); + + /* Read current state and wait for the PLL_LOCK interrupt if the */ + /* radio transceiver is in either RX_ON or PLL_ON. */ + uint8_t trx_state = radio_get_trx_state(); + + if ((trx_state == RX_ON) || + (trx_state == PLL_ON)){ + delay_us(TIME_PLL_LOCK); + } + + radio_status_t channel_set_status = RADIO_TIMED_OUT; + + /* Check that the channel was set properly. */ + if (radio_get_operating_channel() == channel){ + channel_set_status = RADIO_SUCCESS; + } + + return channel_set_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will read and return the output power level. + * + * \returns 0 to 15 Current output power in "TX power settings" as defined in + * the radio transceiver's datasheet + */ +uint8_t +radio_get_tx_power_level(void) +{ + return hal_subregister_read(SR_TX_PWR); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will change the output power level. + * + * \param power_level New output power level in the "TX power settings" + * as defined in the radio transceiver's datasheet. + * + * \retval RADIO_SUCCESS New output power set successfully. + * \retval RADIO_INVALID_ARGUMENT The supplied function argument is out of bounds. + * \retval RADIO_WRONG_STATE It is not possible to change the TX power when the + * device is sleeping. + */ +radio_status_t +radio_set_tx_power_level(uint8_t power_level) +{ + + /*Check function parameter and state.*/ + if (power_level > TX_PWR_17_2DBM){ + return RADIO_INVALID_ARGUMENT; + } + + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + /*Set new power level*/ + hal_subregister_write(SR_TX_PWR, power_level); + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current CCA mode used. + * + * \return CCA mode currently used, 0 to 3. + */ +uint8_t +radio_get_cca_mode(void) +{ + return hal_subregister_read(SR_CCA_MODE); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current ED threshold used by the CCA algorithm. + * + * \return Current ED threshold, 0 to 15. + */ +uint8_t +radio_get_ed_threshold(void) +{ + return hal_subregister_read(SR_CCA_ED_THRES); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will configure the Clear Channel Assessment algorithm. + * + * \param mode Three modes are available: Energy above threshold, carrier + * sense only and carrier sense with energy above threshold. + * \param ed_threshold Above this energy threshold the channel is assumed to be + * busy. The threshold is given in positive dBm values. + * Ex. -91 dBm gives a csThreshold of 91. Value range for + * the variable is [61 to 91]. Only valid for the CCA_ED + * and CCA_CARRIER_SENSE_ED modes. + * + * \retval RADIO_SUCCESS Mode and its parameters successfully changed. + * \retval RADIO_WRONG_STATE This function cannot be called in the SLEEP state. + * \retval RADIO_INVALID_ARGUMENT If one of the three function arguments are out + * of bounds. + */ +radio_status_t +radio_set_cca_mode(uint8_t mode, uint8_t ed_threshold) +{ + /*Check function parameters and state.*/ + if ((mode != CCA_ED) && + (mode != CCA_CARRIER_SENSE) && + (mode != CCA_CARRIER_SENSE_WITH_ED)){ + return RADIO_INVALID_ARGUMENT; + } + + /* Ensure that the ED threshold is within bounds. */ + if (ed_threshold > RF230_MAX_ED_THRESHOLD){ + return RADIO_INVALID_ARGUMENT; + } + + /* Ensure that the radio transceiver is not sleeping. */ + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + /*Change cca mode and ed threshold.*/ + hal_subregister_write(SR_CCA_MODE, mode); + hal_subregister_write(SR_CCA_ED_THRES, ed_threshold); + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the Received Signal Strength Indication. + * + * \note This function should only be called from the: RX_ON and BUSY_RX. This + * can be ensured by reading the current state of the radio transceiver + * before executing this function! + * \param rssi Pointer to memory location where RSSI value should be written. + * \retval RADIO_SUCCESS The RSSI measurement was successful. + * \retval RADIO_WRONG_STATE The radio transceiver is not in RX_ON or BUSY_RX. + */ +radio_status_t +radio_get_rssi_value(uint8_t *rssi) +{ + + uint8_t current_state = radio_get_trx_state(); + radio_status_t retval = RADIO_WRONG_STATE; + + /*The RSSI measurement should only be done in RX_ON or BUSY_RX.*/ + if ((current_state == RX_ON) || + (current_state == BUSY_RX)){ + *rssi = hal_subregister_read(SR_RSSI); + retval = RADIO_SUCCESS; + } + + return retval; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current threshold volatge used by the + * battery monitor (BATMON_VTH). + * + * \note This function can not be called from P_ON or SLEEP. This is ensured + * by reading the device state before calling this function. + * + * \return Current threshold voltage, 0 to 15. + */ +uint8_t +radio_batmon_get_voltage_threshold(void) +{ + return hal_subregister_read(SR_BATMON_VTH); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns if high or low voltage range is used. + * + * \note This function can not be called from P_ON or SLEEP. This is ensured + * by reading the device state before calling this function. + * + * \retval 0 Low voltage range selected. + * \retval 1 High voltage range selected. + */ +uint8_t +radio_batmon_get_voltage_range(void) +{ + return hal_subregister_read(SR_BATMON_HR); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function is used to configure the battery monitor module + * + * \param range True means high voltage range and false low voltage range. + * \param voltage_threshold The datasheet defines 16 voltage levels for both + * low and high range. + * \retval RADIO_SUCCESS Battery monitor configured + * \retval RADIO_WRONG_STATE The device is sleeping. + * \retval RADIO_INVALID_ARGUMENT The voltage_threshold parameter is out of + * bounds (Not within [0 - 15]). + */ +radio_status_t +radio_batmon_configure(bool range, uint8_t voltage_threshold) +{ + + /*Check function parameters and state.*/ + if (voltage_threshold > BATTERY_MONITOR_HIGHEST_VOLTAGE){ + return RADIO_INVALID_ARGUMENT; + } + + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + /*Write new voltage range and voltage level.*/ + if (range == true){ + hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_HIGH_VOLTAGE); + } else { + hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_LOW_VOLTAGE); + } + + hal_subregister_write(SR_BATMON_VTH, voltage_threshold); + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the status of the Battery Monitor module. + * + * \note This function can not be called from P_ON or SLEEP. This is ensured + * by reading the device state before calling this function. + * + * \retval RADIO_BAT_LOW Battery voltage is below the programmed threshold. + * \retval RADIO_BAT_OK Battery voltage is above the programmed threshold. + */ +radio_status_t +radio_batmon_get_status(void) +{ + + radio_status_t batmon_status = RADIO_BAT_LOW; + + if (hal_subregister_read(SR_BATMON_OK) != + BATTERY_MONITOR_VOLTAGE_UNDER_THRESHOLD){ + batmon_status = RADIO_BAT_OK; + } + + return batmon_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function returns the current clock setting for the CLKM pin. + * + * \retval CLKM_DISABLED CLKM pin is disabled. + * \retval CLKM_1MHZ CLKM pin is prescaled to 1 MHz. + * \retval CLKM_2MHZ CLKM pin is prescaled to 2 MHz. + * \retval CLKM_4MHZ CLKM pin is prescaled to 4 MHz. + * \retval CLKM_8MHZ CLKM pin is prescaled to 8 MHz. + * \retval CLKM_16MHZ CLKM pin is not prescaled. Output is 16 MHz. + */ +uint8_t +radio_get_clock_speed(void) +{ + return hal_subregister_read(SR_CLKM_CTRL); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function changes the prescaler on the CLKM pin. + * + * \param direct This boolean variable is used to determine if the frequency + * of the CLKM pin shall be changed directly or not. If direct + * equals true, the frequency will be changed directly. This is + * fine if the CLKM signal is used to drive a timer etc. on the + * connected microcontroller. However, the CLKM signal can also + * be used to clock the microcontroller itself. In this situation + * it is possible to change the CLKM frequency indirectly + * (direct == false). When the direct argument equlas false, the + * CLKM frequency will be changed first after the radio transceiver + * has been taken to SLEEP and awaken again. + * \param clock_speed This parameter can be one of the following constants: + * CLKM_DISABLED, CLKM_1MHZ, CLKM_2MHZ, CLKM_4MHZ, CLKM_8MHZ + * or CLKM_16MHZ. + * + * \retval RADIO_SUCCESS Clock speed updated. New state is TRX_OFF. + * \retval RADIO_INVALID_ARGUMENT Requested clock speed is out of bounds. + */ +radio_status_t +radio_set_clock_speed(bool direct, uint8_t clock_speed) +{ + /*Check function parameter and current clock speed.*/ + if (clock_speed > CLKM_16MHZ){ + return RADIO_INVALID_ARGUMENT; + } + + if (radio_get_clock_speed() == clock_speed){ + return RADIO_SUCCESS; + } + + /*Select to change the CLKM frequency directly or after returning from SLEEP.*/ + if (direct == false){ + hal_subregister_write(SR_CLKM_SHA_SEL, 1); + } else { + hal_subregister_write(SR_CLKM_SHA_SEL, 0); + } + + hal_subregister_write(SR_CLKM_CTRL, clock_speed); + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function calibrates the Single Side Band Filter. + * + * \retval RADIO_SUCCESS Filter is calibrated. + * \retval RADIO_TIMED_OUT The calibration could not be completed within time. + * \retval RADIO_WRONG_STATE This function can only be called from TRX_OFF or + * PLL_ON. + */ +radio_status_t +radio_calibrate_filter(void) +{ + /*Check current state. Only possible to do filter calibration from TRX_OFF or PLL_ON.*/ + uint8_t trx_state = radio_get_trx_state(); + + if ((trx_state != TRX_OFF) && + (trx_state != PLL_ON)){ + return RADIO_WRONG_STATE; + } + + /* Start the tuning algorithm by writing one to the FTN_START subregister. */ + hal_subregister_write(SR_FTN_START, 1); + delay_us(TIME_FTN_TUNING); /* Wait for the calibration to finish. */ + + radio_status_t filter_calibration_status = RADIO_TIMED_OUT; + + /* Verify the calibration result. */ + if (hal_subregister_read(SR_FTN_START) == FTN_CALIBRATION_DONE){ + filter_calibration_status = RADIO_SUCCESS; + } + + return filter_calibration_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function calibrates the PLL. + * + * \retval RADIO_SUCCESS PLL Center Frequency and Delay Cell is calibrated. + * \retval RADIO_TIMED_OUT The calibration could not be completed within time. + * \retval RADIO_WRONG_STATE This function can only be called from PLL_ON. + */ +radio_status_t +radio_calibrate_pll(void) +{ + + /*Check current state. Only possible to calibrate PLL from PLL_ON state*/ + if (radio_get_trx_state() != PLL_ON){ + return RADIO_WRONG_STATE; + } + + /* Initiate the DCU and CF calibration loops. */ + hal_subregister_write(SR_PLL_DCU_START, 1); + hal_subregister_write(SR_PLL_CF_START, 1); + + /* Wait maximum 150 us for the PLL to lock. */ + hal_clear_pll_lock_flag(); + delay_us(TIME_PLL_LOCK); + + radio_status_t pll_calibration_status = RADIO_TIMED_OUT; + + if (hal_get_pll_lock_flag() > 0){ + if (hal_subregister_read(SR_PLL_DCU_START) == PLL_DCU_CALIBRATION_DONE){ + if (hal_subregister_read(SR_PLL_CF_START) == PLL_CF_CALIBRATION_DONE){ + pll_calibration_status = RADIO_SUCCESS; + } + } + } + + return pll_calibration_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function return the Radio Transceivers current state. + * + * \retval P_ON When the external supply voltage (VDD) is + * first supplied to the transceiver IC, the + * system is in the P_ON (Poweron) mode. + * \retval BUSY_RX The radio transceiver is busy receiving a + * frame. + * \retval BUSY_TX The radio transceiver is busy transmitting a + * frame. + * \retval RX_ON The RX_ON mode enables the analog and digital + * receiver blocks and the PLL frequency + * synthesizer. + * \retval TRX_OFF In this mode, the SPI module and crystal + * oscillator are active. + * \retval PLL_ON Entering the PLL_ON mode from TRX_OFF will + * first enable the analog voltage regulator. The + * transceiver is ready to transmit a frame. + * \retval BUSY_RX_AACK The radio was in RX_AACK_ON mode and received + * the Start of Frame Delimiter (SFD). State + * transition to BUSY_RX_AACK is done if the SFD + * is valid. + * \retval BUSY_TX_ARET The radio transceiver is busy handling the + * auto retry mechanism. + * \retval RX_AACK_ON The auto acknowledge mode of the radio is + * enabled and it is waiting for an incomming + * frame. + * \retval TX_ARET_ON The auto retry mechanism is enabled and the + * radio transceiver is waiting for the user to + * send the TX_START command. + * \retval RX_ON_NOCLK The radio transceiver is listening for + * incomming frames, but the CLKM is disabled so + * that the controller could be sleeping. + * However, this is only true if the controller + * is run from the clock output of the radio. + * \retval RX_AACK_ON_NOCLK Same as the RX_ON_NOCLK state, but with the + * auto acknowledge module turned on. + * \retval BUSY_RX_AACK_NOCLK Same as BUSY_RX_AACK, but the controller + * could be sleeping since the CLKM pin is + * disabled. + * \retval STATE_TRANSITION The radio transceiver's state machine is in + * transition between two states. + */ +uint8_t +radio_get_trx_state(void) +{ + return hal_subregister_read(SR_TRX_STATUS); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function checks if the radio transceiver is sleeping. + * + * \retval true The radio transceiver is in SLEEP or one of the *_NOCLK + * states. + * \retval false The radio transceiver is not sleeping. + */ +bool radio_is_sleeping(void) +{ + bool sleeping = false; + + /* The radio transceiver will be at SLEEP or one of the *_NOCLK states only if */ + /* the SLP_TR pin is high. */ + if (hal_get_slptr() != 0){ + sleeping = true; + } + + return sleeping; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will change the current state of the radio + * transceiver's internal state machine. + * + * \param new_state Here is a list of possible states: + * - RX_ON Requested transition to RX_ON state. + * - TRX_OFF Requested transition to TRX_OFF state. + * - PLL_ON Requested transition to PLL_ON state. + * - RX_AACK_ON Requested transition to RX_AACK_ON state. + * - TX_ARET_ON Requested transition to TX_ARET_ON state. + * + * \retval RADIO_SUCCESS Requested state transition completed + * successfully. + * \retval RADIO_INVALID_ARGUMENT Supplied function parameter out of bounds. + * \retval RADIO_WRONG_STATE Illegal state to do transition from. + * \retval RADIO_BUSY_STATE The radio transceiver is busy. + * \retval RADIO_TIMED_OUT The state transition could not be completed + * within resonable time. + */ +radio_status_t +radio_set_trx_state(uint8_t new_state) +{ + /*Check function paramter and current state of the radio transceiver.*/ + if (!((new_state == TRX_OFF) || + (new_state == RX_ON) || + (new_state == PLL_ON) || + (new_state == RX_AACK_ON) || + (new_state == TX_ARET_ON))){ + return RADIO_INVALID_ARGUMENT; + } + + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + uint8_t original_state = radio_get_trx_state(); + + if ((original_state == BUSY_RX) || + (original_state == BUSY_TX) || + (original_state == BUSY_RX_AACK) || + (original_state == BUSY_TX_ARET)){ + return RADIO_BUSY_STATE; + } + + if (new_state == original_state){ + return RADIO_SUCCESS; + } + + /* At this point it is clear that the requested new_state is: */ + /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON. */ + + /* The radio transceiver can be in one of the following states: */ + /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON, TX_ARET_ON. */ + if(new_state == TRX_OFF){ + radio_reset_state_machine(); /* Go to TRX_OFF from any state. */ + } else { + /* It is not allowed to go from RX_AACK_ON or TX_AACK_ON and directly to */ + /* TX_AACK_ON or RX_AACK_ON respectively. Need to go via RX_ON or PLL_ON. */ + if ((new_state == TX_ARET_ON) && + (original_state == RX_AACK_ON)){ + /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */ + /* The final state transition to TX_ARET_ON is handled after the if-else if. */ + hal_subregister_write(SR_TRX_CMD, PLL_ON); + delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); + } else if ((new_state == RX_AACK_ON) && + (original_state == TX_ARET_ON)){ + /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */ + /* The final state transition to RX_AACK_ON is handled after the if-else if. */ + hal_subregister_write(SR_TRX_CMD, RX_ON); + delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); + } + + /* Any other state transition can be done directly. */ + hal_subregister_write(SR_TRX_CMD, new_state); + + /* When the PLL is active most states can be reached in 1us. However, from */ + /* TRX_OFF the PLL needs time to activate. */ + if (original_state == TRX_OFF){ + delay_us(TIME_TRX_OFF_TO_PLL_ACTIVE); + } else { + delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE); + } + } /* end: if(new_state == TRX_OFF) ... */ + + /*Verify state transition.*/ + radio_status_t set_state_status = RADIO_TIMED_OUT; + + if (radio_get_trx_state() == new_state){ + set_state_status = RADIO_SUCCESS; + /* set rx_mode flag based on mode we're changing to */ + if (new_state == RX_ON || + new_state == RX_AACK_ON){ + rx_mode = true; + } else { + rx_mode = false; + } + } + + return set_state_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will put the radio transceiver to sleep. + * + * \retval RADIO_SUCCESS Sleep mode entered successfully. + * \retval RADIO_TIMED_OUT The transition to TRX_OFF took too long. + */ +radio_status_t +radio_enter_sleep_mode(void) +{ + if (radio_is_sleeping() == true){ + return RADIO_SUCCESS; + } + + radio_reset_state_machine(); /* Force the device into TRX_OFF. */ + + radio_status_t enter_sleep_status = RADIO_TIMED_OUT; + + if (radio_get_trx_state() == TRX_OFF){ + /* Enter Sleep. */ + hal_set_slptr_high(); + enter_sleep_status = RADIO_SUCCESS; + } + + return enter_sleep_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will take the radio transceiver from sleep mode and + * put it into the TRX_OFF state. + * + * \retval RADIO_SUCCESS Left sleep mode and entered TRX_OFF state. + * \retval RADIO_TIMED_OUT Transition to TRX_OFF state timed out. + */ +radio_status_t +radio_leave_sleep_mode(void) +{ + /* Check if the radio transceiver is actually sleeping. */ + if (radio_is_sleeping() == false){ + return RADIO_SUCCESS; + } + + hal_set_slptr_low(); + delay_us(TIME_SLEEP_TO_TRX_OFF); + + radio_status_t leave_sleep_status = RADIO_TIMED_OUT; + + /* Ensure that the radio transceiver is in the TRX_OFF state. */ + if (radio_get_trx_state() == TRX_OFF){ + leave_sleep_status = RADIO_SUCCESS; + } + + return leave_sleep_status; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will reset the state machine (to TRX_OFF) from any of + * its states, except for the SLEEP state. + */ +void +radio_reset_state_machine(void) +{ + hal_set_slptr_low(); + delay_us(TIME_NOCLK_TO_WAKE); + hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF); + delay_us(TIME_CMD_FORCE_TRX_OFF); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will reset all the registers and the state machine of + * the radio transceiver. + */ +void +radio_reset_trx(void) +{ + hal_set_rst_low(); + hal_set_slptr_low(); + delay_us(TIME_RESET); + hal_set_rst_high(); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will enable or disable automatic CRC during frame + * transmission. + * + * \param auto_crc_on If this parameter equals true auto CRC will be used for + * all frames to be transmitted. The framelength must be + * increased by two bytes (16 bit CRC). If the parameter equals + * false, the automatic CRC will be disabled. + */ +void +radio_use_auto_tx_crc(bool auto_crc_on) +{ + if (auto_crc_on == true){ + hal_subregister_write(SR_TX_AUTO_CRC_ON, 1); + } else { + hal_subregister_write(SR_TX_AUTO_CRC_ON, 0); + } +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will download a frame to the radio transceiver's + * transmit buffer and send it. + * + * \param data_length Length of the frame to be transmitted. 1 to 128 bytes are the valid lengths. + * \param *data Pointer to the data to transmit + * + * \retval RADIO_SUCCESS Frame downloaded and sent successfully. + * \retval RADIO_INVALID_ARGUMENT If the dataLength is 0 byte or more than 127 + * bytes the frame will not be sent. + * \retval RADIO_WRONG_STATE It is only possible to use this function in the + * PLL_ON and TX_ARET_ON state. If any other state is + * detected this error message will be returned. + */ +radio_status_t +radio_send_data(uint8_t data_length, uint8_t *data) +{ + /*Check function parameters and current state.*/ + if (data_length > RF230_MAX_TX_FRAME_LENGTH){ + return RADIO_INVALID_ARGUMENT; + } + + /* If we are busy, return */ + if ((radio_get_trx_state() == BUSY_TX) || (radio_get_trx_state() == BUSY_TX_ARET) ) + { + return RADIO_WRONG_STATE; + } + + radio_set_trx_state(TRX_OFF); + radio_set_trx_state(TX_ARET_ON); + + /*Do frame transmission.*/ + /* Toggle the SLP_TR pin to initiate the frame transmission. */ + hal_set_slptr_high(); + hal_set_slptr_low(); + + hal_frame_write(data, data_length); /* Then write data to the frame buffer. */ + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will read the I_AM_COORD sub register. + * + * \retval 0 Not coordinator. + * \retval 1 Coordinator role enabled. + */ +uint8_t +radio_get_device_role(void) +{ + return hal_subregister_read(SR_I_AM_COORD); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will set the I_AM_COORD sub register. + * + * \param[in] i_am_coordinator If this parameter is true, the associated + * coordinator role will be enabled in the radio + * transceiver's address filter. + * False disables the same feature. + */ +void +radio_set_device_role(bool i_am_coordinator) +{ + if (i_am_coordinator == true){ + hal_subregister_write(SR_I_AM_COORD, 0); + } else { + hal_subregister_write(SR_I_AM_COORD, 0); + } +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will return the PANID used by the address filter. + * + * \retval Any value from 0 to 0xFFFF. + */ +uint16_t +radio_get_pan_id(void) +{ + + uint8_t pan_id_15_8 = hal_register_read(RG_PAN_ID_1); /* Read pan_id_15_8. */ + uint8_t pan_id_7_0 = hal_register_read(RG_PAN_ID_0); /* Read pan_id_7_0. */ + + uint16_t pan_id = ((uint16_t)(pan_id_15_8 << 8)) | pan_id_7_0; + + return pan_id; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will set the PANID used by the address filter. + * + * \param new_pan_id Desired PANID. Can be any value from 0x0000 to 0xFFFF + */ +void +radio_set_pan_id(uint16_t new_pan_id) +{ + + uint8_t pan_byte = new_pan_id & 0xFF; /* Extract new_pan_id_7_0. */ + hal_register_write(RG_PAN_ID_0, pan_byte); + + pan_byte = (new_pan_id >> 8*1) & 0xFF; /* Extract new_pan_id_15_8. */ + hal_register_write(RG_PAN_ID_1, pan_byte); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will return the current short address used by the + * address filter. + * + * \retval Any value from 0x0000 to 0xFFFF + */ +uint16_t +radio_get_short_address(void) +{ + + uint8_t short_address_15_8 = hal_register_read(RG_SHORT_ADDR_1); /* Read short_address_15_8. */ + uint8_t short_address_7_0 = hal_register_read(RG_SHORT_ADDR_1); /* Read short_address_7_0. */ + + uint16_t short_address = ((uint16_t)(short_address_15_8 << 8)) | short_address_7_0; + + return short_address; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will set the short address used by the address filter. + * + * \param new_short_address Short address to be used by the address filter. + */ +void +radio_set_short_address(uint16_t new_short_address) +{ + + uint8_t short_address_byte = new_short_address & 0xFF; /* Extract short_address_7_0. */ + hal_register_write(RG_SHORT_ADDR_0, short_address_byte); + + short_address_byte = (new_short_address >> 8*1) & 0xFF; /* Extract short_address_15_8. */ + hal_register_write(RG_SHORT_ADDR_1, short_address_byte); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will read the extended address used by the address + * filter. + * + * \note In this function a pointer is used to convey the 64-bit result, since + * it is very inefficient to use the stack for this. + * + * \return Extended Address, any 64-bit value. + */ +void +radio_get_extended_address(uint8_t *extended_address) +{ + *extended_address++ = hal_register_read(RG_IEEE_ADDR_0); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_1); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_2); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_3); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_4); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_5); + *extended_address++ = hal_register_read(RG_IEEE_ADDR_6); + *extended_address = hal_register_read(RG_IEEE_ADDR_7); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will set a new extended address to be used by the + * address filter. + * + * \param extended_address Extended address to be used by the address filter. + */ +void +radio_set_extended_address(uint8_t *extended_address) +{ + hal_register_write(RG_IEEE_ADDR_0, *extended_address++); + hal_register_write(RG_IEEE_ADDR_1, *extended_address++); + hal_register_write(RG_IEEE_ADDR_2, *extended_address++); + hal_register_write(RG_IEEE_ADDR_3, *extended_address++); + hal_register_write(RG_IEEE_ADDR_4, *extended_address++); + hal_register_write(RG_IEEE_ADDR_5, *extended_address++); + hal_register_write(RG_IEEE_ADDR_6, *extended_address++); + hal_register_write(RG_IEEE_ADDR_7, *extended_address++); +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function will configure the CSMA algorithm used by the radio + * transceiver when transmitting data from TX_ARET_ON state. + * + * \param seed0 Lower 8 bits of the seed used for the random number generator + * in the CSMA algorithm. Value range: 0 to 255. + * \param be_csma_seed1 Is a combined argument of the MIN_BE, MAX_CSMA_RETRIES + * and SEED1 variables: + * -# MIN_BE: Bit[7:6] Minimum back-off exponent in the + * CSMA/CA algorithm. + * -# MAX_CSMA_RETRIES: Bit[5:3] Number of retries in + * TX_ARET_ON mode to repeat the CSMA/CA procedures + * before the ARET procedure gives up. + * -# SEED1: Bits[2:0] Higher 3 bits of CSMA_SEED, bits[10:8] + * Seed for the random number generator in the + * CSMA/CA algorithm. + * \retval RADIO_SUCCESS The CSMA algorithm was configured successfully. + * \retval RADIO_WRONG_STATE This function should not be called in the + * SLEEP state. + */ +radio_status_t +radio_configure_csma(uint8_t seed0, uint8_t be_csma_seed1) +{ + + /*Check state.*/ + if (radio_is_sleeping() == true){ + return RADIO_WRONG_STATE; + } + + /*Extract parameters, and configure the CSMA-CA algorithm.*/ + uint8_t back_off_exponent = (be_csma_seed1 & 0xC0) >> 6; + uint8_t csma_retries = (be_csma_seed1 & 0x38) >> 3; + uint8_t seed1 = (be_csma_seed1 & 0x07); + + hal_subregister_write(SR_MAX_FRAME_RETRIES, 0); /* AT86RF230 rev A errata. */ + hal_subregister_write(SR_MAX_CSMA_RETRIES, csma_retries); + hal_subregister_write(SR_MIN_BE, back_off_exponent); + hal_register_write(RG_CSMA_SEED_0, seed0); + hal_subregister_write(SR_CSMA_SEED_1, seed1); + + return RADIO_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/** + \brief Calibrate the internal RC oscillator + + This function calibrates the internal RC oscillator, based + on the 1 MHz clock supplied by the AT86RF2xx. In order to + verify the calibration result you can program the CKOUT fuse + and monitor the CPU clock on an I/O pin. + + \return TRUE if calibrate passed; FALSE if calibrate failed. +*/ +bool +calibrate_rc_osc_clkm(void) +{ + bool success = false; + + /* Use the 1 MHz CLK_M from the AT86RF230. */ + uint16_t temp, counter; + uint8_t osccal_saved; + uint8_t tccr2b, tccr1b, tccr1a; + + /* in the following line, 1000000ULL represents the 1MHz input signal */ + /* from the radio. 265 is the number of counts to overflow 8-bit */ + /* timer 2. 32 is the divide by 32 prescaler for timer 1. F_CPU is */ + /* the main clock frequency. */ +#define TARGETVAL ((1000000ULL * 256 * 32) / F_CPU) + + + osccal_saved = OSCCAL; + cli(); + + radio_set_clock_speed(true, CLKM_1MHz); + + /* Save current values of timer status. */ + tccr2b = TCCR2B; + tccr1b = TCCR1B; + tccr1a = TCCR1A; + + /* Stop timers 1 and 2. */ + /* Set timer 1 to normal mode (no CTC, no PWM, just count). */ + TCCR2B = 0; + TCCR1B = 0; + TCCR1A = 0; + + for (counter = 0; counter < 1000; counter++){ + /* Delete pending timer 1 and 2 interrupts, and clear the */ + /* counters. */ + TIFR1 = 0xFF; + TIFR2 = 0xFF; + TCNT2 = 0; + TCNT1 = 0; + /* Timer 2 driven from clock divided by 32 */ + TCCR2B = (1 << CS21) | (1 << CS20); + /* Timer 1 driven with external clock */ + TCCR1B = (1 << CS12) | (1 << CS11); + + /* Wait for timer 2 to overflow. */ + while (!(TIFR2 & (1 << TOV2))){ + ; + } + + /* Stop timer 1. Now, TCNT1 contains the number of CPU cycles */ + /* counted while timer 2 was counting */ + TCCR1B = 0; + TCCR2B = 0; + + temp = TCNT1; + + if (temp < (uint16_t)(0.995 * TARGETVAL)){ + /* Too fast, slow down */ + OSCCAL--; + } else if (temp > (uint16_t)(1.005 * TARGETVAL)){ + /* Too slow, speed up */ + OSCCAL++; + } else { + /* We are within +/- 0.5 % of our target frequency, so we're */ + /* done. */ + success = true; + break; + } + } + + radio_set_clock_speed(true, CLKM_DISABLED); + + /* restore timer status regs */ + TCCR2B = tccr2b; + TCCR1B = tccr1b; + TCCR1A = tccr1a; + if (!success){ + /* We failed, therefore restore previous OSCCAL value. */ + OSCCAL = osccal_saved; + } + + return success; +} + +/*----------------------------------------------------------------------------*/ +/** + \brief Calibrate the internal RC oscillator + + This function calibrates the internal RC oscillator, based + on an external 32KHz crystal connected to TIMER2. In order to + verify the calibration result you can program the CKOUT fuse + and monitor the CPU clock on an I/O pin. +*/ +void +calibrate_rc_osc_32k(void) +{ + /* Calibrate RC Oscillator: The calibration routine is done by clocking TIMER2 + * from the external 32kHz crystal while running an internal timer simultaneously. + * The internal timer will be clocked at the same speed as the internal RC + * oscillator, while TIMER2 is running at 32768 Hz. This way it is not necessary + * to use a timed loop, and keep track cycles in timed loop vs. optimization + * and compiler. + */ + uint8_t osccal_original = OSCCAL; + volatile uint16_t temp; + + /* This is bad practice, but seems to work. */ + OSCCAL = 0x80; + + + // PRR0 &= ~((1 << PRTIM2)|(1 << PRTIM1)); /* Enable Timer 1 and 2 */ + + TIMSK2 = 0x00; /* Disable Timer/Counter 2 interrupts. */ + TIMSK1 = 0x00; /* Disable Timer/Counter 1 interrupts. */ + + /* Enable TIMER/COUNTER 2 to be clocked from the external 32kHz clock crystal. + * Then wait for the timer to become stable before doing any calibration. + */ + ASSR |= (1 << AS2); + while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; } + TCCR2B = 1 << CS20; /* run timer 2 at divide by 1 (32KHz) */ + + AVR_ENTER_CRITICAL_REGION(); + + uint8_t counter = 128; + bool cal_ok = false; + do{ + /* wait for timer to be ready for updated config */ + TCCR1B = 1 << CS10; + + while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; } + + TCNT2 = 0x80; + TCNT1 = 0; + + TIFR2 = 0xFF; + + /* Wait for TIMER/COUNTER 2 to overflow. Stop TIMER/COUNTER 1 and 2, and + * read the counter value of TIMER/COUNTER 1. It will now contain the + * number of cpu cycles elapsed within the period. + */ + while (!(TIFR2 & (1 << TOV2))){ + ; + } + temp = TCNT1; + + TCCR1B = 0; + +#define cal_upper (31250*1.05) // 32812 = 0x802c +#define cal_lower (31250*0.95) // 29687 = 0x73f7 + /* Iteratively reduce the error to be within limits */ + if (temp < cal_lower) { + /* Too slow. Put the hammer down. */ + OSCCAL++; + } else if (temp > cal_upper) { + /* Too fast, retard. */ + OSCCAL--; + } else { + /* The CPU clock frequency is now within +/- 0.5% of the target value. */ + cal_ok = true; + } + + counter--; + } while ((counter != 0) && (false == cal_ok)); + + if (true != cal_ok) { + /* We failed, therefore restore previous OSCCAL value. */ + OSCCAL = osccal_original; + } + + TCCR2B = 0; + + ASSR &= ~(1 << AS2); + + /* Disable both timers again to save power. */ + // PRR0 |= (1 << PRTIM2);/* |(1 << PRTIM1); */ + + AVR_LEAVE_CRITICAL_REGION(); +} + +/** @} */ +/** @} */ +/*EOF*/ diff --git a/cpu/avr/radio/rf230/radio.h b/cpu/avr/radio/rf230/radio.h new file mode 100644 index 000000000..d91d081b5 --- /dev/null +++ b/cpu/avr/radio/rf230/radio.h @@ -0,0 +1,219 @@ +/* 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. + */ +/** + * \addtogroup radiorf230 + * @{ + */ +/** + * \file + * \brief This file contains radio driver code. + * + * $Id: radio.h,v 1.1 2008/10/14 09:43:40 adamdunkels Exp $ + */ + +#ifndef RADIO_H +#define RADIO_H +/*============================ INCLUDE =======================================*/ +#include +#include +#include "at86rf230_registermap.h" +#include "hal.h" + +/*============================ MACROS ========================================*/ +#define SUPPORTED_PART_NUMBER ( 2 ) +#define RF230_REVA ( 1 ) +#define RF230_REVB ( 2 ) +#define SUPPORTED_MANUFACTURER_ID ( 31 ) +#define RF230_SUPPORTED_INTERRUPT_MASK ( 0x0C ) + +#define RF230_MIN_CHANNEL ( 11 ) +#define RF230_MAX_CHANNEL ( 26 ) +#define RF230_MIN_ED_THRESHOLD ( 0 ) +#define RF230_MAX_ED_THRESHOLD ( 15 ) +#define RF230_MAX_TX_FRAME_LENGTH ( 127 ) /**< 127 Byte PSDU. */ + +#define TX_PWR_3DBM ( 0 ) +#define TX_PWR_17_2DBM ( 15 ) + +#define BATTERY_MONITOR_HIGHEST_VOLTAGE ( 15 ) +#define BATTERY_MONITOR_VOLTAGE_UNDER_THRESHOLD ( 0 ) +#define BATTERY_MONITOR_HIGH_VOLTAGE ( 1 ) +#define BATTERY_MONITOR_LOW_VOLTAGE ( 0 ) + +#define FTN_CALIBRATION_DONE ( 0 ) +#define PLL_DCU_CALIBRATION_DONE ( 0 ) +#define PLL_CF_CALIBRATION_DONE ( 0 ) + +#define RC_OSC_REFERENCE_COUNT_MAX (1.005*F_CPU*31250UL/8000000UL) +#define RC_OSC_REFERENCE_COUNT_MIN (0.995*F_CPU*31250UL/8000000UL) +/*============================ TYPEDEFS ======================================*/ + +/** \brief This macro defines the start value for the RADIO_* status constants. + * + * It was chosen to have this macro so that the user can define where + * the status returned from the TAT starts. This can be useful in a + * system where numerous drivers are used, and some range of status codes + * are occupied. + * + * \see radio_status_t + */ +#define RADIO_STATUS_START_VALUE ( 0x40 ) + +/** \brief This enumeration defines the possible return values for the TAT API + * functions. + * + * These values are defined so that they should not collide with the + * return/status codes defined in the IEEE 802.15.4 standard. + * + */ +typedef enum{ + RADIO_SUCCESS = RADIO_STATUS_START_VALUE, /**< The requested service was performed successfully. */ + RADIO_UNSUPPORTED_DEVICE, /**< The connected device is not an Atmel AT86RF230. */ + RADIO_INVALID_ARGUMENT, /**< One or more of the supplied function arguments are invalid. */ + RADIO_TIMED_OUT, /**< The requested service timed out. */ + RADIO_WRONG_STATE, /**< The end-user tried to do an invalid state transition. */ + RADIO_BUSY_STATE, /**< The radio transceiver is busy receiving or transmitting. */ + RADIO_STATE_TRANSITION_FAILED, /**< The requested state transition could not be completed. */ + RADIO_CCA_IDLE, /**< Channel is clear, available to transmit a new frame. */ + RADIO_CCA_BUSY, /**< Channel busy. */ + RADIO_TRX_BUSY, /**< Transceiver is busy receiving or transmitting data. */ + RADIO_BAT_LOW, /**< Measured battery voltage is lower than voltage threshold. */ + RADIO_BAT_OK, /**< Measured battery voltage is above the voltage threshold. */ + RADIO_CRC_FAILED, /**< The CRC failed for the actual frame. */ + RADIO_CHANNEL_ACCESS_FAILURE, /**< The channel access failed during the auto mode. */ + RADIO_NO_ACK, /**< No acknowledge frame was received. */ +}radio_status_t; + + +/** + * \name Transaction status codes + * \{ + */ +#define TRAC_SUCCESS 0 +#define TRAC_SUCCESS_DATA_PENDING 1 +#define TRAC_SUCCESS_WAIT_FOR_ACK 2 +#define TRAC_CHANNEL_ACCESS_FAILURE 3 +#define TRAC_NO_ACK 5 +#define TRAC_INVALID 7 +/** \} */ + + +/** \brief This enumeration defines the possible modes available for the + * Clear Channel Assessment algorithm. + * + * These constants are extracted from the datasheet. + * + */ +typedef enum{ + CCA_ED = 0, /**< Use energy detection above threshold mode. */ + CCA_CARRIER_SENSE = 1, /**< Use carrier sense mode. */ + CCA_CARRIER_SENSE_WITH_ED = 2 /**< Use a combination of both energy detection and carrier sense. */ +}radio_cca_mode_t; + + +/** \brief This enumeration defines the possible CLKM speeds. + * + * These constants are extracted from the RF230 datasheet. + * + */ +typedef enum{ + CLKM_DISABLED = 0, + CLKM_1MHZ = 1, + CLKM_2MHZ = 2, + CLKM_4MHZ = 3, + CLKM_8MHZ = 4, + CLKM_16MHZ = 5 +}radio_clkm_speed_t; + +typedef void (*radio_rx_callback) (uint16_t data); +extern uint8_t rxMode; +/*============================ PROTOTYPES ====================================*/ +radio_status_t radio_init(bool cal_rc_osc, + hal_rx_start_isr_event_handler_t rx_event, + hal_trx_end_isr_event_handler_t trx_end_event, + radio_rx_callback rx_callback); +uint8_t radio_get_saved_rssi_value(void); +uint8_t radio_get_operating_channel( void ); +radio_status_t radio_set_operating_channel( uint8_t channel ); +uint8_t radio_get_tx_power_level( void ); +radio_status_t radio_set_tx_power_level( uint8_t power_level ); + +uint8_t radio_get_cca_mode( void ); +uint8_t radio_get_ed_threshold( void ); +radio_status_t radio_set_cca_mode( uint8_t mode, uint8_t ed_threshold ); +radio_status_t radio_do_cca( void ); +radio_status_t radio_get_rssi_value( uint8_t *rssi ); + +uint8_t radio_batmon_get_voltage_threshold( void ); +uint8_t radio_batmon_get_voltage_range( void ); +radio_status_t radio_batmon_configure( bool range, uint8_t voltage_threshold ); +radio_status_t radio_batmon_get_status( void ); + +uint8_t radio_get_clock_speed( void ); +radio_status_t radio_set_clock_speed( bool direct, uint8_t clock_speed ); +radio_status_t radio_calibrate_filter( void ); +radio_status_t radio_calibrate_pll( void ); + +uint8_t radio_get_trx_state( void ); +radio_status_t radio_set_trx_state( uint8_t new_state ); +radio_status_t radio_enter_sleep_mode( void ); +radio_status_t radio_leave_sleep_mode( void ); +void radio_reset_state_machine( void ); +void radio_reset_trx( void ); + +void radio_use_auto_tx_crc( bool auto_crc_on ); +radio_status_t radio_send_data( uint8_t data_length, uint8_t *data ); + +uint8_t radio_get_device_role( void ); +void radio_set_device_role( bool i_am_coordinator ); +uint16_t radio_get_pan_id( void ); +void radio_set_pan_id( uint16_t new_pan_id ); +uint16_t radio_get_short_address( void ); +void radio_set_short_address( uint16_t new_short_address ); +void radio_get_extended_address( uint8_t *extended_address ); +void radio_set_extended_address( uint8_t *extended_address ); +radio_status_t radio_configure_csma( uint8_t seed0, uint8_t be_csma_seed1 ); +bool calibrate_rc_osc_clkm(void); +void calibrate_rc_osc_32k(void); +#define delay_us( us ) ( _delay_loop_2( ( F_CPU / 4000000UL ) * ( us ) ) ) + +#endif +/** @} */ +/*EOF*/