Example #1
0
/**************************************************************************************************
 * @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);
}
Example #2
0
/**************************************************************************************************
 * @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);
}
Example #4
0
/**************************************************************************************************
 * @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();
}
Example #11
0
/**************************************************************************************************
 * @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);
}