/************************************************************************************************** Filename: mac_radio.c Revised: $Date: 2007-09-11 10:58:41 -0700 (Tue, 11 Sep 2007) $ Revision: $Revision: 15371 $ Description: Describe the purpose and contents of the file. Copyright 2006-2012 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ /* ------------------------------------------------------------------------------------------------ * Includes * ------------------------------------------------------------------------------------------------ */ /* hal */ #include "hal_types.h" /* high-level */ #include "mac_pib.h" /* exported low-level */ #include "mac_low_level.h" /* low-level specific */ #include "mac_radio.h" #include "mac_tx.h" #include "mac_rx.h" #include "mac_rx_onoff.h" #include "mac_sleep.h" #include "mac_backoff_timer.h" /* target specific */ #include "mac_radio_defs.h" /* debug */ #include "mac_assert.h" /* ------------------------------------------------------------------------------------------------ * Includes * ------------------------------------------------------------------------------------------------ */ #define ED_RF_POWER_MIN_DBM (MAC_RADIO_RECEIVER_SENSITIVITY_DBM + MAC_SPEC_ED_MIN_DBM_ABOVE_RECEIVER_SENSITIVITY) #define ED_RF_POWER_MAX_DBM MAC_RADIO_RECEIVER_SATURATION_DBM /* ------------------------------------------------------------------------------------------------ * Global Variables * ------------------------------------------------------------------------------------------------ */ uint8 macPhyTxPower; uint8 macPhyChannel; /* ------------------------------------------------------------------------------------------------ * Local Variables * ------------------------------------------------------------------------------------------------ */ static uint8 reqChannel; static uint8 reqTxPower; /* ------------------------------------------------------------------------------------------------ * Local Functions * ------------------------------------------------------------------------------------------------ */ static uint8 radioComputeED(int8 rssiDbm); /************************************************************************************************** * @fn macRadioInit * * @brief Initialize radio software. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioInit(void) { /* variable initialization for this module */ reqChannel = MAC_RADIO_CHANNEL_DEFAULT; macPhyChannel = MAC_RADIO_CHANNEL_INVALID; reqTxPower = MAC_RADIO_TX_POWER_INVALID; macPhyTxPower = MAC_RADIO_TX_POWER_INVALID; } /************************************************************************************************** * @fn macRadioReset * * @brief Resets the radio module. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioReset(void) { macRadioStopScan(); macRadioEnergyDetectStop(); } /************************************************************************************************** * @fn macRadioRandomByte * * @brief Return a random byte derived from previously set random seed. * * @param none * * @return a random byte ************************************************************************************************** */ MAC_INTERNAL_API uint8 macRadioRandomByte(void) { return(MAC_RADIO_RANDOM_BYTE()); } /************************************************************************************************** * @fn macRadioSetPanCoordinator * * @brief Configure the pan coordinator status of the radio * * @param panCoordFlag - non-zero to configure radio to be pan coordinator * zero to configure radio as NON pan coordinator * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioSetPanCoordinator(uint8 panCoordFlag) { /* abstracted radio configuration */ MAC_RADIO_SET_PAN_COORDINATOR(panCoordFlag); } /************************************************************************************************** * @fn macRadioSetPanID * * @brief Set the pan ID on the radio. * * @param panID - 16 bit PAN identifier * * @return none ************************************************************************************************** */ void macRadioSetPanID(uint16 panID) { /* abstracted radio configuration */ MAC_RADIO_SET_PAN_ID(panID); } /************************************************************************************************** * @fn macRadioSetShortAddr * * @brief Set the short addrss on the radio. * * @param shortAddr - 16 bit short address * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioSetShortAddr(uint16 shortAddr) { /* abstracted radio configuration */ MAC_RADIO_SET_SHORT_ADDR(shortAddr); } /************************************************************************************************** * @fn macRadioSetIEEEAddr * * @brief Set the IEEE address on the radio. * * @param pIEEEAddr - pointer to array holding 64 bit IEEE address; array must be little * endian format (starts with lowest signficant byte) * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioSetIEEEAddr(uint8 * pIEEEAddr) { /* abstracted radio configuration */ MAC_RADIO_SET_IEEE_ADDR(pIEEEAddr); } /************************************************************************************************** * @fn macRadioSetTxPower * * @brief Set transmitter power of the radio. * * @param txPower - the minus dBm for power but as a postive integer (or if configured * for it, txPower is the raw register value). If PA/LNA is installed * then txPower becomes positive dBm. * * @return The minus dBm for power actually set according to what is possible according to the build and run-time configuration set. ************************************************************************************************** */ #ifndef HAL_MAC_USE_REGISTER_POWER_VALUES /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ MAC_INTERNAL_API uint8 macRadioSetTxPower(uint8 txPower) { halIntState_t s; #if defined MAC_RUNTIME_CC2591 || defined MAC_RUNTIME_CC2590 const uint8 CODE *pTable = macRadioDefsTxPwrTables[macRadioDefsRefTableId >> 4]; #elif defined HAL_PA_LNA || defined HAL_PA_LNA_CC2590 const uint8 CODE *pTable = macRadioDefsTxPwrTables[0]; #else const uint8 CODE *pTable = macRadioDefsTxPwrBare; #endif /* if the selected dBm is out of range, use the closest available */ if ((int8)txPower > (int8)pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY]) { /* greater than base value -- out of table range */ txPower = pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY]; } else if ((int8)txPower < (int8)pTable[MAC_RADIO_DEFS_TBL_TXPWR_LAST_ENTRY]) { /* smaller than the lowest power level -- out of table range */ txPower = pTable[MAC_RADIO_DEFS_TBL_TXPWR_LAST_ENTRY]; } /* * Set the global variable reqTxPower. This variable is referenced * by the function macRadioUpdateTxPower() to write the radio register. * * A lookup table is used to translate the power level to the register * value. */ HAL_ENTER_CRITICAL_SECTION(s); /* When calculating index to the power register value table, * either txPower (of uint8 type) has to be explicitly type-casted to int8 * or the subtraction expression has to be type-casted to uint8 to work * with the integral promotions. * The latter is more code size efficient and hence the latter is used. */ { uint8 index = pTable[MAC_RADIO_DEFS_TBL_TXPWR_FIRST_ENTRY] - txPower + MAC_RADIO_DEFS_TBL_TXPWR_ENTRIES; reqTxPower = pTable[index]; } HAL_EXIT_CRITICAL_SECTION(s); /* update the radio power setting */ macRadioUpdateTxPower(); return txPower; } #else /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ MAC_INTERNAL_API uint8 macRadioSetTxPower(uint8 txPower) { halIntState_t s; /* same as above but with no lookup table, use raw register value */ HAL_ENTER_CRITICAL_SECTION(s); reqTxPower = txPower; HAL_EXIT_CRITICAL_SECTION(s); /* update the radio power setting */ macRadioUpdateTxPower(); return txPower; } #endif /************************************************************************************************** * @fn macRadioUpdateTxPower * * @brief Update the radio's transmit power if a new power level has been requested * * @param reqTxPower - file scope variable that holds the last request power level * macPhyTxPower - global variable that holds radio's set power level * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioUpdateTxPower(void) { halIntState_t s; /* * If the requested power setting is different from the actual radio setting, * attempt to udpate to the new power setting. */ HAL_ENTER_CRITICAL_SECTION(s); if (reqTxPower != macPhyTxPower) { /* * Radio power cannot be updated when the radio is physically transmitting. * If there is a possibility radio is transmitting, do not change the power * setting. This function will be called again after the current transmit * completes. */ if (!macRxOutgoingAckFlag && !MAC_TX_IS_PHYSICALLY_ACTIVE()) { /* * Set new power level; update the shadow value and write * the new value to the radio hardware. */ macPhyTxPower = reqTxPower; MAC_RADIO_SET_TX_POWER(macPhyTxPower); } } HAL_EXIT_CRITICAL_SECTION(s); } /************************************************************************************************** * @fn macRadioSetChannel * * @brief Set radio channel. * * @param channel - channel number, valid range is 11 through 26. Allow * channels 27 and 28 for some Japanese customers. * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioSetChannel(uint8 channel) { halIntState_t s; MAC_ASSERT((channel >= 11) && (channel <= 28)); /* illegal channel */ /* critical section to make sure transmit does not start while updating channel */ HAL_ENTER_CRITICAL_SECTION(s); /* set requested channel */ reqChannel = channel; /* * If transmit is not active, update the radio hardware immediately. If transmit is active, * the channel will be updated at the end of the current transmit. */ if (!macTxActive) { macRadioUpdateChannel(); } HAL_EXIT_CRITICAL_SECTION(s); } /************************************************************************************************** * @fn macRadioUpdateChannel * * @brief Update the radio channel if a new channel has been requested. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioUpdateChannel(void) { halIntState_t s; MAC_ASSERT(!macTxActive); /* cannot change channel during a transmit */ /* if the channel has changed, set the radio to the new channel */ HAL_ENTER_CRITICAL_SECTION(s); if (reqChannel != macPhyChannel) { macPhyChannel = reqChannel; HAL_EXIT_CRITICAL_SECTION(s); /* changing the channel stops any receive in progress */ macRxOff(); MAC_RADIO_SET_CHANNEL(macPhyChannel); /* If the channel is updated in the middle of receiving a frame, we must * clean up the Rx logic. */ macRxHaltCleanup(); macRxOnRequest(); } else { HAL_EXIT_CRITICAL_SECTION(s); } } /************************************************************************************************** * @fn macRadioStartScan * * @brief Puts radio into selected scan mode. * * @param scanMode - scan mode, see #defines in .h file * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioStartScan(uint8 scanMode) { MAC_ASSERT(macSleepState == MAC_SLEEP_STATE_AWAKE); /* radio must be awake */ MAC_ASSERT(macRxFilter == RX_FILTER_OFF); /* all filtering must be off to start scan */ /* set the receive filter based on the selected scan mode */ if (scanMode == MAC_SCAN_ED) { macRxFilter = RX_FILTER_ALL; } else if (scanMode == MAC_SCAN_ORPHAN) { macRxFilter = RX_FILTER_NON_COMMAND_FRAMES; } else { MAC_ASSERT((scanMode == MAC_SCAN_ACTIVE) || (scanMode == MAC_SCAN_PASSIVE)); /* invalid scan type */ macRxFilter = RX_FILTER_NON_BEACON_FRAMES; /* for active and passive scans, per spec the pan ID must be 0xFFFF */ MAC_RADIO_SET_PAN_ID(0xFFFF); } } /************************************************************************************************** * @fn macRadioStopScan * * @brief Takes radio out of scan mode. Note can be called if * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macRadioStopScan(void) { macRxFilter = RX_FILTER_OFF; /* restore the pan ID (passive and active scans set pan ID to 0xFFFF) */ MAC_RADIO_SET_PAN_ID(macPib.panId); } /************************************************************************************************** * @fn macRadioEnergyDetectStart * * @brief Initiates energy detect. The highest energy detected is recorded from the time * when this function is called until the energy detect is stopped. * * @param none * * @return none ************************************************************************************************** */ void macRadioEnergyDetectStart(void) { /* Energy Detection Scan should be run with CC2591 compresson workaround off */ COMPRESSION_WORKAROUND_OFF(); MAC_RADIO_RECORD_MAX_RSSI_START(); } /************************************************************************************************** * @fn macRadioEnergyDetectStop * * @brief Called at completion of an energy detect. Note: can be called even if energy * detect is already stopped (needed by reset). * * @param none * * @return highest energy detect measurement ************************************************************************************************** */ uint8 macRadioEnergyDetectStop(void) { uint8 rssiDbm; uint8 energyDetectMeasurement; rssiDbm = MAC_RADIO_RECORD_MAX_RSSI_STOP() + MAC_RADIO_RSSI_OFFSET; MAC_RADIO_RSSI_LNA_OFFSET(rssiDbm); energyDetectMeasurement = radioComputeED(rssiDbm); /* Trun on CC2591 compresson workaround */ COMPRESSION_WORKAROUND_ON(); return(energyDetectMeasurement); } /*================================================================================================= * @fn radioComputeED * * @brief Compute energy detect measurement. * * @param rssi - raw RSSI value from radio hardware * * @return energy detect measurement in the range of 0x00-0xFF *================================================================================================= */ static uint8 radioComputeED(int8 rssiDbm) { uint8 ed; /* * Keep RF power between minimum and maximum values. * This min/max range is derived from datasheet and specification. */ if (rssiDbm < ED_RF_POWER_MIN_DBM) { rssiDbm = ED_RF_POWER_MIN_DBM; } else if (rssiDbm > ED_RF_POWER_MAX_DBM) { rssiDbm = ED_RF_POWER_MAX_DBM; } /* * Create energy detect measurement by normalizing and scaling RF power level. * * Note : The division operation below is designed for maximum accuracy and * best granularity. This is done by grouping the math operations to * compute the entire numerator before doing any division. */ ed = (MAC_SPEC_ED_MAX * (rssiDbm - ED_RF_POWER_MIN_DBM)) / (ED_RF_POWER_MAX_DBM - ED_RF_POWER_MIN_DBM); return(ed); } /************************************************************************************************** * @fn macRadioComputeLQI * * @brief Compute link quality indication. * * @param rssi - raw RSSI value from radio hardware * corr - correlation value from radio hardware * * @return link quality indicator value ************************************************************************************************** */ MAC_INTERNAL_API uint8 macRadioComputeLQI(int8 rssiDbm, uint8 corr) { (void) corr; /* suppress compiler warning of unused parameter */ /* * Note : Currently the LQI value is simply the energy detect measurement. * A more accurate value could be derived by using the correlation * value along with the RSSI value. */ return(radioComputeED(rssiDbm)); } /************************************************************************************************** */