/************************************************************************************************** * @fn macBackoffTimerCompareIsr * * @brief Interrupt service routine that fires when the backoff count is equal * to the trigger count. * * @param none * * @return none ************************************************************************************************** */ void macBackoffTimerCompareIsr(void) { uint8 oldState; halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); oldState = compareState; /* if compare is a rollover, set count to zero */ if (oldState & COMPARE_STATE_ROLLOVER_BV) { MAC_RADIO_BACKOFF_SET_COUNT(0); macBackoffTimerRolloverCallback(); } /* if compare is a trigger, reset for rollover and run the trigger callback */ if (oldState & COMPARE_STATE_TRIGGER_BV) { compareState = COMPARE_STATE_ROLLOVER; MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerRollover); HAL_EXIT_CRITICAL_SECTION(s); macBackoffTimerTriggerCallback(); } else if (oldState == COMPARE_STATE_ROLLOVER_AND_ARM_TRIGGER) { compareState = COMPARE_STATE_TRIGGER; MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerTrigger); HAL_EXIT_CRITICAL_SECTION(s); } else { HAL_EXIT_CRITICAL_SECTION(s); } }
/************************************************************************************************** * @fn macBackoffTimerSetTrigger * * @brief Sets the trigger count for the backoff counter. A callback is exectuted when * the backoff count reaches the trigger * * @param triggerBackoff - backoff count for new trigger * * @return none ************************************************************************************************** */ void macBackoffTimerSetTrigger(uint32 triggerBackoff) { halIntState_t s; MAC_ASSERT(triggerBackoff < backoffTimerRollover); /* trigger backoff must be less than rollover backoff */ HAL_ENTER_CRITICAL_SECTION(s); backoffTimerTrigger = triggerBackoff; if (triggerBackoff > MAC_RADIO_BACKOFF_COUNT()) { compareState = COMPARE_STATE_TRIGGER; MAC_RADIO_BACKOFF_SET_COMPARE(triggerBackoff); } else { if (triggerBackoff == 0) { compareState = COMPARE_STATE_ROLLOVER_AND_TRIGGER; } else { compareState = COMPARE_STATE_ROLLOVER_AND_ARM_TRIGGER; } MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerRollover); } HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macBackoffTimerCancelTrigger * * @brief Cancels the trigger for the backoff counter - obselete for CC253x and CC26xx. * For CC253x and CC26xx, the timer trigger should never be late, therefore, no * need to cancel. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerCancelTrigger(void) { MAC_RADIO_BACKOFF_COMPARE_CLEAR_INTERRUPT(); #if defined USE_ICALL || defined OSAL_PORT2TIRTOS /* backoffTimerTrigger must be set to a value * to properly use rollover value for the next wakeup time. */ { halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState); /* This code assumes that backoff timer callback does not cause * a problem when the callback is made at the rollover even if * no timer is associated with it. At the time the following * code is written, mac_timer.c can live with such a callback. * Setting backoff comparator value one greater than rollver value * might be conceived here to lift the above constraint, * but it would have to ensure that rollover value is never * the highest counter value, which is a more dangerous assumption. */ backoffTimerTrigger = macBackoffTimerRollover; /* Note that MAC_RADIO_BACKOFF_COMPARE_CLEAR_INTERRUPT() is not implemented * correctly and hence backoff timer trigger interrupt can still occur. * Instead of fixing MAC_RADIO_BACKOFF_COMPARE_CLEAR_INTERRUPT() macro, * comparator is set again, to simplify interrupt handling. */ MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerTrigger); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); HAL_EXIT_CRITICAL_SECTION(intState); } #endif /* defined USE_ICALL || defined OSAL_PORT2TIRTOS */ }
/************************************************************************************************** * @fn macBackoffTimerCancelTrigger * * @brief Cancels the trigger for the backoff counter. * * @param none * * @return none ************************************************************************************************** */ void macBackoffTimerCancelTrigger(void) { halIntState_t s; HAL_ENTER_CRITICAL_SECTION(s); compareState = COMPARE_STATE_ROLLOVER; MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerRollover); HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macBackoffTimerSetRollover * * @brief Set rollover count of backoff timer. * * @param rolloverBackoff - backoff count where count is reset to zero * * @return none ************************************************************************************************** */ void macBackoffTimerSetRollover(uint32 rolloverBackoff) { halIntState_t s; MAC_ASSERT(rolloverBackoff > MAC_RADIO_BACKOFF_COUNT()); /* rollover value must be greater than count */ HAL_ENTER_CRITICAL_SECTION(s); backoffTimerRollover = rolloverBackoff; MAC_RADIO_BACKOFF_SET_COMPARE(rolloverBackoff); HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macBackoffTimerSetTrigger * * @brief Sets the trigger count for the backoff counter. A callback is exectuted when * the backoff count reaches the trigger * * @param triggerBackoff - backoff count for new trigger * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerSetTrigger(uint32 triggerBackoff) { halIntState_t s; MAC_ASSERT(triggerBackoff < macBackoffTimerRollover); /* trigger backoff must be less than rollover backoff */ DBG_PRINT1(DBGSYS, "MAC_RADIO_BACKOFF_SET_COMPARE(%u)", triggerBackoff); HAL_ENTER_CRITICAL_SECTION(s); backoffTimerTrigger = triggerBackoff; MAC_RADIO_BACKOFF_SET_COMPARE(triggerBackoff); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macBackoffTimerSetTrigger * * @brief Sets the trigger count for the backoff counter. A callback is exectuted when * the backoff count reaches the trigger * * @param triggerBackoff - backoff count for new trigger * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerSetTrigger(uint32 triggerBackoff) { halIntState_t s; MAC_ASSERT(triggerBackoff < backoffTimerRollover); /* trigger backoff must be less than rollover backoff */ HAL_ENTER_CRITICAL_SECTION(s); backoffTimerTrigger = triggerBackoff; MAC_RADIO_BACKOFF_SET_COMPARE(triggerBackoff); if (triggerBackoff == MAC_RADIO_BACKOFF_COUNT()) { /* Clear the interrupt and fire it manually */ MAC_RADIO_BACKOFF_COMPARE_CLEAR_INTERRUPT(); HAL_EXIT_CRITICAL_SECTION(s); macBackoffTimerTriggerCallback(); } else { HAL_EXIT_CRITICAL_SECTION(s); } }
/************************************************************************************************** * @fn macBackoffTimerInit * * @brief Intializes backoff timer. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerInit(void) { macPrevPeriodRatCount = macBackoffTimerRollover = 0; /* backoffTimerTrigger has to be set to maximum possible value of * macBackoffTimerRollover value initially. * Otherwise, incorrect backoffTimerTrigger value shall be compared * all the time in macBackoffTimerUpdateWakeup() function, casting * incorrect vote. */ backoffTimerTrigger = MAC_BACKOFF_TIMER_DEFAULT_NONBEACON_ROLLOVER; MAC_RADIO_CLEAR_BACKOFF_COUNT(); #if defined USE_ICALL || defined OSAL_PORT2TIRTOS // Clear events macBackoffTimerEvents = 0; #ifdef USE_ICALL // Register hook function to handle events. if (!osal_eventloop_hook) { /* Don't overwrite if the hook is already set up. * Note that the hook might have been set up to perform other things * as well in which case the other hook function has to call * macBackoffTimerEventHandler. */ osal_eventloop_hook = macBackoffTimerEventHandler; } #endif /* USE_ICALL */ macBackoffTimerImpending = FALSE; #ifdef USE_ICALL /* Start timer just to initialize the timer ID to reuse in the module. * This also serves the purpose of allocating resources upfront, * in order to prevent a case of running out of timer resource * when the timer has to be started. * Note that macBackoffTimerSetRollover() may trigger setting timer * and hence the timer set up must happen before macBackoffTimerSetRollover() * call. */ if (ICall_setTimer(1, macBackoffTimerICallTimerCback, NULL, &macBackoffTimerICallTimerID) != ICALL_ERRNO_SUCCESS) { MAC_ASSERT(0); } #endif /* USE_ICALL */ #ifdef OSAL_PORT2TIRTOS if (!macBackoffWakeupClock) { /* Creates a wakeup clock */ Clock_Params params; Clock_Params_init(¶ms); params.startFlag = FALSE; params.period = 0; macBackoffWakeupClock = Clock_create((Clock_FuncPtr) macBackoffTimerICallTimerCback, 1, ¶ms, NULL); MAC_ASSERT(macBackoffWakeupClock); /* No need to stop clock, the clock event will reprogram next wake time */ } #endif /* OSAL_PORT2TIRTOS */ /* Note that macPwrVote() is called done from macBackoffTimerSetRollover() * call and hence there is no need to make the call here. */ #endif /* defined USE_ICALL || defined OSAL_PORT2TIRTOS */ macBackoffTimerSetRollover(MAC_BACKOFF_TIMER_DEFAULT_NONBEACON_ROLLOVER); /* Since interrupt disable/enable mechanism is not implemented for backoff * timer trigger interrupt for CC26xx, comparator value has to be set * so that the timer trigger interrupt is not triggered. * See comment inside macBackoffTimerCancelTrigger() for relevant * information */ MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerTrigger); }
static #endif /* USE_ICALL */ void macBackoffTimerEventHandler(void) { halIntState_t is; uint8 events; HAL_ENTER_CRITICAL_SECTION(is); events = macBackoffTimerEvents; macBackoffTimerEvents = 0; HAL_EXIT_CRITICAL_SECTION(is); if (events & MAC_BACKOFF_TIMER_EVENT_POWER_WAKEUP) { // Wakeup radio // Turning on radio domain before clock set up seems to cause // unexpected interrupt. // Hence interrupt shall be disabled here. MB_DisableInts(); // Enable clocks for all radio internal modules. // Use Non-Buff access for safety and check for sanity HWREG(RFC_PWR_NONBUF_BASE + RFC_PWR_O_PWMCLKEN) = 0x7FF; /* Setup mailbox */ macSetupMailbox(); #ifdef DEBUG_SW_TRACE /* re-enable RF trace output for FPGA */ MB_SendCommand( BUILD_DIRECT_PARAM_EXT_CMD( CMD_ENABLE_DEBUG, 0x1D40 ) ); /* or 0x1940 for less trace */ DBG_PRINT0(DBGSYS, "RF Trace Resumes..."); #endif /* DEBUG_SW_TRACE */ /* Start off CM0. Patch it. */ macSetupRfHal(); /* Restore states */ MAC_RADIO_SET_CHANNEL(macPhyChannel); MAC_RADIO_SET_PAN_COORDINATOR(macPanCoordinator); MAC_RADIO_SET_PAN_ID(pMacPib->panId); MAC_RADIO_SET_SHORT_ADDR(pMacPib->shortAddress); MAC_RADIO_SET_IEEE_ADDR(pMacPib->extendedAddress.addr.extAddr); #if !defined( USE_FPGA ) #ifdef USE_ICALL // Switch back to HFOSC. while (!ICall_pwrIsStableXOSCHF()); ICall_pwrSwitchXOSCHF(); #endif /* USE_ICALL */ #ifdef OSAL_PORT2TIRTOS // Switches back to HFOSC. while (!Power_isStableXOSC_HF()); Power_switchXOSC_HF(); #endif /* OSAL_PORT2TIRTOS */ #endif /* !defined( USE_FPGA ) */ /* Synchronize RAT timer */ macSyncStartRAT(macRATValue); /* Turn on autoack */ MAC_RADIO_TURN_ON_AUTO_ACK(); /* Initialize SRCEXTPENDEN and SRCSHORTPENDEN to zeros */ MAC_RADIO_SRC_MATCH_INIT_EXTPENDEN(); MAC_RADIO_SRC_MATCH_INIT_SHORTPENDEN(); /* Start 15.4 Radio */ macSetupRadio(); /* Restore timer comparators */ MAC_RADIO_BACKOFF_SET_PERIOD(macBackoffTimerRollover); MAC_RADIO_BACKOFF_SET_COMPARE(backoffTimerTrigger); #if 0 /* Following code should be disabled normally */ /* Code for wakeup lead time calibration */ { static uint32 macBackoffTimerMinMargin = 0xffffffffu; uint32 delta = macPrevPeriodRatCount + backoffTimerTrigger * MAC_BACKOFF_TO_RAT_RATIO - MAC_RAT_COUNT; if (delta < macBackoffTimerMinMargin) { macBackoffTimerMinMargin = delta; } } #endif } /* Note that MAC_BACKOFF_TIMER_EVENT_POWER_TIMER_EXP handling must always * occur after handling of MAC_BACKOFF_TIMER_EVENT_POWER_WAKEUP event * because the device might be waking up upon the timer event itself * in which case, radio has to be turned on before updating the RAT timer. */ if (events & MAC_BACKOFF_TIMER_EVENT_POWER_TIMER_EXP) { /* Update wakeup schedule, which most likely would vote not to enter * sleep state. */ HAL_ENTER_CRITICAL_SECTION(is); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); HAL_EXIT_CRITICAL_SECTION(is); } }