/************************************************************************************************** * @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 macBackoffTimerCount * * @brief Returns the current backoff count. * * @param none * * @return current backoff count ************************************************************************************************** */ uint32 macBackoffTimerCount(void) { halIntState_t s; uint32 backoffCount; HAL_ENTER_CRITICAL_SECTION(s); backoffCount = MAC_RADIO_BACKOFF_COUNT(); HAL_EXIT_CRITICAL_SECTION(s); #ifdef MAC_RADIO_FEATURE_HARDWARE_OVERFLOW_NO_ROLLOVER /* * Extra processing is required if the radio has a special hardware overflow * count feature. Unfortunately this feature does not provide for setting a * rollover value. This must be done manually. * * This means there is a small window in time when reading the hardware count * will be inaccurate. It's possible it could be one more than the allowable * count. This happens if the count has just incremented beyond the maximum * and is queried before the ISR has a chance to run and reset the backoff * count back to zero. (Pure software implementation of backoff count does * not have this problem.) * * To solve this, before returning a value for the backoff count, the value * must be tested to see if it is beyond the maximum value. If so, a rollover * interrupt that will set backoff count to zero is imminent. In that case, * the correct backoff count of zero is returned. */ if (backoffCount >= backoffTimerRollover) { return(0); } #endif return(backoffCount); }
/************************************************************************************************** * @fn macBackoffTimerCount * * @brief Returns the current backoff count. * * @param none * * @return current backoff count ************************************************************************************************** */ MAC_INTERNAL_API uint32 macBackoffTimerCount(void) { halIntState_t s; uint32 backoffCount; HAL_ENTER_CRITICAL_SECTION(s); backoffCount = MAC_RADIO_BACKOFF_COUNT(); HAL_EXIT_CRITICAL_SECTION(s); return(backoffCount); }
/************************************************************************************************** * @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 macBackoffTimerCompareIsr * * @brief Interrupt service routine that fires when the backoff count is equal * to the trigger count. * * @param none * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerCompareIsr(void) { halIntState_t s; DBG_PRINT1(DBGSYS, "macRatChanB Compare ISR, Backoff RAT count = %u", MAC_RADIO_BACKOFF_COUNT()); macBackoffTimerTriggerCallback(); HAL_ENTER_CRITICAL_SECTION(s); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); 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 ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerSetRollover(uint32 rolloverBackoff) { halIntState_t s; /* Normally called on initialization but timer realign also calls this. */ MAC_ASSERT(rolloverBackoff > MAC_RADIO_BACKOFF_COUNT()); /* rollover value must be greater than count */ DBG_PRINTL1(DBGSYS, "MAC_RADIO_BACKOFF_SET_PERIOD(%u)", rolloverBackoff); HAL_ENTER_CRITICAL_SECTION(s); macBackoffTimerRollover = rolloverBackoff; MAC_RADIO_BACKOFF_SET_PERIOD(rolloverBackoff); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); HAL_EXIT_CRITICAL_SECTION(s); }
/************************************************************************************************** * @fn macBackoffTimerSetCount * * @brief Sets the count of the backoff timer. * * @param backoff - new count * * @return none ************************************************************************************************** */ MAC_INTERNAL_API void macBackoffTimerSetCount(uint32 backoff) { #if defined( FEATURE_BEACON_MODE ) halIntState_t s; MAC_ASSERT(backoff < macBackoffTimerRollover); /* count must be less than rollover value */ MAC_ASSERT(!(backoff & 0x80000000)); /* count must not represent negative value for int32 */ DBG_PRINT2(DBGSYS, "MAC_RADIO_BACKOFF_SET_COUNT(%u), RAT BACKOFF = %u", backoff, MAC_RADIO_BACKOFF_COUNT()); HAL_ENTER_CRITICAL_SECTION(s); MAC_RADIO_BACKOFF_SET_COUNT(backoff); MAC_BACKOFF_TIMER_UPDATE_WAKEUP(); HAL_EXIT_CRITICAL_SECTION(s); #endif /* FEATURE_BEACON_MODE */ }
/************************************************************************************************** * @fn macMcuTimer2OverflowWorkaround * * @brief For CC2530, T2 interrupt won’t be generated when the current count is greater than * the comparator. The interrupt is only generated when the current count is equal to * the comparator. When the CC2530 is waking up from sleep, there is a small window * that the count may be grater than the comparator, therefore, missing the interrupt. * This workaround will call the T2 ISR when the current T2 count is greater than the * comparator. * * @param none * * @return none ************************************************************************************************** */ void macMcuTimer2OverflowWorkaround(void) { if (T2IRQM & TIMER2_OVF_COMPARE1F) { /* T2 comapre 1 interrupt is enabled but T2 compare 1 intererrupt is not generated */ if (!(T2IRQF & TIMER2_OVF_COMPARE1F)) { if (MAC_RADIO_BACKOFF_COUNT() > macMcuOverflowGetCompare()) { /* Set the flag to trigger the timer compare interrupt */ macBackoffTimerCompareIsr(); T2IRQF = ~TIMER2_OVF_COMPARE1F; } } } }
/************************************************************************************************** * @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 macBackoffTimerUpdateWakeup * * @brief Recomputes and provides weakup timing hint to power module. * This function does not read timing variables in a critical * section. The caller must call this function within a critical * section where the timing variable is modified in order * to have more accurate notification. * * @param none * * @return none ************************************************************************************************** */ static void macBackoffTimerUpdateWakeup(void) { int_fast64_t ticks; /* Replicate the timer in order to inform power module to wake up properly * in case the device enters sleep state in the future. */ /* First find out which RAT channel between backoffTimerTrigger and * macBackoffTimerRollover is supposed to expire next. */ ticks = MAC_RADIO_BACKOFF_COUNT(); if (backoffTimerTrigger > ticks && backoffTimerTrigger < macBackoffTimerRollover) { ticks = backoffTimerTrigger - ticks; } else if (macBackoffTimerRollover > ticks) { ticks = macBackoffTimerRollover - ticks; } else { /* Note that current count might have exceeded already set thresholds, * as the code is executed while interrupt is flagged. * In such a case, this function shall be called again anyways and * hence this condition can be ignored. */ return; } /* TODO: For subG, backoff timer unit is not necessarily backoff period * but fixed 320us and hence the following constant * (MAC_SPEC_USECS_PER_BACKOFF) should be replaced with backoff * timer unit period in usecs. */ /* Convert backoff timer unit to RTOS tick unit */ ticks *= MAC_SPEC_USECS_PER_BACKOFF; #ifdef USE_ICALL ticks -= (MAC_BACKOFF_TIMER_ADDITIONAL_WAKEUP_LATENCY + ICall_pwrGetXOSCStartupTime(ticks/1000)); #elif defined OSAL_PORT2TIRTOS ticks -= MAC_BACKOFF_TIMER_ADDITIONAL_WAKEUP_LATENCY + Power_getXoscStartupTime(ticks/1000); #endif /* defined OSAL_PORT2TIRTOS */ if (ticks > 0) { #ifdef USE_ICALL ticks /= osal_tickperiod; #elif defined OSAL_PORT2TIRTOS ticks /= Clock_tickPeriod; #endif /* defined OSAL_PORT2TIRTOS */ } if (ticks > 0) { #ifdef USE_ICALL ICall_setTimer((uint_fast32_t) ticks, macBackoffTimerICallTimerCback, NULL, &macBackoffTimerICallTimerID); #endif /* USE_ICALL */ #ifdef OSAL_PORT2TIRTOS Clock_stop(macBackoffWakeupClock); Clock_setTimeout(macBackoffWakeupClock, (UInt32) ticks); Clock_start(macBackoffWakeupClock); #endif /* OSAL_PORT2TIRTOS */ /* Allow entering sleep state */ macBackoffTimerImpending = FALSE; #ifdef DEBUG_SW_TRACE DBG_PRINTL1(DBGSYS, "BO %u", ticks); #endif /* DEBUG_SW_TRACE */ } else { /* Timing is too close. Suppress sleep. */ macBackoffTimerImpending = TRUE; } macPwrVote(); }
/************************************************************************************************** * @fn macBackoffTimerRealign * * @brief * * Realignment is accomplished by adjusting the internal time base to align with the expected * reception time of an incoming frame. The difference between the expected reception time and * the actual reception time is computed and this difference is used to adjust the hardware * timer count and backoff count. * * The realignment is based on the SFD signal for the incoming frame. The timer is aligned * by adjusting it with the difference between the expected SFD time and the actual SFD time. * * @param none * * @return none ************************************************************************************************** */ int32 macBackoffTimerRealign(macRx_t *pMsg) { uint16 timerDelayTicks; int32 backoffDelta; int32 backoffCount; MAC_ASSERT(!MAC_TX_IS_PHYSICALLY_ACTIVE()); /* realignment during actual transmit corrupts timing */ /*------------------------------------------------------------------------------- * Calculate the delta backoff difference between expected backoff count, * which is zero, and the backoff count of the received frame. */ /* since expected receive time is zero, the delta is simply the receive time */ backoffDelta = pMsg->mac.timestamp; /* if the frame was received more than halfway to the rollover count, use a negative delta value */ if (((uint32) backoffDelta) > (backoffTimerRollover / 2)) { backoffDelta = backoffDelta - backoffTimerRollover; /* result will be negative */ } /*------------------------------------------------------------------------------- * Calculate the number of timer ticks to delay that will align the internal * time base with the received frame. */ /* retrieve the timer count when frame was received */ timerDelayTicks = pMsg->mac.timestamp2; /* * Subtract the expected SFD time from the actual SFD time to find the needed * timer adjustment. If subtracting the offset would result in a negative value, * the tick delay must wrap around. */ if (timerDelayTicks >= TIMER_TICKS_EXPECTED_AT_SFD) { /* since delay count is greater than or equal to offset, subtract it directly */ timerDelayTicks = timerDelayTicks - TIMER_TICKS_EXPECTED_AT_SFD; } else { /* * The expected time is greater that actualy time so it cannot be subtracted directly. * The tick count per backoff is added to wrap around within the backoff. * Since a wrap around did happen, the backoff delta is adjusted by one. */ timerDelayTicks = timerDelayTicks - TIMER_TICKS_EXPECTED_AT_SFD + MAC_RADIO_TIMER_TICKS_PER_BACKOFF(); backoffDelta--; } /*------------------------------------------------------------------------------- * Calculate the new backoff count. */ backoffCount = MAC_RADIO_BACKOFF_COUNT() - backoffDelta; if (backoffCount >= ((int32) backoffTimerRollover)) { backoffCount -= backoffTimerRollover; } else if (backoffCount < 0) { backoffCount += backoffTimerRollover; } MAC_RADIO_TIMER_FORCE_DELAY(timerDelayTicks); MAC_RADIO_BACKOFF_SET_COUNT(backoffCount); return(backoffDelta); }