1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the trickle timer logic.
32 */
33
34 #include "trickle_timer.hpp"
35
36 #include "common/code_utils.hpp"
37 #include "common/debug.hpp"
38 #include "common/random.hpp"
39
40 namespace ot {
41
TrickleTimer(Instance & aInstance,Handler aHandler)42 TrickleTimer::TrickleTimer(Instance &aInstance, Handler aHandler)
43 : TimerMilli(aInstance, TrickleTimer::HandleTimer)
44 , mIntervalMin(0)
45 , mIntervalMax(0)
46 , mInterval(0)
47 , mTimeInInterval(0)
48 , mRedundancyConstant(0)
49 , mCounter(0)
50 , mHandler(aHandler)
51 , mMode(kModeTrickle)
52 , mPhase(kBeforeRandomTime)
53 {
54 }
55
Start(Mode aMode,uint32_t aIntervalMin,uint32_t aIntervalMax,uint16_t aRedundancyConstant)56 void TrickleTimer::Start(Mode aMode, uint32_t aIntervalMin, uint32_t aIntervalMax, uint16_t aRedundancyConstant)
57 {
58 OT_ASSERT((aIntervalMax >= aIntervalMin) && (aIntervalMin > 0));
59
60 mIntervalMin = aIntervalMin;
61 mIntervalMax = aIntervalMax;
62 mRedundancyConstant = aRedundancyConstant;
63 mMode = aMode;
64
65 // Select interval randomly from range [Imin, Imax].
66 mInterval = Random::NonCrypto::GetUint32InRange(mIntervalMin, mIntervalMax + 1);
67
68 StartNewInterval();
69 }
70
IndicateConsistent(void)71 void TrickleTimer::IndicateConsistent(void)
72 {
73 if (mCounter < kInfiniteRedundancyConstant)
74 {
75 mCounter++;
76 }
77 }
78
IndicateInconsistent(void)79 void TrickleTimer::IndicateInconsistent(void)
80 {
81 VerifyOrExit(mMode == kModeTrickle);
82
83 // If interval is equal to minimum when an "inconsistent" event
84 // is received, do nothing.
85
86 VerifyOrExit(IsRunning() && (mInterval != mIntervalMin));
87
88 mInterval = mIntervalMin;
89 StartNewInterval();
90
91 exit:
92 return;
93 }
94
StartNewInterval(void)95 void TrickleTimer::StartNewInterval(void)
96 {
97 uint32_t halfInterval;
98
99 switch (mMode)
100 {
101 case kModePlainTimer:
102 mTimeInInterval = mInterval;
103 break;
104
105 case kModeTrickle:
106 // Select a random point in the interval taken from the range [I/2, I).
107 halfInterval = mInterval / 2;
108 mTimeInInterval =
109 (halfInterval < mInterval) ? Random::NonCrypto::GetUint32InRange(halfInterval, mInterval) : halfInterval;
110 mCounter = 0;
111 mPhase = kBeforeRandomTime;
112 break;
113 }
114
115 TimerMilli::Start(mTimeInInterval);
116 }
117
HandleTimer(Timer & aTimer)118 void TrickleTimer::HandleTimer(Timer &aTimer)
119 {
120 static_cast<TrickleTimer *>(&aTimer)->HandleTimer();
121 }
122
HandleTimer(void)123 void TrickleTimer::HandleTimer(void)
124 {
125 switch (mMode)
126 {
127 case kModePlainTimer:
128 mInterval = Random::NonCrypto::GetUint32InRange(mIntervalMin, mIntervalMax + 1);
129 StartNewInterval();
130 break;
131
132 case kModeTrickle:
133 switch (mPhase)
134 {
135 case kBeforeRandomTime:
136 // We reached end of random `mTimeInInterval` (aka `t`)
137 // within the current interval. Trickle timer invokes
138 // handler if and only if the counter is less than the
139 // redundancy constant.
140
141 mPhase = kAfterRandomTime;
142 TimerMilli::Start(mInterval - mTimeInInterval);
143 VerifyOrExit(mCounter < mRedundancyConstant);
144 break;
145
146 case kAfterRandomTime:
147 // Interval has expired. Double the interval length and
148 // ensure result is below max.
149
150 if (mInterval == 0)
151 {
152 mInterval = 1;
153 }
154 else if (mInterval <= mIntervalMax - mInterval)
155 {
156 mInterval *= 2;
157 }
158 else
159 {
160 mInterval = mIntervalMax;
161 }
162
163 StartNewInterval();
164 ExitNow(); // Exit so to not call `mHanlder`
165 }
166
167 break;
168 }
169
170 mHandler(*this);
171
172 exit:
173 return;
174 }
175
176 } // namespace ot
177