mirror of
https://github.com/espressif/openthread.git
synced 2026-08-19 17:09:51 +00:00
[trickle-timer] improve/simplify the implementation (#2742)
This commit makes the following changes in `TrickleTimer` class: - Member variable are renamed to follow the code style guideline. - New methods added for handling of "end of interval" vs. "middle of interval" timer fired callbacks. - The random range selections for mode `kModeNormal` are updated to follow RFC6206.
This commit is contained in:
committed by
Jonathan Hui
parent
a3d01cbca8
commit
98ed5ea2ad
+116
-138
@@ -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<TrickleTimer *>(&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<TrickleTimer *>(&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
|
||||
|
||||
@@ -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`).
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user