• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 jam detector feature.
32  */
33 
34 #include "jam_detector.hpp"
35 
36 #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
37 
38 #include "instance/instance.hpp"
39 
40 namespace ot {
41 namespace Utils {
42 
43 RegisterLogModule("JamDetector");
44 
JamDetector(Instance & aInstance)45 JamDetector::JamDetector(Instance &aInstance)
46     : InstanceLocator(aInstance)
47     , mTimer(aInstance)
48     , mHistoryBitmap(0)
49     , mCurSecondStartTime(0)
50     , mSampleInterval(0)
51     , mWindow(kMaxWindow)
52     , mBusyPeriod(kMaxWindow)
53     , mEnabled(false)
54     , mAlwaysAboveThreshold(false)
55     , mJamState(false)
56     , mRssiThreshold(kDefaultRssiThreshold)
57 {
58 }
59 
Start(Handler aHandler,void * aContext)60 Error JamDetector::Start(Handler aHandler, void *aContext)
61 {
62     Error error = kErrorNone;
63 
64     VerifyOrExit(!mEnabled, error = kErrorAlready);
65     VerifyOrExit(aHandler != nullptr, error = kErrorInvalidArgs);
66 
67     mCallback.Set(aHandler, aContext);
68     mEnabled = true;
69 
70     LogInfo("Started");
71 
72     CheckState();
73 
74 exit:
75     return error;
76 }
77 
Stop(void)78 Error JamDetector::Stop(void)
79 {
80     Error error = kErrorNone;
81 
82     VerifyOrExit(mEnabled, error = kErrorAlready);
83 
84     mEnabled  = false;
85     mJamState = false;
86 
87     mTimer.Stop();
88 
89     LogInfo("Stopped");
90 
91 exit:
92     return error;
93 }
94 
CheckState(void)95 void JamDetector::CheckState(void)
96 {
97     VerifyOrExit(mEnabled);
98 
99     switch (Get<Mle::MleRouter>().GetRole())
100     {
101     case Mle::kRoleDisabled:
102         VerifyOrExit(mTimer.IsRunning());
103         mTimer.Stop();
104         SetJamState(false);
105         break;
106 
107     default:
108         VerifyOrExit(!mTimer.IsRunning());
109         mCurSecondStartTime   = TimerMilli::GetNow();
110         mAlwaysAboveThreshold = true;
111         mHistoryBitmap        = 0;
112         mJamState             = false;
113         mSampleInterval       = kMaxSampleInterval;
114         mTimer.Start(kMinSampleInterval);
115         break;
116     }
117 
118 exit:
119     return;
120 }
121 
SetRssiThreshold(int8_t aThreshold)122 void JamDetector::SetRssiThreshold(int8_t aThreshold)
123 {
124     mRssiThreshold = aThreshold;
125     LogInfo("RSSI threshold set to %d", mRssiThreshold);
126 }
127 
SetWindow(uint8_t aWindow)128 Error JamDetector::SetWindow(uint8_t aWindow)
129 {
130     Error error = kErrorNone;
131 
132     VerifyOrExit(aWindow != 0, error = kErrorInvalidArgs);
133     VerifyOrExit(aWindow <= kMaxWindow, error = kErrorInvalidArgs);
134 
135     mWindow = aWindow;
136     LogInfo("window set to %d", mWindow);
137 
138 exit:
139     return error;
140 }
141 
SetBusyPeriod(uint8_t aBusyPeriod)142 Error JamDetector::SetBusyPeriod(uint8_t aBusyPeriod)
143 {
144     Error error = kErrorNone;
145 
146     VerifyOrExit(aBusyPeriod != 0, error = kErrorInvalidArgs);
147     VerifyOrExit(aBusyPeriod <= mWindow, error = kErrorInvalidArgs);
148 
149     mBusyPeriod = aBusyPeriod;
150     LogInfo("busy period set to %d", mBusyPeriod);
151 
152 exit:
153     return error;
154 }
155 
HandleTimer(void)156 void JamDetector::HandleTimer(void)
157 {
158     int8_t rssi;
159     bool   didExceedThreshold = true;
160 
161     VerifyOrExit(mEnabled);
162 
163     rssi = Get<Radio>().GetRssi();
164 
165     // If the RSSI is valid, check if it exceeds the threshold
166     // and try to update the history bit map
167     if (rssi != Radio::kInvalidRssi)
168     {
169         didExceedThreshold = (rssi >= mRssiThreshold);
170         UpdateHistory(didExceedThreshold);
171     }
172 
173     // If the RSSI sample does not exceed the threshold, go back to max sample interval
174     // Otherwise, divide the sample interval by half while ensuring it does not go lower
175     // than minimum sample interval.
176 
177     if (!didExceedThreshold)
178     {
179         mSampleInterval = kMaxSampleInterval;
180     }
181     else
182     {
183         mSampleInterval /= 2;
184 
185         if (mSampleInterval < kMinSampleInterval)
186         {
187             mSampleInterval = kMinSampleInterval;
188         }
189     }
190 
191     mTimer.Start(mSampleInterval + Random::NonCrypto::GetUint32InRange(0, kMaxRandomDelay));
192 
193 exit:
194     return;
195 }
196 
UpdateHistory(bool aDidExceedThreshold)197 void JamDetector::UpdateHistory(bool aDidExceedThreshold)
198 {
199     uint32_t interval = TimerMilli::GetNow() - mCurSecondStartTime;
200 
201     // If the RSSI is ever below the threshold, update mAlwaysAboveThreshold
202     // for current second interval.
203     if (!aDidExceedThreshold)
204     {
205         mAlwaysAboveThreshold = false;
206     }
207 
208     // If we reached end of current one second interval, update the history bitmap
209 
210     if (interval >= Time::kOneSecondInMsec)
211     {
212         mHistoryBitmap <<= 1;
213 
214         if (mAlwaysAboveThreshold)
215         {
216             mHistoryBitmap |= 0x1;
217         }
218 
219         mAlwaysAboveThreshold = true;
220 
221         mCurSecondStartTime += (interval / Time::kOneSecondInMsec) * Time::kOneSecondInMsec;
222 
223         UpdateJamState();
224     }
225 }
226 
UpdateJamState(void)227 void JamDetector::UpdateJamState(void)
228 {
229     uint8_t  numJammedSeconds = 0;
230     uint64_t bitmap           = mHistoryBitmap;
231 
232     // Clear all history bits beyond the current window size
233     bitmap &= (static_cast<uint64_t>(1) << mWindow) - 1;
234 
235     // Count the number of bits in the bitmap
236     while (bitmap != 0)
237     {
238         numJammedSeconds++;
239         bitmap &= (bitmap - 1);
240     }
241 
242     SetJamState(numJammedSeconds >= mBusyPeriod);
243 }
244 
SetJamState(bool aNewState)245 void JamDetector::SetJamState(bool aNewState)
246 {
247     bool shouldInvokeHandler = aNewState;
248 
249     if (aNewState != mJamState)
250     {
251         mJamState           = aNewState;
252         shouldInvokeHandler = true;
253         LogInfo("Jamming %s", mJamState ? "detected" : "cleared");
254     }
255 
256     if (shouldInvokeHandler)
257     {
258         mCallback.Invoke(aNewState);
259     }
260 }
261 
HandleNotifierEvents(Events aEvents)262 void JamDetector::HandleNotifierEvents(Events aEvents)
263 {
264     if (aEvents.Contains(kEventThreadRoleChanged))
265     {
266         CheckState();
267     }
268 }
269 
270 } // namespace Utils
271 } // namespace ot
272 
273 #endif // OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
274