diff --git a/src/core/common/trickle_timer.cpp b/src/core/common/trickle_timer.cpp index d17fabf1d..17213eb69 100644 --- a/src/core/common/trickle_timer.cpp +++ b/src/core/common/trickle_timer.cpp @@ -46,195 +46,173 @@ TrickleTimer::TrickleTimer(Instance &aInstance, Handler aTransmitHandler, Handler aIntervalExpiredHandler, void * aOwner) - : TimerMilli(aInstance, HandleTimerFired, aOwner) + : TimerMilli(aInstance, &TrickleTimer::HandleTimer, aOwner) #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT - , k(aRedundancyConstant) - , c(0) + , mRedundancyConstant(aRedundancyConstant) + , mCounter(0) #endif - , Imin(0) - , Imax(0) - , mMode(kModeNormal) - , I(0) - , t(0) - , mPhase(kPhaseDormant) + , mIntervalMin(0) + , mIntervalMax(0) + , mInterval(0) + , mTimeInInterval(0) , mTransmitHandler(aTransmitHandler) , mIntervalExpiredHandler(aIntervalExpiredHandler) + , mMode(kModeNormal) + , mIsRunning(false) + , mInTransmitPhase(false) { + assert(aTransmitHandler != NULL); } -bool TrickleTimer::IsRunning(void) const +otError TrickleTimer::Start(uint32_t aIntervalMin, uint32_t aIntervalMax, Mode aMode) { - return mPhase != kPhaseDormant; -} + otError error = OT_ERROR_NONE; -void TrickleTimer::Start(uint32_t aIntervalMin, uint32_t aIntervalMax, Mode aMode) -{ - assert(!IsRunning()); + VerifyOrExit(aIntervalMax >= aIntervalMin, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(aIntervalMin != 0 || aIntervalMax != 0, error = OT_ERROR_INVALID_ARGS); - // Set the interval limits and mode - Imin = aIntervalMin; - Imax = aIntervalMax; - mMode = aMode; + mIntervalMin = aIntervalMin; + mIntervalMax = aIntervalMax; + mMode = aMode; + mIsRunning = true; - // Initialize I to [Imin, Imax] - if (Imin == Imax) - { - I = Imin; - } - else - { - I = Random::GetUint32InRange(Imin, Imax); - } + // Select interval randomly from range [Imin, Imax]. + mInterval = Random::GetUint32InRange(mIntervalMin, mIntervalMax + 1); - // Start a new interval StartNewInterval(); + +exit: + return error; } void TrickleTimer::Stop(void) { - mPhase = kPhaseDormant; + mIsRunning = false; TimerMilli::Stop(); } -#ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT -void TrickleTimer::IndicateConsistent(void) -{ - // Increment counter - c++; -} -#endif - void TrickleTimer::IndicateInconsistent(void) { - // Only relevant if we aren't already at 'I' == 'Imin' - if (IsRunning() && I != Imin) - { - // Reset I to Imin - I = Imin; + // If interval is equal to minimum when an "inconsistent" event + // is received, do nothing. + VerifyOrExit(mIsRunning && (mInterval != mIntervalMin)); - // Stop the existing timer - TimerMilli::Stop(); + mInterval = mIntervalMin; + StartNewInterval(); - // Start a new interval - StartNewInterval(); - } +exit: + return; } void TrickleTimer::StartNewInterval(void) { -// Reset the counter and timer phase + uint32_t halfInterval; #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT - c = 0; + mCounter = 0; #endif - mPhase = kPhaseTransmit; - // Initialize t - if (I < 2) + mInTransmitPhase = true; + + switch (mMode) { - // Immediate interval, just set t to 0 - t = 0; + case kModeNormal: + halfInterval = mInterval / 2; + VerifyOrExit(halfInterval < mInterval, mTimeInInterval = halfInterval); + + // Select a random point in the interval taken from the range [I/2, I). + mTimeInInterval = Random::GetUint32InRange(halfInterval, mInterval); + break; + + case kModePlainTimer: + mTimeInInterval = mInterval; + break; + + case kModeMPL: + // Select a random point in interval taken from the range [0, I]. + mTimeInInterval = Random::GetUint32InRange(0, mInterval + 1); + break; } - else if (mMode == kModeMPL) + +exit: + TimerMilli::Start(mTimeInInterval); +} + +void TrickleTimer::HandleTimer(Timer &aTimer) +{ + static_cast(&aTimer)->HandleTimer(); +} + +void TrickleTimer::HandleTimer(void) +{ + if (mInTransmitPhase) { - // Initialize t to random value between (0, I] - t = Random::GetUint32InRange(0, I); - } - else if (mMode == kModePlainTimer) - { - // Initialize t to I, which has already been randomized in Start - t = I; + HandleEndOfTimeInInterval(); } else { - // Initialize t to random value between (I/2, I] - t = Random::GetUint32InRange(I / 2, I); + HandleEndOfInterval(); } - - // Start the timer for 't' milliseconds from now - TimerMilli::Start(t); } -void TrickleTimer::HandleTimerFired(Timer &aTimer) +void TrickleTimer::HandleEndOfTimeInInterval(void) { - static_cast(&aTimer)->HandleTimerFired(); -} - -void TrickleTimer::HandleTimerFired(void) -{ - Phase curPhase = mPhase; - bool shouldContinue = true; - - // Default the current state to Dormant - mPhase = kPhaseDormant; - - switch (curPhase) - { - // We have just reached time 't' - case kPhaseTransmit: - { - // Are we not using redundancy or is the counter still less than it? #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT - if (k == 0 || c < k) + // Trickle transmits if and only if the counter `c` is less + // than the redundancy constant `k`. + if (mRedundancyConstant == 0 || mCounter < mRedundancyConstant) #endif - { - // Invoke the transmission callback - shouldContinue = TransmitFired(); - } - - // Wait for the rest of the interval to elapse - if (shouldContinue) - { - // If we are in plain timer mode, just randomize I and restart the interval - if (mMode == kModePlainTimer) - { - // Initialize I to [Imin, Imax] - I = Random::GetUint32InRange(Imin, Imax); - - // Start a new interval - StartNewInterval(); - } - else - { - // Start next phase of the timer - mPhase = kPhaseInterval; - - // Start the time for 'I - t' milliseconds - TimerMilli::Start(I - t); - } - } - - break; - } - - // We have just reached time 'I' - case kPhaseInterval: { - // Double 'I' to get the new interval length - uint32_t newI = I == 0 ? 1 : I << 1; + bool shouldContinue = mTransmitHandler(*this); + VerifyOrExit(shouldContinue, Stop()); + } - if (newI > Imax) - { - newI = Imax; - } - - I = newI; - - // Invoke the interval expiration callback - shouldContinue = IntervalExpiredFired(); - - if (shouldContinue) - { - // Start a new interval - StartNewInterval(); - } + switch (mMode) + { + case kModePlainTimer: + // Select a random interval in [Imin, Imax] and restart. + mInterval = Random::GetUint32InRange(mIntervalMin, mIntervalMax + 1); + StartNewInterval(); + break; + case kModeNormal: + case kModeMPL: + // Waiting for the rest of the interval to elapse. + mInTransmitPhase = false; + TimerMilli::Start(mInterval - mTimeInInterval); break; } - default: - assert(false); +exit: + return; +} + +void TrickleTimer::HandleEndOfInterval(void) +{ + // Double the interval and ensure result is below max. + if (mInterval == 0) + { + mInterval = 1; } + else if (mInterval <= mIntervalMax - mInterval) + { + mInterval *= 2; + } + else + { + mInterval = mIntervalMax; + } + + if (mIntervalExpiredHandler) + { + bool shouldContinue = mIntervalExpiredHandler(*this); + VerifyOrExit(shouldContinue, Stop()); + } + + StartNewInterval(); + +exit: + return; } } // namespace ot diff --git a/src/core/common/trickle_timer.hpp b/src/core/common/trickle_timer.hpp index df52faf37..6a13dcfe6 100644 --- a/src/core/common/trickle_timer.hpp +++ b/src/core/common/trickle_timer.hpp @@ -58,29 +58,32 @@ class TrickleTimer : public TimerMilli { public: /** - * Represents the modes of operation for the TrickleTimer + * This enumeration defines the modes of operation for the `TrickleTimer`. + * */ - typedef enum Mode { - kModeNormal = 0, ///< Runs the normal trickle logic. - kModePlainTimer = 1, ///< Runs a normal timer between Imin and Imax. - kModeMPL = 2, ///< Runs the trickle logic modified for MPL. - } Mode; + enum Mode + { + kModeNormal, ///< Runs the normal trickle logic (as per RFC6206). + kModePlainTimer, ///< Runs a plain timer with random interval selected between min/max intervals. + kModeMPL, ///< Runs the trickle logic modified for MPL. + }; /** * This function pointer is called when the timer expires. * - * @param[in] aTimer A reference to the expired timer. + * @param[in] aTimer A reference to the trickle timer. * * @retval TRUE If the trickle timer should continue running. * @retval FALSE If the trickle timer should stop running. + * */ typedef bool (*Handler)(TrickleTimer &aTimer); /** - * This constructor creates a trickle timer instance. + * This constructor initializes a `TrickleTimer` instance. * - * @param[in] aInstance A reference to the instance. - * @param[in] aRedundancyConstant The redundancy constant for the timer, k. + * @param[in] aInstance A reference to the OpenThread instance. + * @param[in] aRedundancyConstant The redundancy constant for the timer, also known as `k`. * @param[in] aTransmitHandler A pointer to a function that is called when transmission should occur. * @param[in] aIntervalExpiredHandler An optional pointer to a function that is called when the interval expires. * @param[in] aOwner A pointer to owner of the `TrickleTimer` object. @@ -99,29 +102,22 @@ public: * * @retval TRUE If the trickle timer is running. * @retval FALSE If the trickle timer is not running. + * */ - bool IsRunning(void) const; + bool IsRunning(void) const { return mIsRunning; } /** - * This method start the trickle timer. + * This method starts the trickle timer. * - * @param[in] aIntervalMin The minimum interval for the timer, Imin. - * @param[in] aIntervalMax The maximum interval for the timer, Imax. + * @param[in] aIntervalMin The minimum interval for the timer in milliseconds. + * @param[in] aIntervalMax The maximum interval for the timer in milliseconds. * @param[in] aMode The operating mode for the timer. * - */ - void Start(uint32_t aIntervalMin, uint32_t aIntervalMax, Mode aMode); - - /** - * This method start the trickle timer. - * - * @param[in] aStartTime The start time. - * @param[in] aIntervalMin The minimum interval for the timer, Imin. - * @param[in] aIntervalMax The maximum interval for the timer, Imax. - * @param[in] aMode The operating mode for the timer. + * @retval OT_ERROR_NONE The timer started successfully. + * @retval OT_ERROR_INVALID_ARGS The given parameters are invalid (i.e., max interval is smaller than min). * */ - void StartAt(uint32_t aStartTime, uint32_t aIntervalMin, uint32_t aIntervalMax, Mode aMode); + otError Start(uint32_t aIntervalMin, uint32_t aIntervalMax, Mode aMode); /** * This method stops the trickle timer. @@ -134,7 +130,7 @@ public: * This method indicates to the trickle timer a 'consistent' state. * */ - void IndicateConsistent(void); + void IndicateConsistent(void) { mCounter++; } #endif /** @@ -144,52 +140,27 @@ public: void IndicateInconsistent(void); private: - bool TransmitFired(void) { return mTransmitHandler(*this); } - bool IntervalExpiredFired(void) { return mIntervalExpiredHandler ? mIntervalExpiredHandler(*this) : true; } - - void StartNewInterval(void); - - static void HandleTimerFired(Timer &aTimer); - void HandleTimerFired(void); - - // Shadow base class method to ensure it is hidden. - void StartAt(void) {} - - typedef enum Phase { - ///< Indicates we are currently not running - kPhaseDormant = 1, - ///< Indicates that when the timer expires, it should evaluate for transmit callbacks - kPhaseTransmit = 2, - ///< Indicates that when the timer expires, it should process interval expiration callbacks - kPhaseInterval = 3, - } Phase; + void StartNewInterval(void); + static void HandleTimer(Timer &aTimer); + void HandleTimer(void); + void HandleEndOfTimeInInterval(void); + void HandleEndOfInterval(void); + void StartAt(void) {} // Shadow base class `TimerMilli` method to ensure it is hidden. #ifdef ENABLE_TRICKLE_TIMER_SUPPRESSION_SUPPORT - // Redundancy constant - const uint32_t k; - - // A counter, keeping track of the number of "consistent" transmissions received - uint32_t c; + const uint32_t mRedundancyConstant; // Redundancy constant (aka 'k'). + uint32_t mCounter; // A counter for number of "consistent" transmissions (aka 'c'). #endif - // Minimum interval size - uint32_t Imin; - // Maximum interval size - uint32_t Imax; - // The mode of operation - Mode mMode; - - // The current interval size (in milliseconds) - uint32_t I; - // The time (in milliseconds) into the interval at which we should transmit - uint32_t t; - - // The current trickle phase for the timer - Phase mPhase; - - // Callback variables - Handler mTransmitHandler; - Handler mIntervalExpiredHandler; + uint32_t mIntervalMin; // Minimum interval (aka `Imin`). + uint32_t mIntervalMax; // Maximum interval (aka `Imax`). + uint32_t mInterval; // Current interval (aka `I`). + uint32_t mTimeInInterval; // Time in interval (aka `t`). + Handler mTransmitHandler; // Transmit handler callback. + Handler mIntervalExpiredHandler; // Interval expired handler callback. + Mode mMode; // Trickle timer mode. + bool mIsRunning : 1; // Indicates if the trickle timer is running. + bool mInTransmitPhase : 1; // Indicates if in transmit phase (before time `t` in current interval `I`). }; /**