Contiki 2.6

hal.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  *
00006  *      Colin O'Flynn coflynn@newae.com
00007  *      Eric Gnoske egnoske@gmail.com
00008  *      Blake Leverett bleverett@gmail.com
00009  *      Mike Vidales mavida404@gmail.com
00010  *      Kevin Brown kbrown3@uccs.edu
00011  *      Nate Bohlmann nate@elfwerks.com
00012  *
00013  *   All rights reserved.
00014  *
00015  *   Redistribution and use in source and binary forms, with or without
00016  *   modification, are permitted provided that the following conditions are met:
00017  *
00018  *   * Redistributions of source code must retain the above copyright
00019  *     notice, this list of conditions and the following disclaimer.
00020  *   * Redistributions in binary form must reproduce the above copyright
00021  *     notice, this list of conditions and the following disclaimer in
00022  *     the documentation and/or other materials provided with the
00023  *     distribution.
00024  *   * Neither the name of the copyright holders nor the names of
00025  *     contributors may be used to endorse or promote products derived
00026  *     from this software without specific prior written permission.
00027  *
00028  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00029  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00030  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00031  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00032  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00033  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00034  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00035  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00036  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00037  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00038  *  POSSIBILITY OF SUCH DAMAGE.
00039  *
00040  *  $Id: hal.c,v 1.2 2008/10/14 18:37:28 c_oflynn Exp $
00041 */
00042 
00043 /**
00044  *   \addtogroup wireless
00045  *  @{
00046 */
00047 
00048 /**
00049  *   \defgroup hal RF230 hardware level drivers
00050  *   @{
00051  */
00052 
00053 /**
00054  *  \file
00055  *  This file contains low-level radio driver code.
00056  */
00057 
00058 
00059 
00060 /*============================ INCLUDE =======================================*/
00061 #include <stdlib.h>
00062 
00063 #include "hal.h"
00064 #include "at86rf230_registermap.h"
00065 /*============================ MACROS ========================================*/
00066 
00067 /*
00068  * Macros defined for the radio transceiver's access modes.
00069  *
00070  * These functions are implemented as macros since they are used very often.
00071  */
00072 #define HAL_DUMMY_READ         (0x00) /**<  Dummy value for the SPI. */
00073 
00074 #define HAL_TRX_CMD_RW         (0xC0) /**<  Register Write (short mode). */
00075 #define HAL_TRX_CMD_RR         (0x80) /**<  Register Read (short mode). */
00076 #define HAL_TRX_CMD_FW         (0x60) /**<  Frame Transmit Mode (long mode). */
00077 #define HAL_TRX_CMD_FR         (0x20) /**<  Frame Receive Mode (long mode). */
00078 #define HAL_TRX_CMD_SW         (0x40) /**<  SRAM Write. */
00079 #define HAL_TRX_CMD_SR         (0x00) /**<  SRAM Read. */
00080 #define HAL_TRX_CMD_RADDRM     (0x7F) /**<  Register Address Mask. */
00081 
00082 #define HAL_CALCULATED_CRC_OK   (0) /**<  CRC calculated over the frame including the CRC field should be 0. */
00083 /*============================ TYPDEFS =======================================*/
00084 /*============================ VARIABLES =====================================*/
00085 /** \brief This is a file internal variable that contains the 16 MSB of the
00086  *         system time.
00087  *
00088  *         The system time (32-bit) is the current time in microseconds. For the
00089  *         AVR microcontroller implementation this is solved by using a 16-bit
00090  *         timer (Timer1) with a clock frequency of 1MHz. The hal_system_time is
00091  *         incremented when the 16-bit timer overflows, representing the 16 MSB.
00092  *         The timer value it self (TCNT1) is then the 16 LSB.
00093  *
00094  *  \see hal_get_system_time
00095  */
00096 static uint16_t hal_system_time = 0;
00097 
00098 /*Flag section.*/
00099 static uint8_t volatile hal_bat_low_flag; /**<  BAT_LOW flag. */
00100 static uint8_t volatile hal_pll_lock_flag;   /**<  PLL_LOCK flag. */
00101 
00102 /*Callbacks.*/
00103 
00104 /** \brief This function is called when a rx_start interrupt is signaled.
00105  *
00106  *         If this function pointer is set to something else than NULL, it will
00107  *         be called when a RX_START event is signaled. The function takes two
00108  *         parameters: timestamp in IEEE 802.15.4 symbols (16 us resolution) and
00109  *         frame length. The event handler will be called in the interrupt domain,
00110  *         so the function must be kept short and not be blocking! Otherwise the
00111  *         system performance will be greatly degraded.
00112  *
00113  *  \see hal_set_rx_start_event_handler
00114  */
00115 static hal_rx_start_isr_event_handler_t rx_start_callback;
00116 
00117 /** \brief This function is called when a trx_end interrupt is signaled.
00118  *
00119  *         If this function pointer is set to something else than NULL, it will
00120  *         be called when a TRX_END event is signaled. The function takes one
00121  *         parameter: timestamp in IEEE 802.15.4 symbols (16 us resolution).
00122  *         The event handler will be called in the interrupt domain,
00123  *         so the function must not block!
00124  *
00125  *  \see hal_set_trx_end_event_handler
00126  */
00127 static hal_trx_end_isr_event_handler_t trx_end_callback;
00128 /*============================ PROTOTYPES ====================================*/
00129 /*============================ IMPLEMENTATION ================================*/
00130 
00131 /** \brief  This function initializes the Hardware Abstraction Layer.
00132  */
00133 void
00134 hal_init(void)
00135 {
00136     /*Reset variables used in file.*/
00137     hal_system_time = 0;
00138     hal_reset_flags();
00139 
00140     /*IO Specific Initialization.*/
00141     DDR_SLP_TR |= (1 << SLP_TR); /* Enable SLP_TR as output. */
00142     DDR_RST    |= (1 << RST);    /* Enable RST as output. */
00143 
00144     /*SPI Specific Initialization.*/
00145     /* Set SS, CLK and MOSI as output. */
00146     HAL_DDR_SPI  |= (1 << HAL_DD_SS) | (1 << HAL_DD_SCK) | (1 << HAL_DD_MOSI);
00147     HAL_PORT_SPI |= (1 << HAL_DD_SS) | (1 << HAL_DD_SCK); /* Set SS and CLK high */
00148     /* Run SPI at max speed */
00149     SPCR         = (1 << SPE) | (1 << MSTR); /* Enable SPI module and master operation. */
00150     SPSR         = (1 << SPI2X); /* Enable doubled SPI speed in master mode. */
00151 
00152     /*TIMER1 Specific Initialization.*/
00153     TCCR1B = HAL_TCCR1B_CONFIG;       /* Set clock prescaler */
00154     TIFR1 |= (1 << ICF1);             /* Clear Input Capture Flag. */
00155     HAL_ENABLE_OVERFLOW_INTERRUPT(); /* Enable Timer1 overflow interrupt. */
00156     hal_enable_trx_interrupt();    /* Enable interrupts from the radio transceiver. */
00157 }
00158 
00159 /*----------------------------------------------------------------------------*/
00160 /** \brief  This function reset the interrupt flags and interrupt event handlers
00161  *          (Callbacks) to their default value.
00162  */
00163 void
00164 hal_reset_flags(void)
00165 {
00166     AVR_ENTER_CRITICAL_REGION();
00167 
00168     /* Reset Flags. */
00169     hal_bat_low_flag     = 0;
00170     hal_pll_lock_flag    = 0;
00171 
00172     /* Reset Associated Event Handlers. */
00173     rx_start_callback = NULL;
00174     trx_end_callback  = NULL;
00175 
00176     AVR_LEAVE_CRITICAL_REGION();
00177 }
00178 
00179 /*----------------------------------------------------------------------------*/
00180 /** \brief  This function returns the current value of the BAT_LOW flag.
00181  *
00182  *  The BAT_LOW flag is incremented each time a BAT_LOW event is signaled from the
00183  *  radio transceiver. This way it is possible for the end user to poll the flag
00184  *  for new event occurances.
00185  */
00186 uint8_t
00187 hal_get_bat_low_flag(void)
00188 {
00189     return hal_bat_low_flag;
00190 }
00191 
00192 /*----------------------------------------------------------------------------*/
00193 /** \brief  This function clears the BAT_LOW flag.
00194  */
00195 void
00196 hal_clear_bat_low_flag(void)
00197 {
00198     AVR_ENTER_CRITICAL_REGION();
00199     hal_bat_low_flag = 0;
00200     AVR_LEAVE_CRITICAL_REGION();
00201 }
00202 
00203 /*----------------------------------------------------------------------------*/
00204 /** \brief  This function is used to set new TRX_END event handler, overriding
00205  *          old handler reference.
00206  */
00207 hal_trx_end_isr_event_handler_t
00208 hal_get_trx_end_event_handler(void)
00209 {
00210     return trx_end_callback;
00211 }
00212 
00213 /*----------------------------------------------------------------------------*/
00214 /** \brief  This function is used to set new TRX_END event handler, overriding
00215  *          old handler reference.
00216  */
00217 void
00218 hal_set_trx_end_event_handler(hal_trx_end_isr_event_handler_t trx_end_callback_handle)
00219 {
00220     AVR_ENTER_CRITICAL_REGION();
00221     trx_end_callback = trx_end_callback_handle;
00222     AVR_LEAVE_CRITICAL_REGION();
00223 }
00224 
00225 /*----------------------------------------------------------------------------*/
00226 /** \brief  Remove event handler reference.
00227  */
00228 void
00229 hal_clear_trx_end_event_handler(void)
00230 {
00231     AVR_ENTER_CRITICAL_REGION();
00232     trx_end_callback = NULL;
00233     AVR_LEAVE_CRITICAL_REGION();
00234 }
00235 
00236 /*----------------------------------------------------------------------------*/
00237 /** \brief  This function returns the active RX_START event handler
00238  *
00239  *  \return Current RX_START event handler registered.
00240  */
00241 hal_rx_start_isr_event_handler_t
00242 hal_get_rx_start_event_handler(void)
00243 {
00244     return rx_start_callback;
00245 }
00246 
00247 /*----------------------------------------------------------------------------*/
00248 /** \brief  This function is used to set new RX_START event handler, overriding
00249  *          old handler reference.
00250  */
00251 void
00252 hal_set_rx_start_event_handler(hal_rx_start_isr_event_handler_t rx_start_callback_handle)
00253 {
00254     AVR_ENTER_CRITICAL_REGION();
00255     rx_start_callback = rx_start_callback_handle;
00256     AVR_LEAVE_CRITICAL_REGION();
00257 }
00258 
00259 /*----------------------------------------------------------------------------*/
00260 /** \brief  Remove event handler reference.
00261  */
00262 void
00263 hal_clear_rx_start_event_handler(void)
00264 {
00265     AVR_ENTER_CRITICAL_REGION();
00266     rx_start_callback = NULL;
00267     AVR_LEAVE_CRITICAL_REGION();
00268 }
00269 
00270 /*----------------------------------------------------------------------------*/
00271 /** \brief  This function returns the current value of the PLL_LOCK flag.
00272  *
00273  *  The PLL_LOCK flag is incremented each time a PLL_LOCK event is signaled from the
00274  *  radio transceiver. This way it is possible for the end user to poll the flag
00275  *  for new event occurances.
00276  */
00277 uint8_t
00278 hal_get_pll_lock_flag(void)
00279 {
00280     return hal_pll_lock_flag;
00281 }
00282 
00283 /*----------------------------------------------------------------------------*/
00284 /** \brief  This function clears the PLL_LOCK flag.
00285  */
00286 void
00287 hal_clear_pll_lock_flag(void)
00288 {
00289     AVR_ENTER_CRITICAL_REGION();
00290     hal_pll_lock_flag = 0;
00291     AVR_LEAVE_CRITICAL_REGION();
00292 }
00293 
00294 /*----------------------------------------------------------------------------*/
00295 /** \brief  This function reads data from one of the radio transceiver's registers.
00296  *
00297  *  \param  address Register address to read from. See datasheet for register
00298  *                  map.
00299  *
00300  *  \see Look at the at86rf230_registermap.h file for register address definitions.
00301  *
00302  *  \returns The actual value of the read register.
00303  */
00304 uint8_t
00305 hal_register_read(uint8_t address)
00306 {
00307     /* Add the register read command to the register address. */
00308     address &= HAL_TRX_CMD_RADDRM;
00309     address |= HAL_TRX_CMD_RR;
00310 
00311     uint8_t register_value = 0;
00312 
00313     AVR_ENTER_CRITICAL_REGION();
00314 
00315     HAL_SS_LOW(); /* Start the SPI transaction by pulling the Slave Select low. */
00316 
00317     /*Send Register address and read register content.*/
00318     SPDR = address;
00319     while ((SPSR & (1 << SPIF)) == 0) {;}
00320     register_value = SPDR;
00321 
00322     SPDR = register_value;
00323     while ((SPSR & (1 << SPIF)) == 0) {;}
00324     register_value = SPDR;
00325 
00326     HAL_SS_HIGH(); /* End the transaction by pulling the Slave Select High. */
00327 
00328     AVR_LEAVE_CRITICAL_REGION();
00329 
00330     return register_value;
00331 }
00332 
00333 /*----------------------------------------------------------------------------*/
00334 /** \brief  This function writes a new value to one of the radio transceiver's
00335  *          registers.
00336  *
00337  *  \see Look at the at86rf230_registermap.h file for register address definitions.
00338  *
00339  *  \param  address Address of register to write.
00340  *  \param  value   Value to write.
00341  */
00342 void
00343 hal_register_write(uint8_t address, uint8_t value)
00344 {
00345     /* Add the Register Write command to the address. */
00346     address = HAL_TRX_CMD_RW | (HAL_TRX_CMD_RADDRM & address);
00347 
00348     AVR_ENTER_CRITICAL_REGION();
00349 
00350     HAL_SS_LOW(); /* Start the SPI transaction by pulling the Slave Select low. */
00351 
00352     /*Send Register address and write register content.*/
00353     SPDR = address;
00354     while ((SPSR & (1 << SPIF)) == 0) {;}
00355     uint8_t dummy_read = SPDR;
00356 
00357     SPDR = value;
00358     while ((SPSR & (1 << SPIF)) == 0) {;}
00359     dummy_read = SPDR;
00360 
00361     HAL_SS_HIGH(); /* End the transaction by pulling the Slave Slect High. */
00362 
00363     AVR_LEAVE_CRITICAL_REGION();
00364 }
00365 
00366 /*----------------------------------------------------------------------------*/
00367 /** \brief  This function reads the value of a specific subregister.
00368  *
00369  *  \see Look at the at86rf230_registermap.h file for register and subregister
00370  *       definitions.
00371  *
00372  *  \param  address  Main register's address.
00373  *  \param  mask  Bit mask of the subregister.
00374  *  \param  position   Bit position of the subregister
00375  *  \retval Value of the read subregister.
00376  */
00377 uint8_t
00378 hal_subregister_read(uint8_t address, uint8_t mask, uint8_t position)
00379 {
00380     /* Read current register value and mask out subregister. */
00381     uint8_t register_value = hal_register_read(address);
00382     register_value &= mask;
00383     register_value >>= position; /* Align subregister value. */
00384 
00385     return register_value;
00386 }
00387 
00388 /*----------------------------------------------------------------------------*/
00389 /** \brief  This function writes a new value to one of the radio transceiver's
00390  *          subregisters.
00391  *
00392  *  \see Look at the at86rf230_registermap.h file for register and subregister
00393  *       definitions.
00394  *
00395  *  \param  address  Main register's address.
00396  *  \param  mask  Bit mask of the subregister.
00397  *  \param  position  Bit position of the subregister
00398  *  \param  value  Value to write into the subregister.
00399  */
00400 void
00401 hal_subregister_write(uint8_t address, uint8_t mask, uint8_t position,
00402                             uint8_t value)
00403 {
00404     /* Read current register value and mask area outside the subregister. */
00405     uint8_t register_value = hal_register_read(address);
00406     register_value &= ~mask;
00407 
00408     /* Start preparing the new subregister value. shift in place and mask. */
00409     value <<= position;
00410     value &= mask;
00411 
00412     value |= register_value; /* Set the new subregister value. */
00413 
00414     /* Write the modified register value. */
00415     hal_register_write(address, value);
00416 }
00417 
00418 /*----------------------------------------------------------------------------*/
00419 /** \brief  This function will upload a frame from the radio transceiver's frame
00420  *          buffer.
00421  *
00422  *          If the frame currently available in the radio transceiver's frame buffer
00423  *          is out of the defined bounds. Then the frame length, lqi value and crc
00424  *          be set to zero. This is done to indicate an error.
00425  *
00426  *  \param  rx_frame    Pointer to the data structure where the frame is stored.
00427  *  \param  rx_callback Pointer to callback function for receiving one byte at a time.
00428  */
00429 void
00430 hal_frame_read(hal_rx_frame_t *rx_frame, rx_callback_t rx_callback)
00431 {
00432     uint8_t *rx_data=0;
00433 
00434     /*  check that we have either valid frame pointer or callback pointer */
00435     if (!rx_frame && !rx_callback)
00436         return;
00437 
00438     AVR_ENTER_CRITICAL_REGION();
00439 
00440     HAL_SS_LOW();
00441 
00442     /*Send frame read command.*/
00443     SPDR = HAL_TRX_CMD_FR;
00444     while ((SPSR & (1 << SPIF)) == 0) {;}
00445     uint8_t frame_length = SPDR;
00446 
00447     /*Read frame length.*/
00448     SPDR = frame_length;
00449     while ((SPSR & (1 << SPIF)) == 0) {;}
00450     frame_length = SPDR;
00451 
00452     /*Check for correct frame length.*/
00453     if ((frame_length >= HAL_MIN_FRAME_LENGTH) && (frame_length <= HAL_MAX_FRAME_LENGTH)){
00454         uint16_t crc = 0;
00455         if (rx_frame){
00456             rx_data = (rx_frame->data);
00457             rx_frame->length = frame_length; /* Store frame length. */
00458         } else {
00459             rx_callback(frame_length);
00460         }
00461         /*Upload frame buffer to data pointer. Calculate CRC.*/
00462         SPDR = frame_length;
00463         while ((SPSR & (1 << SPIF)) == 0) {;}
00464 
00465         do{
00466             uint8_t tempData = SPDR;
00467             SPDR = 0;       /*  dummy write */
00468 
00469             if (rx_frame){
00470                 *rx_data++ = tempData;
00471             } else {
00472                 rx_callback(tempData);
00473             }
00474 
00475             crc = _crc_ccitt_update(crc, tempData);
00476 
00477             while ((SPSR & (1 << SPIF)) == 0) {;}
00478 
00479         } while (--frame_length > 0);
00480 
00481         /*Read LQI value for this frame.*/
00482         if (rx_frame){
00483             rx_frame->lqi = SPDR;
00484         } else {
00485             rx_callback(SPDR);
00486         }
00487         
00488         HAL_SS_HIGH();
00489 
00490         /*Check calculated crc, and set crc field in hal_rx_frame_t accordingly.*/
00491         if (rx_frame){
00492             rx_frame->crc = (crc == HAL_CALCULATED_CRC_OK);
00493         } else {
00494             rx_callback(crc != HAL_CALCULATED_CRC_OK);
00495         }
00496     } else {
00497         HAL_SS_HIGH();
00498 
00499         if (rx_frame){
00500             rx_frame->length = 0;
00501             rx_frame->lqi    = 0;
00502             rx_frame->crc    = false;
00503         }
00504     }
00505 
00506     AVR_LEAVE_CRITICAL_REGION();
00507 }
00508 
00509 /*----------------------------------------------------------------------------*/
00510 /** \brief  This function will download a frame to the radio transceiver's frame
00511  *          buffer.
00512  *
00513  *  \param  write_buffer    Pointer to data that is to be written to frame buffer.
00514  *  \param  length          Length of data. The maximum length is 127 bytes.
00515  */
00516 void
00517 hal_frame_write(uint8_t *write_buffer, uint8_t length)
00518 {
00519     length &= HAL_TRX_CMD_RADDRM; /* Truncate length to maximum frame length. */
00520 
00521     AVR_ENTER_CRITICAL_REGION();
00522 
00523     HAL_SS_LOW(); /* Initiate the SPI transaction. */
00524 
00525     /*SEND FRAME WRITE COMMAND AND FRAME LENGTH.*/
00526     SPDR = HAL_TRX_CMD_FW;
00527     while ((SPSR & (1 << SPIF)) == 0) {;}
00528     uint8_t dummy_read = SPDR;
00529 
00530     SPDR = length;
00531     while ((SPSR & (1 << SPIF)) == 0) {;}
00532     dummy_read = SPDR;
00533 
00534     /* Download to the Frame Buffer. */
00535     do{
00536         SPDR = *write_buffer++;
00537         --length;
00538 
00539         while ((SPSR & (1 << SPIF)) == 0) {;}
00540 
00541         dummy_read = SPDR;
00542     } while (length > 0);
00543 
00544     HAL_SS_HIGH(); /* Terminate SPI transaction. */
00545 
00546     AVR_LEAVE_CRITICAL_REGION();
00547 }
00548 
00549 /*----------------------------------------------------------------------------*/
00550 /** \brief Read SRAM
00551  *
00552  * This function reads from the SRAM of the radio transceiver.
00553  *
00554  * \param address Address in the TRX's SRAM where the read burst should start
00555  * \param length Length of the read burst
00556  * \param data Pointer to buffer where data is stored.
00557  */
00558 void
00559 hal_sram_read(uint8_t address, uint8_t length, uint8_t *data)
00560 {
00561     AVR_ENTER_CRITICAL_REGION();
00562 
00563     HAL_SS_LOW(); /* Initiate the SPI transaction. */
00564 
00565     /*Send SRAM read command.*/
00566     SPDR = HAL_TRX_CMD_SR;
00567     while ((SPSR & (1 << SPIF)) == 0) {;}
00568     uint8_t dummy_read = SPDR;
00569 
00570     /*Send address where to start reading.*/
00571     SPDR = address;
00572     while ((SPSR & (1 << SPIF)) == 0) {;}
00573 
00574     dummy_read = SPDR;
00575 
00576     /*Upload the chosen memory area.*/
00577     do{
00578         SPDR = HAL_DUMMY_READ;
00579         while ((SPSR & (1 << SPIF)) == 0) {;}
00580         *data++ = SPDR;
00581     } while (--length > 0);
00582 
00583     HAL_SS_HIGH();
00584 
00585     AVR_LEAVE_CRITICAL_REGION();
00586 }
00587 
00588 /*----------------------------------------------------------------------------*/
00589 /** \brief Write SRAM
00590  *
00591  * This function writes into the SRAM of the radio transceiver.
00592  *
00593  * \param address Address in the TRX's SRAM where the write burst should start
00594  * \param length  Length of the write burst
00595  * \param data    Pointer to an array of bytes that should be written
00596  */
00597 void
00598 hal_sram_write(uint8_t address, uint8_t length, uint8_t *data)
00599 {
00600     AVR_ENTER_CRITICAL_REGION();
00601 
00602     HAL_SS_LOW();
00603 
00604     /*Send SRAM write command.*/
00605     SPDR = HAL_TRX_CMD_SW;
00606     while ((SPSR & (1 << SPIF)) == 0) {;}
00607     uint8_t dummy_read = SPDR;
00608 
00609     /*Send address where to start writing to.*/
00610     SPDR = address;
00611     while ((SPSR & (1 << SPIF)) == 0) {;}
00612     dummy_read = SPDR;
00613 
00614     /*Upload the chosen memory area.*/
00615     do{
00616         SPDR = *data++;
00617         while ((SPSR & (1 << SPIF)) == 0) {;}
00618         dummy_read = SPDR;
00619     } while (--length > 0);
00620 
00621     HAL_SS_HIGH();
00622 
00623     AVR_LEAVE_CRITICAL_REGION();
00624 }
00625 
00626 /*----------------------------------------------------------------------------*/
00627 /* This #if compile switch is used to provide a "standard" function body for the */
00628 /* doxygen documentation. */
00629 #if defined(DOXYGEN)
00630 /** \brief ISR for the radio IRQ line, triggered by the input capture.
00631  *  This is the interrupt service routine for timer1.ICIE1 input capture.
00632  *  It is triggered of a rising edge on the radio transceivers IRQ line.
00633  */
00634 void RADIO_VECT(void);
00635 #else  /* !DOXYGEN */
00636 ISR(RADIO_VECT)
00637 {
00638     /*The following code reads the current system time. This is done by first
00639       reading the hal_system_time and then adding the 16 LSB directly from the
00640       TCNT1 register.
00641      */
00642     uint32_t isr_timestamp = hal_system_time;
00643     isr_timestamp <<= 16;
00644     isr_timestamp |= TCNT1;
00645 
00646     /*Read Interrupt source.*/
00647     HAL_SS_LOW();
00648 
00649     /*Send Register address and read register content.*/
00650     SPDR = RG_IRQ_STATUS | HAL_TRX_CMD_RR;
00651 
00652     /* This is the second part of the convertion of system time to a 16 us time
00653        base. The division is moved here so we can spend less time waiting for SPI
00654        data.
00655      */
00656     isr_timestamp /= HAL_US_PER_SYMBOL; /* Divide so that we get time in 16us resolution. */
00657     isr_timestamp &= HAL_SYMBOL_MASK;
00658 
00659     while ((SPSR & (1 << SPIF)) == 0) {;}
00660     uint8_t interrupt_source = SPDR; /* The interrupt variable is used as a dummy read. */
00661 
00662     SPDR = interrupt_source;
00663     while ((SPSR & (1 << SPIF)) == 0) {;}
00664     interrupt_source = SPDR; /* The interrupt source is read. */
00665 
00666     HAL_SS_HIGH();
00667 
00668     /*Handle the incomming interrupt. Prioritized.*/
00669     if ((interrupt_source & HAL_RX_START_MASK)){
00670         if(rx_start_callback != NULL){
00671             /* Read Frame length and call rx_start callback. */
00672             HAL_SS_LOW();
00673 
00674             SPDR = HAL_TRX_CMD_FR;
00675             while ((SPSR & (1 << SPIF)) == 0) {;}
00676             uint8_t frame_length = SPDR;
00677 
00678             SPDR = frame_length; /*  frame_length used for dummy data */
00679             while ((SPSR & (1 << SPIF)) == 0) {;}
00680             frame_length = SPDR;
00681 
00682             HAL_SS_HIGH();
00683 
00684             rx_start_callback(isr_timestamp, frame_length);
00685         }
00686     } else if (interrupt_source & HAL_TRX_END_MASK){
00687         if(trx_end_callback != NULL){
00688             trx_end_callback(isr_timestamp);
00689         }
00690     } else if (interrupt_source & HAL_TRX_UR_MASK){
00691         ;
00692     } else if (interrupt_source & HAL_PLL_UNLOCK_MASK){
00693         ;
00694     } else if (interrupt_source & HAL_PLL_LOCK_MASK){
00695         hal_pll_lock_flag++;
00696         ;
00697     } else if (interrupt_source & HAL_BAT_LOW_MASK){
00698         /*  Disable BAT_LOW interrupt to prevent endless interrupts. The interrupt */
00699         /*  will continously be asserted while the supply voltage is less than the */
00700         /*  user-defined voltage threshold. */
00701         uint8_t trx_isr_mask = hal_register_read(RG_IRQ_MASK);
00702         trx_isr_mask &= ~HAL_BAT_LOW_MASK;
00703         hal_register_write(RG_IRQ_MASK, trx_isr_mask);
00704         hal_bat_low_flag++; /* Increment BAT_LOW flag. */
00705     } else {
00706         ;
00707     }
00708 }
00709 #   endif /* defined(DOXYGEN) */
00710 
00711 /*----------------------------------------------------------------------------*/
00712 /* This #if compile switch is used to provide a "standard" function body for the */
00713 /* doxygen documentation. */
00714 #if defined(DOXYGEN)
00715 /** \brief Timer Overflow ISR
00716  * This is the interrupt service routine for timer1 overflow.
00717  */
00718 void TIMER1_OVF_vect(void);
00719 #else  /* !DOXYGEN */
00720 ISR(TIMER1_OVF_vect)
00721 {
00722     hal_system_time++;
00723 }
00724 #endif
00725 
00726 /** @} */
00727 /** @} */
00728 
00729 /*EOF*/