📄 radio.c
字号:
/* Copyright (c) 2008, Swedish Institute of Computer Science * All rights reserved. * * Additional fixes for AVR contributed by: * Colin O'Flynn coflynn@newae.com * Eric Gnoske egnoske@gmail.com * Blake Leverett bleverett@gmail.com * Mike Vidales mavida404@gmail.com * Kevin Brown kbrown3@uccs.edu * Nate Bohlmann nate@elfwerks.com * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $Id: radio.c,v 1.2 2008/10/14 18:37:28 c_oflynn Exp $*//** * \brief This module contains the radio driver code for the Atmel * AT86RF230, '231, and '212 chips. * * \author Blake Leverett <bleverett@gmail.com> * Mike Vidales <mavida404@gmail.com> * Eric Gnoske <egnoske@gmail.com> **//** \addtogroup wireless * @{ *//** * \defgroup radiorf230 RF230 interface * @{ *//** * \file * This file contains radio driver code. * *//*============================ INCLUDE =======================================*/#include <stdlib.h>#include <util/delay.h>#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;static 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_tradio_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;}/*---------------------------------------------------------------------------*/uint8_t *radio_frame_data(void){ return rx_frame.data;}uint8_tradio_frame_length(void){ return rx_frame.length;}/*---------------------------------------------------------------------------*/static voidradio_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_tradio_get_saved_rssi_value(void){ return rssi_val;}/*---------------------------------------------------------------------------*/static voidradio_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_tradio_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_tradio_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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -