radio.c

Go to the documentation of this file.
00001 /*   Copyright (c) 2008, Swedish Institute of Computer Science
00002  *  All rights reserved.
00003  *
00004  *  Additional fixes for AVR contributed by:
00005  *      Colin O'Flynn coflynn@newae.com
00006  *      Eric Gnoske egnoske@gmail.com
00007  *      Blake Leverett bleverett@gmail.com
00008  *      Mike Vidales mavida404@gmail.com
00009  *      Kevin Brown kbrown3@uccs.edu
00010  *      Nate Bohlmann nate@elfwerks.com
00011  *
00012  *   All rights reserved.
00013  *
00014  *   Redistribution and use in source and binary forms, with or without
00015  *   modification, are permitted provided that the following conditions are met:
00016  *
00017  *   * Redistributions of source code must retain the above copyright
00018  *     notice, this list of conditions and the following disclaimer.
00019  *   * Redistributions in binary form must reproduce the above copyright
00020  *     notice, this list of conditions and the following disclaimer in
00021  *     the documentation and/or other materials provided with the
00022  *     distribution.
00023  *   * Neither the name of the copyright holders nor the names of
00024  *     contributors may be used to endorse or promote products derived
00025  *     from this software without specific prior written permission.
00026  *
00027  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037  *  POSSIBILITY OF SUCH DAMAGE.
00038  *
00039  * $Id: radio.c,v 1.5 2010/02/12 18:00:30 dak664 Exp $
00040 */
00041 
00042 /**
00043  *  \brief This module contains the radio driver code for the Atmel
00044  *  AT86RF230, '231, and '212 chips.
00045  *
00046  *  \author Blake Leverett <bleverett@gmail.com>
00047  *          Mike Vidales <mavida404@gmail.com>
00048  *          Eric Gnoske <egnoske@gmail.com>
00049  *
00050 */
00051 
00052 /**  \addtogroup wireless
00053  * @{
00054  */
00055 
00056 /**
00057  *  \defgroup radiorf230 RF230 interface
00058  * @{
00059  */
00060 /**
00061  *  \file
00062  *  This file contains radio driver code.
00063  *
00064  */
00065 
00066 
00067 
00068 /*============================ INCLUDE =======================================*/
00069 #include <stdlib.h>
00070 #include <util/delay.h>
00071 #include "radio.h"
00072 #include "hal.h"
00073 #include "process.h"
00074 #include "sicslowmac.h"
00075 #include "frame.h"
00076 
00077 /*============================ MACROS ========================================*/
00078 #define RADIO_CCA_DONE_MASK     (1 << 7) /**<  Mask used to check the CCA_DONE bit. */
00079 #define RADIO_CCA_IDLE_MASK     (1 << 6) /**<  Mask used to check the CCA_STATUS bit. */
00080 
00081 #define RADIO_START_CCA (1) /**<  Value in the CCA_REQUEST subregister that initiate a cca. */
00082 
00083 #define RADIO_TRANSMISSION_SUCCESS  (0)
00084 #define RADIO_BUSY_CHANNEL          (3)
00085 #define RADIO_MIN_IEEE_FRAME_LENGTH (5)
00086 /*============================ TYPEDEFS ======================================*/
00087 
00088 /** \brief  This enumeration defines the necessary timing information for the
00089  *          AT86RF230 radio transceiver. All times are in microseconds.
00090  *
00091  *          These constants are extracted from the datasheet.
00092  */
00093 typedef enum{
00094     TIME_TO_ENTER_P_ON               = 510, /**<  Transition time from VCC is applied to P_ON. */
00095     TIME_P_ON_TO_TRX_OFF             = 510, /**<  Transition time from P_ON to TRX_OFF. */
00096     TIME_SLEEP_TO_TRX_OFF            = 880, /**<  Transition time from SLEEP to TRX_OFF. */
00097     TIME_RESET                       = 6,   /**<  Time to hold the RST pin low during reset */
00098     TIME_ED_MEASUREMENT              = 140, /**<  Time it takes to do a ED measurement. */
00099     TIME_CCA                         = 140, /**<  Time it takes to do a CCA. */
00100     TIME_PLL_LOCK                    = 150, /**<  Maximum time it should take for the PLL to lock. */
00101     TIME_FTN_TUNING                  = 25,  /**<  Maximum time it should take to do the filter tuning. */
00102     TIME_NOCLK_TO_WAKE               = 6,   /**<  Transition time from *_NOCLK to being awake. */
00103     TIME_CMD_FORCE_TRX_OFF           = 1,    /**<  Time it takes to execute the FORCE_TRX_OFF command. */
00104     TIME_TRX_OFF_TO_PLL_ACTIVE       = 180, /**<  Transition time from TRX_OFF to: RX_ON, PLL_ON, TX_ARET_ON and RX_AACK_ON. */
00105     TIME_STATE_TRANSITION_PLL_ACTIVE = 1, /**<  Transition time from PLL active state to another. */
00106 }radio_trx_timing_t;
00107 
00108 /*============================ VARIABLES =====================================*/
00109 static hal_rx_start_isr_event_handler_t user_rx_event;
00110 static hal_trx_end_isr_event_handler_t user_trx_end_event;
00111 static radio_rx_callback rx_frame_callback;
00112 static uint8_t rssi_val;
00113 static uint8_t rx_mode;
00114 uint8_t rxMode = RX_AACK_ON;
00115 
00116 /* See clock.c and httpd-cgi.c for RADIOSTATS code */
00117 #define RADIOSTATS 0
00118 #if RADIOSTATS
00119 uint8_t RF230_radio_on, RF230_rsigsi;
00120 uint16_t RF230_sendpackets,RF230_receivepackets,RF230_sendfail,RF230_receivefail;
00121 #endif
00122 
00123 static hal_rx_frame_t rx_frame;
00124 static parsed_frame_t parsed_frame;
00125 
00126 /*============================ PROTOTYPES ====================================*/
00127 bool radio_is_sleeping(void);
00128 static void radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length);
00129 static void radio_trx_end_event(uint32_t const isr_timestamp);
00130 
00131 /** \brief  Initialize the Transceiver Access Toolbox and lower layers.
00132  *
00133  *          If the initialization is successful the radio transceiver will be in
00134  *          TRX_OFF state.
00135  *
00136  *  \note  This function must be called prior to any of the other functions in
00137  *         this file! Can be called from any transceiver state.
00138  *
00139  *  \param cal_rc_osc If true, the radio's accurate clock is used to calibrate the
00140  *                    CPU's internal RC oscillator.
00141  *
00142  *  \param rx_event Optional pointer to a user-defined function to be called on an
00143  *                  RX_START interrupt.  Use NULL for no handler.
00144  *
00145  *  \param trx_end_event Optional pointer to a user-defined function to be called on an
00146  *                  TRX_END interrupt.  Use NULL for no handler.
00147  *
00148  *  \param rx_callback Optional pointer to a user-defined function that receives
00149  *         a frame from the radio one byte at a time.  If the index parameter to
00150  *         this callback is 0xff, then the function should reset its state and prepare
00151  *         for a frame from the radio, with one call per byte.
00152  *
00153  *  \retval RADIO_SUCCESS     The radio transceiver was successfully initialized
00154  *                          and put into the TRX_OFF state.
00155  *  \retval RADIO_UNSUPPORTED_DEVICE  The connected device is not an Atmel
00156  *                                  AT86RF230 radio transceiver.
00157  *  \retval RADIO_TIMED_OUT   The radio transceiver was not able to initialize and
00158  *                          enter TRX_OFF state within the specified time.
00159  */
00160 radio_status_t
00161 radio_init(bool cal_rc_osc,
00162            hal_rx_start_isr_event_handler_t rx_event,
00163            hal_trx_end_isr_event_handler_t trx_end_event,
00164            radio_rx_callback rx_callback)
00165 {
00166     radio_status_t init_status = RADIO_SUCCESS;
00167 
00168     delay_us(TIME_TO_ENTER_P_ON);
00169 
00170     /*  calibrate oscillator */
00171     if (cal_rc_osc){
00172         calibrate_rc_osc_32k();
00173     }
00174 
00175     /* Initialize Hardware Abstraction Layer. */
00176     hal_init();
00177 
00178     radio_reset_trx(); /* Do HW reset of radio transeiver. */
00179 
00180     /* Force transition to TRX_OFF. */
00181     hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF);
00182     delay_us(TIME_P_ON_TO_TRX_OFF); /* Wait for the transition to be complete. */
00183 
00184     if (radio_get_trx_state() != TRX_OFF){
00185         init_status = RADIO_TIMED_OUT;
00186     } else {
00187         /* Read Version Number */
00188         uint8_t version_number = hal_register_read(RG_VERSION_NUM);
00189 
00190         if ((version_number != RF230_REVA) && (version_number != RF230_REVB))
00191             init_status = RADIO_UNSUPPORTED_DEVICE;
00192         else {
00193             if (hal_register_read(RG_MAN_ID_0) != SUPPORTED_MANUFACTURER_ID)
00194                 init_status = RADIO_UNSUPPORTED_DEVICE;
00195             else
00196                 hal_register_write(RG_IRQ_MASK, RF230_SUPPORTED_INTERRUPT_MASK);
00197         }
00198 #if RADIOSTATS
00199         RF230_radio_on = 1;
00200 #endif
00201     }
00202 
00203     /*  set callbacks for events.  Save user's rx_event, which we will */
00204     /*  call from radio_rx_start_event().  Same with trx_end */
00205     user_rx_event = rx_event;
00206     user_trx_end_event = trx_end_event;
00207     hal_set_rx_start_event_handler(radio_rx_start_event);
00208     hal_set_trx_end_event_handler(radio_trx_end_event);
00209 
00210     rx_frame_callback = rx_callback;
00211 
00212     return init_status;
00213 }
00214 
00215 /*---------------------------------------------------------------------------*/
00216 uint8_t *
00217 radio_frame_data(void)
00218 {
00219         return rx_frame.data;
00220 }
00221 
00222 uint8_t
00223 radio_frame_length(void)
00224 {
00225         return rx_frame.length;
00226 }
00227 
00228 /*---------------------------------------------------------------------------*/
00229 static void
00230 radio_rx_start_event(uint32_t const isr_timestamp, uint8_t const frame_length)
00231 {
00232     /*  save away RSSI */
00233     rssi_val =  hal_subregister_read( SR_RSSI );
00234 
00235     /*  call user's rx_start event handler */
00236     if (user_rx_event)
00237         user_rx_event(isr_timestamp, frame_length);
00238 }
00239 
00240 /*---------------------------------------------------------------------------*/
00241 uint8_t
00242 radio_get_saved_rssi_value(void)
00243 {
00244     return rssi_val;
00245 }
00246 
00247 /*---------------------------------------------------------------------------*/
00248 static void
00249 radio_trx_end_event(uint32_t const isr_timestamp)
00250 {
00251     volatile uint8_t status;
00252 
00253     /*  call user's trx_end event handler */
00254     if (user_trx_end_event){
00255         user_trx_end_event(isr_timestamp);
00256         return;
00257     }
00258     if (rx_mode){
00259         /* radio has received frame, store it away */
00260 #if RADIOSTATS
00261         RF230_rsigsi=rssi_val;
00262         RF230_receivepackets++;
00263 #endif
00264         parsed_frame.time = isr_timestamp;
00265         parsed_frame.rssi = rssi_val;
00266         
00267         hal_frame_read(&rx_frame, NULL);
00268         rx_frame_parse(&rx_frame, &parsed_frame);
00269         }
00270 
00271     if (!rx_mode){
00272         /*  Put radio back into receive mode. */
00273         radio_set_trx_state(TRX_OFF);
00274         radio_set_trx_state(rxMode);
00275 
00276         /*  transmit mode, put end-of-transmit event in queue */
00277         event_object_t event;
00278         event.event = 0;
00279         event.data = 0;
00280         status = hal_subregister_read(SR_TRAC_STATUS);
00281         switch(status){
00282         case TRAC_SUCCESS:
00283         case TRAC_SUCCESS_DATA_PENDING:
00284             event.event = MAC_EVENT_ACK;
00285             break;
00286         case TRAC_NO_ACK:
00287         case TRAC_CHANNEL_ACCESS_FAILURE:
00288             event.event = MAC_EVENT_NACK;
00289 #if RADIOSTATS
00290         RF230_sendfail++;
00291 #endif
00292             break;
00293         case TRAC_SUCCESS_WAIT_FOR_ACK:
00294             /*  should only happen in RX mode */
00295         case TRAC_INVALID:
00296             /*  should never happen here */
00297         default:
00298 #if RADIOSTATS
00299             RF230_sendfail++;
00300 #endif
00301             break;
00302         }
00303         if (event.event)
00304             mac_put_event(&event);
00305         process_post(&mac_process, event.event, event.data);
00306     }
00307 }
00308 /*----------------------------------------------------------------------------*/
00309 /** \brief  This function will return the channel used by the radio transceiver.
00310  *
00311  *  \return Current channel, 11 to 26.
00312  */
00313 uint8_t
00314 radio_get_operating_channel(void)
00315 {
00316     return hal_subregister_read(SR_CHANNEL);
00317 }
00318 /*----------------------------------------------------------------------------*/
00319 /** \brief This function will change the operating channel.
00320  *
00321  *  \param  channel New channel to operate on. Must be between 11 and 26.
00322  *
00323  *  \retval RADIO_SUCCESS New channel set.
00324  *  \retval RADIO_WRONG_STATE Transceiver is in a state where the channel cannot
00325  *                          be changed (SLEEP).
00326  *  \retval RADIO_INVALID_ARGUMENT Channel argument is out of bounds.
00327  *  \retval RADIO_TIMED_OUT The PLL did not lock within the specified time.
00328  */
00329 radio_status_t
00330 radio_set_operating_channel(uint8_t channel)
00331 {
00332     /*Do function parameter and state check.*/
00333     if ((channel < RF230_MIN_CHANNEL) ||
00334         (channel > RF230_MAX_CHANNEL)){
00335         return RADIO_INVALID_ARGUMENT;
00336     }
00337 
00338     if (radio_is_sleeping() == true){
00339         return RADIO_WRONG_STATE;
00340     }
00341 
00342     if (radio_get_operating_channel() == channel){
00343         return RADIO_SUCCESS;
00344     }
00345 
00346     /*Set new operating channel.*/
00347     hal_subregister_write(SR_CHANNEL, channel);
00348 
00349     /* Read current state and wait for the PLL_LOCK interrupt if the */
00350     /* radio transceiver is in either RX_ON or PLL_ON. */
00351     uint8_t trx_state = radio_get_trx_state();
00352 
00353     if ((trx_state == RX_ON) ||
00354         (trx_state == PLL_ON)){
00355         delay_us(TIME_PLL_LOCK);
00356     }
00357 
00358     radio_status_t channel_set_status = RADIO_TIMED_OUT;
00359 
00360     /* Check that the channel was set properly. */
00361     if (radio_get_operating_channel() == channel){
00362         channel_set_status = RADIO_SUCCESS;
00363     }
00364 
00365     return channel_set_status;
00366 }
00367 
00368 /*----------------------------------------------------------------------------*/
00369 /** \brief This function will read and return the output power level.
00370  *
00371  *  \returns 0 to 15 Current output power in "TX power settings" as defined in
00372  *          the radio transceiver's datasheet
00373  */
00374 uint8_t
00375 radio_get_tx_power_level(void)
00376 {
00377     return hal_subregister_read(SR_TX_PWR);
00378 }
00379 
00380 /*----------------------------------------------------------------------------*/
00381 /** \brief This function will change the output power level.
00382  *
00383  *  \param  power_level New output power level in the "TX power settings"
00384  *                      as defined in the radio transceiver's datasheet.
00385  *
00386  *  \retval RADIO_SUCCESS New output power set successfully.
00387  *  \retval RADIO_INVALID_ARGUMENT The supplied function argument is out of bounds.
00388  *  \retval RADIO_WRONG_STATE It is not possible to change the TX power when the
00389  *                          device is sleeping.
00390  */
00391 radio_status_t
00392 radio_set_tx_power_level(uint8_t power_level)
00393 {
00394 
00395     /*Check function parameter and state.*/
00396     if (power_level > TX_PWR_17_2DBM){
00397         return RADIO_INVALID_ARGUMENT;
00398     }
00399 
00400     if (radio_is_sleeping() == true){
00401         return RADIO_WRONG_STATE;
00402     }
00403 
00404     /*Set new power level*/
00405     hal_subregister_write(SR_TX_PWR, power_level);
00406 
00407     return RADIO_SUCCESS;
00408 }
00409 
00410 /*----------------------------------------------------------------------------*/
00411 /** \brief This function returns the current CCA mode used.
00412  *
00413  *  \return CCA mode currently used, 0 to 3.
00414  */
00415 uint8_t
00416 radio_get_cca_mode(void)
00417 {
00418     return hal_subregister_read(SR_CCA_MODE);
00419 }
00420 
00421 /*----------------------------------------------------------------------------*/
00422 /** \brief This function returns the current ED threshold used by the CCA algorithm.
00423  *
00424  *  \return Current ED threshold, 0 to 15.
00425  */
00426 uint8_t
00427 radio_get_ed_threshold(void)
00428 {
00429     return hal_subregister_read(SR_CCA_ED_THRES);
00430 }
00431 
00432 /*----------------------------------------------------------------------------*/
00433 /** \brief This function will configure the Clear Channel Assessment algorithm.
00434  *
00435  *  \param  mode Three modes are available: Energy above threshold, carrier
00436  *               sense only and carrier sense with energy above threshold.
00437  *  \param  ed_threshold Above this energy threshold the channel is assumed to be
00438  *                      busy. The threshold is given in positive dBm values.
00439  *                      Ex. -91 dBm gives a csThreshold of 91. Value range for
00440  *                      the variable is [61 to 91]. Only valid for the CCA_ED
00441  *                      and CCA_CARRIER_SENSE_ED modes.
00442  *
00443  *  \retval RADIO_SUCCESS Mode and its parameters successfully changed.
00444  *  \retval RADIO_WRONG_STATE This function cannot be called in the SLEEP state.
00445  *  \retval RADIO_INVALID_ARGUMENT If one of the three function arguments are out
00446  *                               of bounds.
00447  */
00448 radio_status_t
00449 radio_set_cca_mode(uint8_t mode, uint8_t ed_threshold)
00450 {
00451     /*Check function parameters and state.*/
00452     if ((mode != CCA_ED) &&
00453         (mode != CCA_CARRIER_SENSE) &&
00454         (mode != CCA_CARRIER_SENSE_WITH_ED)){
00455         return RADIO_INVALID_ARGUMENT;
00456     }
00457 
00458     /* Ensure that the ED threshold is within bounds. */
00459     if (ed_threshold > RF230_MAX_ED_THRESHOLD){
00460         return RADIO_INVALID_ARGUMENT;
00461     }
00462 
00463     /* Ensure that the radio transceiver is not sleeping. */
00464     if (radio_is_sleeping() == true){
00465         return RADIO_WRONG_STATE;
00466     }
00467 
00468     /*Change cca mode and ed threshold.*/
00469     hal_subregister_write(SR_CCA_MODE, mode);
00470     hal_subregister_write(SR_CCA_ED_THRES, ed_threshold);
00471 
00472     return RADIO_SUCCESS;
00473 }
00474 
00475 /*----------------------------------------------------------------------------*/
00476 /** \brief This function returns the Received Signal Strength Indication.
00477  *
00478  *  \note This function should only be called from the: RX_ON and BUSY_RX. This
00479  *        can be ensured by reading the current state of the radio transceiver
00480  *        before executing this function!
00481  *  \param rssi Pointer to memory location where RSSI value should be written.
00482  *  \retval RADIO_SUCCESS The RSSI measurement was successful.
00483  *  \retval RADIO_WRONG_STATE The radio transceiver is not in RX_ON or BUSY_RX.
00484  */
00485 radio_status_t
00486 radio_get_rssi_value(uint8_t *rssi)
00487 {
00488 
00489     uint8_t current_state = radio_get_trx_state();
00490     radio_status_t retval = RADIO_WRONG_STATE;
00491 
00492     /*The RSSI measurement should only be done in RX_ON or BUSY_RX.*/
00493     if ((current_state == RX_ON) ||
00494         (current_state == BUSY_RX)){
00495         *rssi = hal_subregister_read(SR_RSSI);
00496         retval = RADIO_SUCCESS;
00497     }
00498 
00499     return retval;
00500 }
00501 
00502 /*----------------------------------------------------------------------------*/
00503 /** \brief This function returns the current threshold volatge used by the
00504  *         battery monitor (BATMON_VTH).
00505  *
00506  *  \note This function can not be called from P_ON or SLEEP. This is ensured
00507  *        by reading the device state before calling this function.
00508  *
00509  *  \return Current threshold voltage, 0 to 15.
00510  */
00511 uint8_t
00512 radio_batmon_get_voltage_threshold(void)
00513 {
00514     return hal_subregister_read(SR_BATMON_VTH);
00515 }
00516 
00517 /*----------------------------------------------------------------------------*/
00518 /** \brief This function returns if high or low voltage range is used.
00519  *
00520  *  \note This function can not be called from P_ON or SLEEP. This is ensured
00521  *        by reading the device state before calling this function.
00522  *
00523  *  \retval 0 Low voltage range selected.
00524  *  \retval 1 High voltage range selected.
00525  */
00526 uint8_t
00527 radio_batmon_get_voltage_range(void)
00528 {
00529     return hal_subregister_read(SR_BATMON_HR);
00530 }
00531 
00532 /*----------------------------------------------------------------------------*/
00533 /** \brief This function is used to configure the battery monitor module
00534  *
00535  *  \param range True means high voltage range and false low voltage range.
00536  *  \param voltage_threshold The datasheet defines 16 voltage levels for both
00537  *                          low and high range.
00538  *  \retval RADIO_SUCCESS Battery monitor configured
00539  *  \retval RADIO_WRONG_STATE The device is sleeping.
00540  *  \retval RADIO_INVALID_ARGUMENT The voltage_threshold parameter is out of
00541  *                               bounds (Not within [0 - 15]).
00542  */
00543 radio_status_t
00544 radio_batmon_configure(bool range, uint8_t voltage_threshold)
00545 {
00546 
00547     /*Check function parameters and state.*/
00548     if (voltage_threshold > BATTERY_MONITOR_HIGHEST_VOLTAGE){
00549         return RADIO_INVALID_ARGUMENT;
00550     }
00551 
00552     if (radio_is_sleeping() == true){
00553         return RADIO_WRONG_STATE;
00554     }
00555 
00556     /*Write new voltage range and voltage level.*/
00557     if (range == true){
00558         hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_HIGH_VOLTAGE);
00559     } else {
00560         hal_subregister_write(SR_BATMON_HR, BATTERY_MONITOR_LOW_VOLTAGE);
00561     }
00562 
00563     hal_subregister_write(SR_BATMON_VTH, voltage_threshold);
00564 
00565     return RADIO_SUCCESS;
00566 }
00567 
00568 /*----------------------------------------------------------------------------*/
00569 /** \brief This function returns the status of the Battery Monitor module.
00570  *
00571  *  \note This function can not be called from P_ON or SLEEP. This is ensured
00572  *        by reading the device state before calling this function.
00573  *
00574  *  \retval RADIO_BAT_LOW Battery voltage is below the programmed threshold.
00575  *  \retval RADIO_BAT_OK Battery voltage is above the programmed threshold.
00576  */
00577 radio_status_t
00578 radio_batmon_get_status(void)
00579 {
00580 
00581     radio_status_t batmon_status = RADIO_BAT_LOW;
00582 
00583     if (hal_subregister_read(SR_BATMON_OK) !=
00584         BATTERY_MONITOR_VOLTAGE_UNDER_THRESHOLD){
00585         batmon_status = RADIO_BAT_OK;
00586     }
00587 
00588     return batmon_status;
00589 }
00590 
00591 /*----------------------------------------------------------------------------*/
00592 /** \brief This function returns the current clock setting for the CLKM pin.
00593  *
00594  *  \retval CLKM_DISABLED CLKM pin is disabled.
00595  *  \retval CLKM_1MHZ CLKM pin is prescaled to 1 MHz.
00596  *  \retval CLKM_2MHZ CLKM pin is prescaled to 2 MHz.
00597  *  \retval CLKM_4MHZ CLKM pin is prescaled to 4 MHz.
00598  *  \retval CLKM_8MHZ CLKM pin is prescaled to 8 MHz.
00599  *  \retval CLKM_16MHZ CLKM pin is not prescaled. Output is 16 MHz.
00600  */
00601 uint8_t
00602 radio_get_clock_speed(void)
00603 {
00604     return hal_subregister_read(SR_CLKM_CTRL);
00605 }
00606 
00607 /*----------------------------------------------------------------------------*/
00608 /** \brief This function changes the prescaler on the CLKM pin.
00609  *
00610  *  \param direct   This boolean variable is used to determine if the frequency
00611  *                  of the CLKM pin shall be changed directly or not. If direct
00612  *                  equals true, the frequency will be changed directly. This is
00613  *                  fine if the CLKM signal is used to drive a timer etc. on the
00614  *                  connected microcontroller. However, the CLKM signal can also
00615  *                  be used to clock the microcontroller itself. In this situation
00616  *                  it is possible to change the CLKM frequency indirectly
00617  *                  (direct == false). When the direct argument equlas false, the
00618  *                  CLKM frequency will be changed first after the radio transceiver
00619  *                  has been taken to SLEEP and awaken again.
00620  *  \param clock_speed This parameter can be one of the following constants:
00621  *                     CLKM_DISABLED, CLKM_1MHZ, CLKM_2MHZ, CLKM_4MHZ, CLKM_8MHZ
00622  *                     or CLKM_16MHZ.
00623  *
00624  *  \retval RADIO_SUCCESS Clock speed updated. New state is TRX_OFF.
00625  *  \retval RADIO_INVALID_ARGUMENT Requested clock speed is out of bounds.
00626  */
00627 radio_status_t
00628 radio_set_clock_speed(bool direct, uint8_t clock_speed)
00629 {
00630         /*Check function parameter and current clock speed.*/
00631     if (clock_speed > CLKM_16MHZ){
00632             return RADIO_INVALID_ARGUMENT;
00633     }
00634 
00635     if (radio_get_clock_speed() == clock_speed){
00636         return RADIO_SUCCESS;
00637     }
00638 
00639         /*Select to change the CLKM frequency directly or after returning from SLEEP.*/
00640     if (direct == false){
00641             hal_subregister_write(SR_CLKM_SHA_SEL, 1);
00642     } else {
00643             hal_subregister_write(SR_CLKM_SHA_SEL, 0);
00644     }
00645         
00646         hal_subregister_write(SR_CLKM_CTRL, clock_speed);
00647 
00648     return RADIO_SUCCESS;
00649 }
00650 
00651 /*----------------------------------------------------------------------------*/
00652 /** \brief  This function calibrates the Single Side Band Filter.
00653  *
00654  *  \retval     RADIO_SUCCESS    Filter is calibrated.
00655  *  \retval     RADIO_TIMED_OUT  The calibration could not be completed within time.
00656  *  \retval     RADIO_WRONG_STATE This function can only be called from TRX_OFF or
00657  *              PLL_ON.
00658  */
00659 radio_status_t
00660 radio_calibrate_filter(void)
00661 {
00662     /*Check current state. Only possible to do filter calibration from TRX_OFF or PLL_ON.*/
00663     uint8_t trx_state = radio_get_trx_state();
00664 
00665     if ((trx_state != TRX_OFF) &&
00666         (trx_state != PLL_ON)){
00667         return RADIO_WRONG_STATE;
00668     }
00669 
00670     /* Start the tuning algorithm by writing one to the FTN_START subregister. */
00671     hal_subregister_write(SR_FTN_START, 1);
00672     delay_us(TIME_FTN_TUNING); /* Wait for the calibration to finish. */
00673 
00674     radio_status_t filter_calibration_status = RADIO_TIMED_OUT;
00675 
00676     /* Verify the calibration result. */
00677     if (hal_subregister_read(SR_FTN_START) == FTN_CALIBRATION_DONE){
00678         filter_calibration_status = RADIO_SUCCESS;
00679     }
00680 
00681     return filter_calibration_status;
00682 }
00683 
00684 /*----------------------------------------------------------------------------*/
00685 /** \brief  This function calibrates the PLL.
00686  *
00687  *  \retval     RADIO_SUCCESS    PLL Center Frequency and Delay Cell is calibrated.
00688  *  \retval     RADIO_TIMED_OUT  The calibration could not be completed within time.
00689  *  \retval     RADIO_WRONG_STATE This function can only be called from PLL_ON.
00690  */
00691 radio_status_t
00692 radio_calibrate_pll(void)
00693 {
00694 
00695     /*Check current state. Only possible to calibrate PLL from PLL_ON state*/
00696     if (radio_get_trx_state() != PLL_ON){
00697         return RADIO_WRONG_STATE;
00698     }
00699 
00700     /* Initiate the DCU and CF calibration loops. */
00701     hal_subregister_write(SR_PLL_DCU_START, 1);
00702     hal_subregister_write(SR_PLL_CF_START, 1);
00703 
00704     /* Wait maximum 150 us for the PLL to lock. */
00705     hal_clear_pll_lock_flag();
00706     delay_us(TIME_PLL_LOCK);
00707 
00708     radio_status_t pll_calibration_status = RADIO_TIMED_OUT;
00709 
00710     if (hal_get_pll_lock_flag() > 0){
00711         if (hal_subregister_read(SR_PLL_DCU_START) == PLL_DCU_CALIBRATION_DONE){
00712             if (hal_subregister_read(SR_PLL_CF_START) == PLL_CF_CALIBRATION_DONE){
00713                 pll_calibration_status = RADIO_SUCCESS;
00714             }
00715         }
00716     }
00717 
00718     return pll_calibration_status;
00719 }
00720 
00721 /*----------------------------------------------------------------------------*/
00722 /** \brief  This function return the Radio Transceivers current state.
00723  *
00724  *  \retval     P_ON               When the external supply voltage (VDD) is
00725  *                                 first supplied to the transceiver IC, the
00726  *                                 system is in the P_ON (Poweron) mode.
00727  *  \retval     BUSY_RX            The radio transceiver is busy receiving a
00728  *                                 frame.
00729  *  \retval     BUSY_TX            The radio transceiver is busy transmitting a
00730  *                                 frame.
00731  *  \retval     RX_ON              The RX_ON mode enables the analog and digital
00732  *                                 receiver blocks and the PLL frequency
00733  *                                 synthesizer.
00734  *  \retval     TRX_OFF            In this mode, the SPI module and crystal
00735  *                                 oscillator are active.
00736  *  \retval     PLL_ON             Entering the PLL_ON mode from TRX_OFF will
00737  *                                 first enable the analog voltage regulator. The
00738  *                                 transceiver is ready to transmit a frame.
00739  *  \retval     BUSY_RX_AACK       The radio was in RX_AACK_ON mode and received
00740  *                                 the Start of Frame Delimiter (SFD). State
00741  *                                 transition to BUSY_RX_AACK is done if the SFD
00742  *                                 is valid.
00743  *  \retval     BUSY_TX_ARET       The radio transceiver is busy handling the
00744  *                                 auto retry mechanism.
00745  *  \retval     RX_AACK_ON         The auto acknowledge mode of the radio is
00746  *                                 enabled and it is waiting for an incomming
00747  *                                 frame.
00748  *  \retval     TX_ARET_ON         The auto retry mechanism is enabled and the
00749  *                                 radio transceiver is waiting for the user to
00750  *                                 send the TX_START command.
00751  *  \retval     RX_ON_NOCLK        The radio transceiver is listening for
00752  *                                 incomming frames, but the CLKM is disabled so
00753  *                                 that the controller could be sleeping.
00754  *                                 However, this is only true if the controller
00755  *                                 is run from the clock output of the radio.
00756  *  \retval     RX_AACK_ON_NOCLK   Same as the RX_ON_NOCLK state, but with the
00757  *                                 auto acknowledge module turned on.
00758  *  \retval     BUSY_RX_AACK_NOCLK Same as BUSY_RX_AACK, but the controller
00759  *                                 could be sleeping since the CLKM pin is
00760  *                                 disabled.
00761  *  \retval     STATE_TRANSITION   The radio transceiver's state machine is in
00762  *                                 transition between two states.
00763  */
00764 uint8_t
00765 radio_get_trx_state(void)
00766 {
00767     return hal_subregister_read(SR_TRX_STATUS);
00768 }
00769 
00770 /*----------------------------------------------------------------------------*/
00771 /** \brief  This function checks if the radio transceiver is sleeping.
00772  *
00773  *  \retval     true    The radio transceiver is in SLEEP or one of the *_NOCLK
00774  *                      states.
00775  *  \retval     false   The radio transceiver is not sleeping.
00776  */
00777 bool radio_is_sleeping(void)
00778 {
00779     bool sleeping = false;
00780 
00781     /* The radio transceiver will be at SLEEP or one of the *_NOCLK states only if */
00782     /* the SLP_TR pin is high. */
00783     if (hal_get_slptr() != 0){
00784         sleeping = true;
00785     }
00786 
00787     return sleeping;
00788 }
00789 
00790 /*----------------------------------------------------------------------------*/
00791 /** \brief  This function will change the current state of the radio
00792  *          transceiver's internal state machine.
00793  *
00794  *  \param     new_state        Here is a list of possible states:
00795  *             - RX_ON        Requested transition to RX_ON state.
00796  *             - TRX_OFF      Requested transition to TRX_OFF state.
00797  *             - PLL_ON       Requested transition to PLL_ON state.
00798  *             - RX_AACK_ON   Requested transition to RX_AACK_ON state.
00799  *             - TX_ARET_ON   Requested transition to TX_ARET_ON state.
00800  *
00801  *  \retval    RADIO_SUCCESS          Requested state transition completed
00802  *                                  successfully.
00803  *  \retval    RADIO_INVALID_ARGUMENT Supplied function parameter out of bounds.
00804  *  \retval    RADIO_WRONG_STATE      Illegal state to do transition from.
00805  *  \retval    RADIO_BUSY_STATE       The radio transceiver is busy.
00806  *  \retval    RADIO_TIMED_OUT        The state transition could not be completed
00807  *                                  within resonable time.
00808  */
00809 radio_status_t
00810 radio_set_trx_state(uint8_t new_state)
00811 {
00812     uint8_t original_state;
00813 
00814     /*Check function paramter and current state of the radio transceiver.*/
00815     if (!((new_state == TRX_OFF)    ||
00816           (new_state == RX_ON)      ||
00817           (new_state == PLL_ON)     ||
00818           (new_state == RX_AACK_ON) ||
00819           (new_state == TX_ARET_ON))){
00820         return RADIO_INVALID_ARGUMENT;
00821     }
00822 
00823     if (radio_is_sleeping() == true){
00824         return RADIO_WRONG_STATE;
00825     }
00826 
00827     // Wait for radio to finish previous operation
00828     for(;;)
00829     {
00830         original_state = radio_get_trx_state();
00831         if (original_state != BUSY_TX_ARET &&
00832             original_state != BUSY_RX_AACK &&
00833             original_state != BUSY_RX && 
00834             original_state != BUSY_TX)
00835             break;
00836     }
00837 
00838     if (new_state == original_state){
00839         return RADIO_SUCCESS;
00840     }
00841 
00842 
00843     /* At this point it is clear that the requested new_state is: */
00844     /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON or TX_ARET_ON. */
00845 
00846     /* The radio transceiver can be in one of the following states: */
00847     /* TRX_OFF, RX_ON, PLL_ON, RX_AACK_ON, TX_ARET_ON. */
00848     if(new_state == TRX_OFF){
00849         radio_reset_state_machine(); /* Go to TRX_OFF from any state. */
00850     } else {
00851         /* It is not allowed to go from RX_AACK_ON or TX_AACK_ON and directly to */
00852         /* TX_AACK_ON or RX_AACK_ON respectively. Need to go via RX_ON or PLL_ON. */
00853         if ((new_state == TX_ARET_ON) &&
00854             (original_state == RX_AACK_ON)){
00855             /* First do intermediate state transition to PLL_ON, then to TX_ARET_ON. */
00856             /* The final state transition to TX_ARET_ON is handled after the if-else if. */
00857             hal_subregister_write(SR_TRX_CMD, PLL_ON);
00858             delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE);
00859         } else if ((new_state == RX_AACK_ON) &&
00860                  (original_state == TX_ARET_ON)){
00861             /* First do intermediate state transition to RX_ON, then to RX_AACK_ON. */
00862             /* The final state transition to RX_AACK_ON is handled after the if-else if. */
00863             hal_subregister_write(SR_TRX_CMD, RX_ON);
00864             delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE);
00865         }
00866 
00867         /* Any other state transition can be done directly. */
00868         hal_subregister_write(SR_TRX_CMD, new_state);
00869 
00870         /* When the PLL is active most states can be reached in 1us. However, from */
00871         /* TRX_OFF the PLL needs time to activate. */
00872         if (original_state == TRX_OFF){
00873             delay_us(TIME_TRX_OFF_TO_PLL_ACTIVE);
00874         } else {
00875             delay_us(TIME_STATE_TRANSITION_PLL_ACTIVE);
00876         }
00877     } /*  end: if(new_state == TRX_OFF) ... */
00878 
00879     /*Verify state transition.*/
00880     radio_status_t set_state_status = RADIO_TIMED_OUT;
00881 
00882     if (radio_get_trx_state() == new_state){
00883         set_state_status = RADIO_SUCCESS;
00884         /*  set rx_mode flag based on mode we're changing to */
00885         if (new_state == RX_ON ||
00886             new_state == RX_AACK_ON){
00887             rx_mode = true;
00888         } else {
00889             rx_mode = false;
00890     }
00891     }
00892 
00893     return set_state_status;
00894 }
00895 
00896 /*----------------------------------------------------------------------------*/
00897 /** \brief  This function will put the radio transceiver to sleep.
00898  *
00899  *  \retval    RADIO_SUCCESS          Sleep mode entered successfully.
00900  *  \retval    RADIO_TIMED_OUT        The transition to TRX_OFF took too long.
00901  */
00902 radio_status_t
00903 radio_enter_sleep_mode(void)
00904 {
00905     if (radio_is_sleeping() == true){
00906         return RADIO_SUCCESS;
00907     }
00908 
00909     radio_reset_state_machine(); /* Force the device into TRX_OFF. */
00910 
00911     radio_status_t enter_sleep_status = RADIO_TIMED_OUT;
00912 
00913     if (radio_get_trx_state() == TRX_OFF){
00914         /* Enter Sleep. */
00915         hal_set_slptr_high();
00916         enter_sleep_status = RADIO_SUCCESS;
00917 #if RADIOSTATS
00918         RF230_radio_on = 0;
00919 #endif
00920     }
00921 
00922     return enter_sleep_status;
00923 }
00924 
00925 /*----------------------------------------------------------------------------*/
00926 /** \brief  This function will take the radio transceiver from sleep mode and
00927  *          put it into the TRX_OFF state.
00928  *
00929  *  \retval    RADIO_SUCCESS          Left sleep mode and entered TRX_OFF state.
00930  *  \retval    RADIO_TIMED_OUT        Transition to TRX_OFF state timed out.
00931  */
00932 radio_status_t
00933 radio_leave_sleep_mode(void)
00934 {
00935     /* Check if the radio transceiver is actually sleeping. */
00936     if (radio_is_sleeping() == false){
00937         return RADIO_SUCCESS;
00938     }
00939 
00940     hal_set_slptr_low();
00941     delay_us(TIME_SLEEP_TO_TRX_OFF);
00942 
00943     radio_status_t leave_sleep_status = RADIO_TIMED_OUT;
00944 
00945     /* Ensure that the radio transceiver is in the TRX_OFF state. */
00946     if (radio_get_trx_state() == TRX_OFF){
00947         leave_sleep_status = RADIO_SUCCESS;
00948 #if RADIOSTATS
00949         RF230_radio_on = 1;
00950 #endif
00951     }
00952 
00953     return leave_sleep_status;
00954 }
00955 
00956 /*----------------------------------------------------------------------------*/
00957 /** \brief  This function will reset the state machine (to TRX_OFF) from any of
00958  *          its states, except for the SLEEP state.
00959  */
00960 void
00961 radio_reset_state_machine(void)
00962 {
00963     hal_set_slptr_low();
00964     delay_us(TIME_NOCLK_TO_WAKE);
00965     hal_subregister_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF);
00966     delay_us(TIME_CMD_FORCE_TRX_OFF);
00967 }
00968 
00969 /*----------------------------------------------------------------------------*/
00970 /** \brief  This function will reset all the registers and the state machine of
00971  *          the radio transceiver.
00972  */
00973 void
00974 radio_reset_trx(void)
00975 {
00976     hal_set_rst_low();
00977     hal_set_slptr_low();
00978     delay_us(TIME_RESET);
00979     hal_set_rst_high();
00980 }
00981 
00982 /*----------------------------------------------------------------------------*/
00983 /** \brief  This function will enable or disable automatic CRC during frame
00984  *          transmission.
00985  *
00986  *  \param  auto_crc_on If this parameter equals true auto CRC will be used for
00987  *                      all frames to be transmitted. The framelength must be
00988  *                      increased by two bytes (16 bit CRC). If the parameter equals
00989  *                      false, the automatic CRC will be disabled.
00990  */
00991 void
00992 radio_use_auto_tx_crc(bool auto_crc_on)
00993 {
00994     if (auto_crc_on == true){
00995         hal_subregister_write(SR_TX_AUTO_CRC_ON, 1);
00996     } else {
00997         hal_subregister_write(SR_TX_AUTO_CRC_ON, 0);
00998     }
00999 }
01000 
01001 /*----------------------------------------------------------------------------*/
01002 /** \brief  This function will download a frame to the radio transceiver's
01003  *          transmit buffer and send it.
01004  *
01005  *  \param  data_length Length of the frame to be transmitted. 1 to 128 bytes are the valid lengths.
01006  *  \param  *data   Pointer to the data to transmit
01007  *
01008  *  \retval RADIO_SUCCESS Frame downloaded and sent successfully.
01009  *  \retval RADIO_INVALID_ARGUMENT If the dataLength is 0 byte or more than 127
01010  *                               bytes the frame will not be sent.
01011  *  \retval RADIO_WRONG_STATE It is only possible to use this function in the
01012  *                          PLL_ON and TX_ARET_ON state. If any other state is
01013  *                          detected this error message will be returned.
01014  */
01015 radio_status_t
01016 radio_send_data(uint8_t data_length, uint8_t *data)
01017 {
01018     /*Check function parameters and current state.*/
01019     if (data_length > RF230_MAX_TX_FRAME_LENGTH){
01020 #if RADIOSTATS
01021         RF230_sendfail++;
01022 #endif
01023         return RADIO_INVALID_ARGUMENT;
01024     }
01025 
01026      /* If we are busy, return */
01027         if ((radio_get_trx_state() == BUSY_TX) || (radio_get_trx_state() == BUSY_TX_ARET) )
01028         {
01029 #if RADIOSTATS
01030         RF230_sendfail++;
01031 #endif
01032         return RADIO_WRONG_STATE;
01033         }
01034 
01035     radio_set_trx_state(TRX_OFF);
01036     radio_set_trx_state(TX_ARET_ON);
01037 
01038     /*Do frame transmission.*/
01039     /* Toggle the SLP_TR pin to initiate the frame transmission. */
01040     hal_set_slptr_high();
01041     hal_set_slptr_low();
01042 
01043     hal_frame_write(data, data_length); /* Then write data to the frame buffer. */
01044 #if RADIOSTATS
01045     RF230_sendpackets++;
01046 #endif
01047     return RADIO_SUCCESS;
01048 }
01049 
01050 /*----------------------------------------------------------------------------*/
01051 /** \brief  This function will read the I_AM_COORD sub register.
01052  *
01053  *  \retval 0 Not coordinator.
01054  *  \retval 1 Coordinator role enabled.
01055  */
01056 uint8_t
01057 radio_get_device_role(void)
01058 {
01059     return hal_subregister_read(SR_I_AM_COORD);
01060 }
01061 
01062 /*----------------------------------------------------------------------------*/
01063 /** \brief  This function will set the I_AM_COORD sub register.
01064  *
01065  *  \param[in] i_am_coordinator If this parameter is true, the associated
01066  *                              coordinator role will be enabled in the radio
01067  *                              transceiver's address filter.
01068  *                              False disables the same feature.
01069  */
01070 void
01071 radio_set_device_role(bool i_am_coordinator)
01072 {
01073     hal_subregister_write(SR_I_AM_COORD, i_am_coordinator);
01074 }
01075 
01076 /*----------------------------------------------------------------------------*/
01077 /** \brief  This function will return the PANID used by the address filter.
01078  *
01079  *  \retval Any value from 0 to 0xFFFF.
01080  */
01081 uint16_t
01082 radio_get_pan_id(void)
01083 {
01084 
01085     uint8_t pan_id_15_8 = hal_register_read(RG_PAN_ID_1); /*  Read pan_id_15_8. */
01086     uint8_t pan_id_7_0 = hal_register_read(RG_PAN_ID_0); /*  Read pan_id_7_0. */
01087 
01088     uint16_t pan_id = ((uint16_t)(pan_id_15_8 << 8)) | pan_id_7_0;
01089 
01090     return pan_id;
01091 }
01092 
01093 /*----------------------------------------------------------------------------*/
01094 /** \brief  This function will set the PANID used by the address filter.
01095  *
01096  *  \param  new_pan_id Desired PANID. Can be any value from 0x0000 to 0xFFFF
01097  */
01098 void
01099 radio_set_pan_id(uint16_t new_pan_id)
01100 {
01101 
01102     uint8_t pan_byte = new_pan_id & 0xFF; /*  Extract new_pan_id_7_0. */
01103     hal_register_write(RG_PAN_ID_0, pan_byte);
01104 
01105     pan_byte = (new_pan_id >> 8*1) & 0xFF;  /*  Extract new_pan_id_15_8. */
01106     hal_register_write(RG_PAN_ID_1, pan_byte);
01107 }
01108 
01109 /*----------------------------------------------------------------------------*/
01110 /** \brief  This function will return the current short address used by the
01111  *          address filter.
01112  *
01113  *  \retval Any value from 0x0000 to 0xFFFF
01114  */
01115 uint16_t
01116 radio_get_short_address(void)
01117 {
01118 
01119     uint8_t short_address_15_8 = hal_register_read(RG_SHORT_ADDR_1); /*  Read short_address_15_8. */
01120     uint8_t short_address_7_0  = hal_register_read(RG_SHORT_ADDR_1); /*  Read short_address_7_0. */
01121 
01122     uint16_t short_address = ((uint16_t)(short_address_15_8 << 8)) | short_address_7_0;
01123 
01124     return short_address;
01125 }
01126 
01127 /*----------------------------------------------------------------------------*/
01128 /** \brief  This function will set the short address used by the address filter.
01129  *
01130  *  \param  new_short_address Short address to be used by the address filter.
01131  */
01132 void
01133 radio_set_short_address(uint16_t new_short_address)
01134 {
01135 
01136     uint8_t short_address_byte = new_short_address & 0xFF; /*  Extract short_address_7_0. */
01137     hal_register_write(RG_SHORT_ADDR_0, short_address_byte);
01138 
01139     short_address_byte = (new_short_address >> 8*1) & 0xFF; /*  Extract short_address_15_8. */
01140     hal_register_write(RG_SHORT_ADDR_1, short_address_byte);
01141 }
01142 
01143 /*----------------------------------------------------------------------------*/
01144 /** \brief  This function will read the extended address used by the address
01145  *          filter.
01146  *
01147  *  \note In this function a pointer is used to convey the 64-bit result, since
01148  *        it is very inefficient to use the stack for this.
01149  *
01150  *  \return Extended Address, any 64-bit value.
01151  */
01152 void
01153 radio_get_extended_address(uint8_t *extended_address)
01154 {
01155     *extended_address++ = hal_register_read(RG_IEEE_ADDR_0);
01156     *extended_address++ = hal_register_read(RG_IEEE_ADDR_1);
01157     *extended_address++ = hal_register_read(RG_IEEE_ADDR_2);
01158     *extended_address++ = hal_register_read(RG_IEEE_ADDR_3);
01159     *extended_address++ = hal_register_read(RG_IEEE_ADDR_4);
01160     *extended_address++ = hal_register_read(RG_IEEE_ADDR_5);
01161     *extended_address++ = hal_register_read(RG_IEEE_ADDR_6);
01162     *extended_address   = hal_register_read(RG_IEEE_ADDR_7);
01163 }
01164 
01165 /*----------------------------------------------------------------------------*/
01166 /** \brief  This function will set a new extended address to be used by the
01167  *          address filter.
01168  *
01169  *  \param  extended_address Extended address to be used by the address filter.
01170  */
01171 void
01172 radio_set_extended_address(uint8_t *extended_address)
01173 {
01174     hal_register_write(RG_IEEE_ADDR_0, *extended_address++);
01175     hal_register_write(RG_IEEE_ADDR_1, *extended_address++);
01176     hal_register_write(RG_IEEE_ADDR_2, *extended_address++);
01177     hal_register_write(RG_IEEE_ADDR_3, *extended_address++);
01178     hal_register_write(RG_IEEE_ADDR_4, *extended_address++);
01179     hal_register_write(RG_IEEE_ADDR_5, *extended_address++);
01180     hal_register_write(RG_IEEE_ADDR_6, *extended_address++);
01181     hal_register_write(RG_IEEE_ADDR_7, *extended_address++);
01182 }
01183 
01184 /*----------------------------------------------------------------------------*/
01185 /** \brief  This function will configure the CSMA algorithm used by the radio
01186  *          transceiver when transmitting data from TX_ARET_ON state.
01187  *
01188  *  \param  seed0 Lower 8 bits of the seed used for the random number generator
01189  *                in the CSMA algorithm. Value range: 0 to 255.
01190  *  \param  be_csma_seed1 Is a combined argument of the MIN_BE, MAX_CSMA_RETRIES
01191  *                        and SEED1 variables:
01192  *                        -# MIN_BE: Bit[7:6] Minimum back-off exponent in the
01193  *                           CSMA/CA algorithm.
01194  *                        -# MAX_CSMA_RETRIES: Bit[5:3] Number of retries in
01195  *                          TX_ARET_ON mode to repeat the CSMA/CA procedures
01196  *                          before the ARET procedure gives up.
01197  *                        -# SEED1: Bits[2:0] Higher 3 bits of CSMA_SEED, bits[10:8]
01198  *                           Seed for the random number generator in the
01199  *                           CSMA/CA algorithm.
01200  *  \retval RADIO_SUCCESS The CSMA algorithm was configured successfully.
01201  *  \retval RADIO_WRONG_STATE This function should not be called in the
01202  *                          SLEEP state.
01203  */
01204 radio_status_t
01205 radio_configure_csma(uint8_t seed0, uint8_t be_csma_seed1)
01206 {
01207 
01208     /*Check state.*/
01209     if (radio_is_sleeping() == true){
01210         return RADIO_WRONG_STATE;
01211     }
01212 
01213     /*Extract parameters, and configure the CSMA-CA algorithm.*/
01214     uint8_t back_off_exponent = (be_csma_seed1 & 0xC0) >> 6;
01215     uint8_t csma_retries      = (be_csma_seed1 & 0x38) >> 3;
01216     uint8_t seed1             = (be_csma_seed1 & 0x07);
01217 
01218     hal_subregister_write(SR_MAX_FRAME_RETRIES, 0); /* AT86RF230 rev A errata. */
01219     hal_subregister_write(SR_MAX_CSMA_RETRIES, csma_retries);
01220     hal_subregister_write(SR_MIN_BE, back_off_exponent);
01221     hal_register_write(RG_CSMA_SEED_0, seed0);
01222     hal_subregister_write(SR_CSMA_SEED_1, seed1);
01223 
01224     return RADIO_SUCCESS;
01225 }
01226 
01227 /*----------------------------------------------------------------------------*/
01228 /**
01229     \brief Calibrate the internal RC oscillator
01230 
01231     This function calibrates the internal RC oscillator, based
01232     on the 1 MHz clock supplied by the AT86RF2xx. In order to
01233     verify the calibration result you can program the CKOUT fuse
01234     and monitor the CPU clock on an I/O pin.
01235 
01236     \return TRUE if calibrate passed; FALSE if calibrate failed.
01237 */
01238 bool
01239 calibrate_rc_osc_clkm(void)
01240 {
01241         bool success = false;
01242 
01243     /*  Use the 1 MHz CLK_M from the AT86RF230. */
01244     uint16_t temp, counter;
01245     uint8_t osccal_saved;
01246     uint8_t tccr2b, tccr1b, tccr1a;
01247 
01248     /*  in the following line, 1000000ULL represents the 1MHz input signal */
01249     /*  from the radio.  265 is the number of counts to overflow 8-bit */
01250     /*  timer 2.  32 is the divide by 32 prescaler for timer 1.  F_CPU is */
01251     /*  the main clock frequency. */
01252 #define TARGETVAL ((1000000ULL * 256 * 32) / F_CPU)
01253 
01254 
01255         osccal_saved = OSCCAL;
01256         cli();
01257 
01258         radio_set_clock_speed(true, CLKM_1MHz);
01259 
01260     /*  Save current values of timer status. */
01261         tccr2b = TCCR2B;
01262         tccr1b = TCCR1B;
01263         tccr1a = TCCR1A;
01264 
01265     /*  Stop timers 1 and 2. */
01266     /*  Set timer 1 to normal mode (no CTC, no PWM, just count). */
01267         TCCR2B = 0;
01268         TCCR1B = 0;
01269         TCCR1A = 0;
01270 
01271     for (counter = 0; counter < 1000;  counter++){
01272         /*  Delete pending timer 1 and 2 interrupts, and clear the */
01273         /*  counters. */
01274             TIFR1 = 0xFF;
01275             TIFR2 = 0xFF;
01276             TCNT2 = 0;
01277             TCNT1 = 0;
01278         /*  Timer 2 driven from clock divided by 32 */
01279             TCCR2B = (1 << CS21) | (1 << CS20);
01280         /*  Timer 1 driven with external clock */
01281             TCCR1B = (1 << CS12) | (1 << CS11);
01282 
01283         /*  Wait for timer 2 to overflow. */
01284         while (!(TIFR2 & (1 << TOV2))){
01285                 ;
01286         }
01287 
01288         /*  Stop timer 1.  Now, TCNT1 contains the number of CPU cycles */
01289         /*  counted while timer 2 was counting */
01290             TCCR1B = 0;
01291             TCCR2B = 0;
01292 
01293             temp = TCNT1;
01294 
01295         if (temp < (uint16_t)(0.995 * TARGETVAL)){
01296             /*  Too fast, slow down */
01297                 OSCCAL--;
01298         } else if (temp > (uint16_t)(1.005 * TARGETVAL)){
01299             /*  Too slow, speed up */
01300                 OSCCAL++;
01301         } else {
01302             /*  We are within +/- 0.5 % of our target frequency, so we're */
01303             /*  done. */
01304                 success = true;
01305                 break;
01306             }
01307         }
01308 
01309         radio_set_clock_speed(true, CLKM_DISABLED);
01310 
01311     /*  restore timer status regs */
01312         TCCR2B = tccr2b;
01313         TCCR1B = tccr1b;
01314         TCCR1A = tccr1a;
01315     if (!success){
01316         /*  We failed, therefore restore previous OSCCAL value. */
01317             OSCCAL = osccal_saved;
01318         }
01319 
01320         return success;
01321 }
01322 
01323 /*----------------------------------------------------------------------------*/
01324 /**
01325     \brief Calibrate the internal RC oscillator
01326 
01327     This function calibrates the internal RC oscillator, based
01328     on an external 32KHz crystal connected to TIMER2. In order to
01329     verify the calibration result you can program the CKOUT fuse
01330     and monitor the CPU clock on an I/O pin.
01331 */
01332 void
01333 calibrate_rc_osc_32k(void)
01334 {
01335     /* Calibrate RC Oscillator: The calibration routine is done by clocking TIMER2
01336      * from the external 32kHz crystal while running an internal timer simultaneously.
01337      * The internal timer will be clocked at the same speed as the internal RC
01338      * oscillator, while TIMER2 is running at 32768 Hz. This way it is not necessary
01339      * to use a timed loop, and keep track cycles in timed loop vs. optimization
01340      * and compiler.
01341      */
01342     uint8_t osccal_original = OSCCAL;
01343     volatile uint16_t temp;
01344         
01345     /* This is bad practice, but seems to work. */
01346     OSCCAL = 0x80;
01347 
01348 
01349   //    PRR0 &= ~((1 << PRTIM2)|(1 << PRTIM1)); /*  Enable Timer 1 and 2 */
01350 
01351     TIMSK2 = 0x00; /*  Disable Timer/Counter 2 interrupts. */
01352     TIMSK1 = 0x00; /*  Disable Timer/Counter 1 interrupts. */
01353 
01354     /* Enable TIMER/COUNTER 2 to be clocked from the external 32kHz clock crystal.
01355      * Then wait for the timer to become stable before doing any calibration.
01356      */
01357     ASSR |= (1 << AS2);
01358     while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; }
01359     TCCR2B = 1 << CS20;   /* run timer 2 at divide by 1 (32KHz) */
01360 
01361     AVR_ENTER_CRITICAL_REGION();
01362 
01363     uint8_t counter = 128;
01364     bool cal_ok = false;
01365     do{
01366         /* wait for timer to be ready for updated config */
01367         TCCR1B = 1 << CS10;
01368 
01369         while (ASSR & ((1 << TCN2UB)|(1 << OCR2AUB)|(1 << TCR2AUB)|(1 << TCR2BUB))) { ; }
01370 
01371         TCNT2 = 0x80;
01372         TCNT1 = 0;
01373 
01374         TIFR2 = 0xFF;
01375 
01376         /* Wait for TIMER/COUNTER 2 to overflow. Stop TIMER/COUNTER 1 and 2, and
01377          * read the counter value of TIMER/COUNTER 1. It will now contain the
01378          * number of cpu cycles elapsed within the period.
01379          */
01380         while (!(TIFR2 & (1 << TOV2))){
01381             ;
01382             }
01383         temp = TCNT1;
01384 
01385         TCCR1B = 0;
01386 
01387 #define cal_upper (31250*1.05) // 32812 = 0x802c
01388 #define cal_lower (31250*0.95) // 29687 = 0x73f7
01389         /* Iteratively reduce the error to be within limits */
01390         if (temp < cal_lower) {
01391             /* Too slow. Put the hammer down. */
01392             OSCCAL++;
01393         } else if (temp > cal_upper) {
01394             /* Too fast, retard. */
01395             OSCCAL--;
01396         } else {
01397             /* The CPU clock frequency is now within +/- 0.5% of the target value. */
01398             cal_ok = true;
01399         }
01400 
01401         counter--;
01402     } while ((counter != 0) && (false == cal_ok));
01403 
01404     if (true != cal_ok) {
01405         /* We failed, therefore restore previous OSCCAL value. */
01406         OSCCAL = osccal_original;
01407     }
01408 
01409     TCCR2B = 0;
01410 
01411     ASSR &= ~(1 << AS2);
01412 
01413     /* Disable both timers again to save power. */
01414     //    PRR0 |= (1 << PRTIM2);/* |(1 << PRTIM1); */
01415 
01416     AVR_LEAVE_CRITICAL_REGION();
01417 }
01418 
01419 /** @} */
01420 /** @} */
01421 /*EOF*/

Generated on Mon Apr 11 14:23:37 2011 for Contiki 2.5 by  doxygen 1.6.1