From 2bc79217d2e86478e5b477c38df48238308ea37a Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Sun, 13 Nov 2016 17:01:26 -0800 Subject: [PATCH] Implementation of "signal jamming detection" feature (#966) This commit contains the following changes: - Introducing `JamDetector` class as the core of signal jamming detection. - Adding new OpenThread APIs related to jamming detection. - Adding support in `NcpBase` for jamming detection spinel properties. --- configure.ac | 32 +++ etc/visual-studio/libopenthread.vcxproj | 4 +- .../libopenthread.vcxproj.filters | 6 + etc/visual-studio/libopenthread_k.vcxproj | 4 +- .../libopenthread_k.vcxproj.filters | 6 + include/Makefile.am | 1 + include/openthread-jam-detection.h | 181 ++++++++++++ include/openthread-windows-config.h | 3 + include/platform/radio.h | 1 + src/core/Makefile.am | 7 + src/core/openthread.cpp | 56 ++++ src/core/thread/thread_netif.cpp | 4 + src/core/thread/thread_netif.hpp | 19 ++ src/core/utils/jam_detector.cpp | 237 +++++++++++++++ src/core/utils/jam_detector.hpp | 208 ++++++++++++++ src/ncp/ncp_base.cpp | 270 ++++++++++++++++++ src/ncp/ncp_base.hpp | 28 +- src/ncp/spinel.h | 15 +- 18 files changed, 1072 insertions(+), 10 deletions(-) create mode 100644 include/openthread-jam-detection.h create mode 100644 src/core/utils/jam_detector.cpp create mode 100644 src/core/utils/jam_detector.hpp diff --git a/configure.ac b/configure.ac index cb2a866cd..e07a610e3 100644 --- a/configure.ac +++ b/configure.ac @@ -532,6 +532,37 @@ AC_SUBST(OPENTHREAD_ENABLE_DTLS) AM_CONDITIONAL([OPENTHREAD_ENABLE_DTLS], [test "${enable_dtls}" = "yes"]) AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DTLS],[${OPENTHREAD_ENABLE_DTLS}],[Define to 1 to enable dtls support.]) +# +# Jam Detection +# + +AC_ARG_ENABLE(jam_detection, + [AS_HELP_STRING([--enable-jam-detection],[Enable Jam Detection support @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_jam_detection=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enable_jam_detection} for --enable-jam-detection]) + ;; + esac + ], + [enable_jam_detection=no]) + +if test "$enable_jam_detection" = "yes"; then + OPENTHREAD_ENABLE_JAM_DETECTION=1 +else + OPENTHREAD_ENABLE_JAM_DETECTION=0 +fi + +AC_MSG_RESULT(${enable_jam_detection}) +AC_SUBST(OPENTHREAD_ENABLE_JAM_DETECTION) +AM_CONDITIONAL([OPENTHREAD_ENABLE_JAM_DETECTION], [test "${enable_jam_detection}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_JAM_DETECTION],[${OPENTHREAD_ENABLE_JAM_DETECTION}],[Define to 1 if you want to use jam detection feature]) + # # Diagnostics Library # @@ -969,6 +1000,7 @@ AC_MSG_NOTICE([ OpenThread Commissioner support : ${enable_commissioner} OpenThread Joiner support : ${enable_joiner} OpenThread DTLS support : ${enable_dtls} + OpenThread Jam Detection support : ${enable_jam_detection} OpenThread Diagnostics support : ${enable_diag} OpenThread Legacy network support : ${enable_legacy} OpenThread Cli logging support : ${enable_cli_logging} diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index 984ba09c2..720dedca8 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -1,6 +1,6 @@  - + {DD5018BE-54C6-4FD4-9F8D-08D52FC0CD40} StaticLibrary @@ -113,6 +113,7 @@ + @@ -185,6 +186,7 @@ + diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index d4cae2b5e..c1a15aea7 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -225,6 +225,9 @@ Source Files\utils + + Source Files\utils + Source Files\meshcop @@ -437,6 +440,9 @@ Header Files\utils + + Header Files\utils + Header Files\meshcop diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index e5753c094..15537f99f 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -1,6 +1,6 @@  - + {9B33C190-5D07-40BF-9536-68843DC5D7AF} {8c0e3d8b-df43-455b-815a-4a0e72973bc6} @@ -123,6 +123,7 @@ + @@ -200,6 +201,7 @@ + diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 8bd66c267..416adfa3e 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -216,6 +216,9 @@ Source Files\utils + + Source Files\utils + Source Files\thread @@ -416,6 +419,9 @@ Header Files\utils + + Header Files\utils + Header Files\thread diff --git a/include/Makefile.am b/include/Makefile.am index 32d0e531e..b4c3a6932 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -64,6 +64,7 @@ include_HEADERS = \ openthread-crypto.h \ openthread-diag.h \ openthread-ip6.h \ + openthread-jam-detection.h \ openthread-message.h \ openthread-tasklet.h \ openthread-types.h \ diff --git a/include/openthread-jam-detection.h b/include/openthread-jam-detection.h new file mode 100644 index 000000000..ecdef9fde --- /dev/null +++ b/include/openthread-jam-detection.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file includes the OenThread API for jam detection feature. + */ + +#ifndef OPENTHREAD_JAM_DETECTION_H_ +#define OPENTHREAD_JAM_DETECTION_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup jam-det Jamming Detection + * + * @brief + * This module includes functions for signal jamming detection feature. + * + * @{ + * + */ + +/** + * This function pointer is called if signal jam detection is enabled and a jam is detected. + * + * @param[in] aJamState Current jam state (`true` if jam is detected, `false` otherwise). + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (*otJamDetectionCallback)(bool aJamState, void *aContext); + +/** + * Set the Jam Detection RSSI Threshold (in dBm). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aRssiThreshold The RSSI threshold. + * + * @retval kThreadErrorNone Successfully set the threshold. + * + */ +ThreadError otSetJamDetectionRssiThreshold(otInstance *aInstance, int8_t aRssiThreshold); + +/** + * Get the Jam Detection RSSI Threshold (in dBm). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Jam Detection RSSI Threshold. + */ +int8_t otGetJamDetectionRssiThreshold(otInstance *aInstance); + +/** + * Set the Jam Detection Detection Window (in seconds). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aWindow The Jam Detection window (valid range is 1 to 63) + * + * @retval kThreadErrorNone Successfully set the window. + * @retval kThreadErrorInvalidArgs The given input parameter not within valid range (1-63) + * + */ +ThreadError otSetJamDetectionWindow(otInstance *aInstance, uint8_t aWindow); + +/** + * Get the Jam Detection Detection Window (in seconds). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Jam Detection Window. + */ +uint8_t otGetJamDetectionWindow(otInstance *aInstance); + +/** + * Set the Jam Detection Busy Period (in seconds). + * + * The number of aggregate seconds within the detection window where the RSSI must be above + * threshold to trigger detection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aBusyPeriod The Jam Detection busy period (should be non-zero and + less than or equal to Jam Detection Window) + * + * @retval kThreadErrorNone Successfully set the window. + * @retval kThreadErrorInvalidArgs The given input is not within the valid range. + * + */ +ThreadError otSetJamDetectionBusyPeriod(otInstance *aInstance, uint8_t aBusyPeriod); + +/** + * Get the Jam Detection Busy Period (in seconds) + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Jam Detection Busy Period + */ +uint8_t otGetJamDetectionBusyPeriod(otInstance *aInstance); + +/** + * Start the jamming detection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCallback A pointer to a function called when jamming state changes. + * @param[in] aContext A pointer to application-specific context. + * + * @retval kThreadErrorNone Successfully started the jamming detection. + * @retval kThreadErrorAlready Jam detection has been started before. + * + */ +ThreadError otStartJamDetection(otInstance *aInstance, otJamDetectionCallback aCallback, void *aContext); + +/** + * Stop the jamming detection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval kThreadErrorNone Successfully stopped the jamming detection. + * @retval kThreadErrorAlready Jam detection is already stopped. + * + */ +ThreadError otStopJamDetection(otInstance *aInstance); + +/** + * Get the Jam Detection Status (enabled/disabled) + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Jam Detection status (true if enabled, false otherwise). + */ +bool otIsJamDetectionEnabled(otInstance *aInstance); + + +/** + * Get the Jam Detection State + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The Jam Detection state (`true` jam is detected, `false' otherwise). + */ +bool otGetJamDetectionState(otInstance *aInstance); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_JAM_DETECTION_H_ diff --git a/include/openthread-windows-config.h b/include/openthread-windows-config.h index 3fc3e4db2..7599049ef 100644 --- a/include/openthread-windows-config.h +++ b/include/openthread-windows-config.h @@ -41,6 +41,9 @@ /* Define to 1 to enable the joiner role. */ #define OPENTHREAD_ENABLE_JOINER 1 +/* Define to 1 to enable the jam detection. */ +#define OPENTHREAD_ENABLE_JAM_DETECTION 0 + /* Define to 1 to enable DHCPv6 Client. */ #define OPENTHREAD_ENABLE_DHCP6_CLIENT 0 diff --git a/include/platform/radio.h b/include/platform/radio.h index 50c215b7a..2f9e6c636 100644 --- a/include/platform/radio.h +++ b/include/platform/radio.h @@ -78,6 +78,7 @@ enum kPhyUsPerSymbol = ((kPhyBitsPerOctet / kPhySymbolsPerOctet) * 1000000) / kPhyBitRate, kPhyNoLqi = 0, ///< LQI measurement not supported + kPhyInvalidRssi = 127, ///< Invalid or unknown RSSI value }; /** diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 15f812815..600c1462c 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -123,6 +123,12 @@ libopenthread_a_SOURCES += \ $(NULL) endif # OPENTHREAD_ENABLE_DHCP6_SERVER +if OPENTHREAD_ENABLE_JAM_DETECTION +libopenthread_a_SOURCES += \ + utils/jam_detector.cpp \ + $(NULL) +endif # OPENTHREAD_ENABLE_DHCP6_SERVER + noinst_HEADERS = \ openthread-core-config.h \ openthread-core-default-config.h \ @@ -199,6 +205,7 @@ noinst_HEADERS = \ thread/thread_uris.hpp \ thread/topology.hpp \ utils/slaac_address.hpp \ + utils/jam_detector.hpp \ $(NULL) if OPENTHREAD_BUILD_COVERAGE diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index e904ac0cb..dee043479 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -40,6 +40,10 @@ #endif #include +#if OPENTHREAD_ENABLE_JAM_DETECTION +#include +#endif + #include #include #include @@ -919,6 +923,58 @@ void otGetMessageBufferInfo(otInstance *aInstance, otBufferInfo *aBufferInfo) aBufferInfo->mCoapClientBuffers); } +#if OPENTHREAD_ENABLE_JAM_DETECTION +ThreadError otSetJamDetectionRssiThreshold(otInstance *aInstance, int8_t aRssiThreshold) +{ + return aInstance->mThreadNetif.GetJamDetector().SetRssiThreshold(aRssiThreshold); +} + +int8_t otGetJamDetectionRssiThreshold(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().GetRssiThreshold(); +} + +ThreadError otSetJamDetectionWindow(otInstance *aInstance, uint8_t aWindow) +{ + return aInstance->mThreadNetif.GetJamDetector().SetWindow(aWindow); +} + +uint8_t otGetJamDetectionWindow(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().GetWindow(); +} + +ThreadError otSetJamDetectionBusyPeriod(otInstance *aInstance, uint8_t aBusyPeriod) +{ + return aInstance->mThreadNetif.GetJamDetector().SetBusyPeriod(aBusyPeriod); +} + +uint8_t otGetJamDetectionBusyPeriod(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().GetBusyPeriod(); +} + +ThreadError otStartJamDetection(otInstance *aInstance, otJamDetectionCallback aCallback, void *aContext) +{ + return aInstance->mThreadNetif.GetJamDetector().Start(aCallback, aContext); +} + +ThreadError otStopJamDetection(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().Stop(); +} + +bool otIsJamDetectionEnabled(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().IsEnabled(); +} + +bool otGetJamDetectionState(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetJamDetector().GetState(); +} +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b) { return *static_cast(a) == *static_cast(b); diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index 923d537cc..75a5d3b2e 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -83,11 +83,15 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6): #if OPENTHREAD_ENABLE_JOINER mJoiner(*this), #endif // OPENTHREAD_ENABLE_JOINER +#if OPENTHREAD_ENABLE_JAM_DETECTION + mJamDetector(*this), +#endif // OPENTHREAD_ENABLE_JAM_DETECTTION mJoinerRouter(*this), mLeader(*this), mAnnounceBegin(*this), mPanIdQuery(*this), mEnergyScan(*this) + { mKeyManager.SetMasterKey(kThreadMasterKey, sizeof(kThreadMasterKey)); } diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index 04fceb805..a4a7f0e35 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -64,6 +64,10 @@ #include #include +#if OPENTHREAD_ENABLE_JAM_DETECTION +#include +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + #if OPENTHREAD_ENABLE_COMMISSIONER #include #endif // OPENTHREAD_ENABLE_COMMISSIONER @@ -288,6 +292,16 @@ public: MeshCoP::Joiner &GetJoiner(void) { return mJoiner; } #endif // OPENTHREAD_ENABLE_JOINER +#if OPENTHREAD_ENABLE_JAM_DETECTION + /** + * This method returns the jam detector instance. + * + * @returns Reference to the JamDetector instance. + * + */ + Utils::JamDetector &GetJamDetector(void) { return mJamDetector; } +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + /** * This method returns the pointer to the parent otInstance structure. * @@ -331,11 +345,16 @@ private: MeshCoP::Joiner mJoiner; #endif // OPENTHREAD_ENABLE_JOINER +#if OPENTHREAD_ENABLE_JAM_DETECTION + Utils::JamDetector mJamDetector; +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + MeshCoP::JoinerRouter mJoinerRouter; MeshCoP::Leader mLeader; AnnounceBeginServer mAnnounceBegin; PanIdQueryServer mPanIdQuery; EnergyScanServer mEnergyScan; + }; /** diff --git a/src/core/utils/jam_detector.cpp b/src/core/utils/jam_detector.cpp new file mode 100644 index 000000000..8f3954b25 --- /dev/null +++ b/src/core/utils/jam_detector.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the jam detector feature. + */ + +#ifdef OPENTHREAD_CONFIG_FILE +#include OPENTHREAD_CONFIG_FILE +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +namespace Thread { +namespace Utils { + +JamDetector::JamDetector(ThreadNetif &aNetif) : + mNetif(aNetif), + mTimer(aNetif.GetIp6().mTimerScheduler, &JamDetector::HandleTimer, this) +{ + mWindow = kMaxWindow; + mBusyPeriod = kMaxWindow; + mRssiThreshold = kDefaultRssiThreshold; + + mEnabled = false; + + mHandler = NULL; + mContext = NULL; + + mHistoryBitmap = 0; +} + +ThreadError JamDetector::Start(Handler aHandler, void *aContext) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(!mEnabled, error = kThreadError_Already); + VerifyOrExit(aHandler != NULL, error = kThreadError_InvalidArgs); + + mHandler = aHandler; + mContext = aContext; + + mEnabled = true; + + mCurSecondStartTime = Timer::GetNow(); + mAlwaysAboveThreshold = true; + mHistoryBitmap = 0; + mJamState = false; + mSampleInterval = kMaxSampleInterval; + + mTimer.Start(kMinSampleInterval); + +exit: + return error; +} + +ThreadError JamDetector::Stop(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_Already); + + mEnabled = false; + mJamState = false; + + mTimer.Stop(); + +exit: + return error; +} + +ThreadError JamDetector::SetRssiThreshold(int8_t aThreshold) +{ + mRssiThreshold = aThreshold; + + return kThreadError_None; +} + +ThreadError JamDetector::SetWindow(uint8_t aWindow) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(aWindow != 0, error = kThreadError_InvalidArgs); + VerifyOrExit(aWindow <= kMaxWindow, error = kThreadError_InvalidArgs); + + mWindow = aWindow; + +exit: + return error; +} + +ThreadError JamDetector::SetBusyPeriod(uint8_t aBusyPeriod) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(aBusyPeriod != 0, error = kThreadError_InvalidArgs); + VerifyOrExit(aBusyPeriod <= mWindow, error = kThreadError_InvalidArgs); + + mBusyPeriod = aBusyPeriod; + +exit: + return error; +} + +void JamDetector::HandleTimer(void *aContext) +{ + static_cast(aContext)->HandleTimer(); +} + +void JamDetector::HandleTimer(void) +{ + int8_t rssi; + bool didExceedThreshold = true; + + VerifyOrExit(mEnabled, ;); + + rssi = otPlatRadioGetRssi(mNetif.GetInstance()); + + // If the RSSI is valid, check if it exceeds the threshold + // and try to update the history bit map + if (rssi != kPhyInvalidRssi) + { + didExceedThreshold = (rssi >= mRssiThreshold); + UpdateHistory(didExceedThreshold); + } + + // If the RSSI sample does not exceed the threshold, go back to max sample interval + // Otherwise, divide the sample interval by half while ensuring it does not go lower + // than minimum sample interval. + + if (!didExceedThreshold) + { + mSampleInterval = kMaxSampleInterval; + } + else + { + mSampleInterval /= 2; + + if (mSampleInterval < kMinSampleInterval) + { + mSampleInterval = kMinSampleInterval; + } + } + + mTimer.Start(mSampleInterval + (otPlatRandomGet() % kMaxRandomDelay)); + +exit: + return; +} + +void JamDetector::UpdateHistory(bool aDidExceedThreshold) +{ + // If the RSSI is ever below the threshold, update mAlwaysAboveThreshold + // for current second interval. + if (!aDidExceedThreshold) + { + mAlwaysAboveThreshold = false; + } + + // If we reached end of current one second interval, update the history bitmap + if (Timer::GetNow() - mCurSecondStartTime >= kOneSecondInterval) + { + mHistoryBitmap <<= 1; + + if (mAlwaysAboveThreshold) + { + mHistoryBitmap |= 0x1; + } + + mAlwaysAboveThreshold = true; + mCurSecondStartTime += kOneSecondInterval; + + UpdateJamState(); + } +} + +void JamDetector::UpdateJamState(void) +{ + uint8_t numJammedSeconds = 0; + uint64_t bitmap = mHistoryBitmap; + bool oldJamState = mJamState; + + // Clear all history bits beyond the current window size + bitmap &= (static_cast(1) << mWindow) - 1; + + // Count the number of bits in the bitmap + while (bitmap != 0) + { + numJammedSeconds++; + bitmap &= (bitmap - 1); + } + + // Update the Jam state + mJamState = (numJammedSeconds >= mBusyPeriod); + + // If there is a change, invoke the handler. + if (mJamState != oldJamState) + { + mHandler(mJamState, mContext); + } +} + +} // namespace Utils +} // namespace Thread diff --git a/src/core/utils/jam_detector.hpp b/src/core/utils/jam_detector.hpp new file mode 100644 index 000000000..890d0b22b --- /dev/null +++ b/src/core/utils/jam_detector.hpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for jam detector. + */ + +#ifndef JAM_DETECTOR_HPP_ +#define JAM_DETECTOR_HPP_ + +#ifdef OPENTHREAD_CONFIG_FILE +#include OPENTHREAD_CONFIG_FILE +#else +#include +#endif + +#include +#include + + +namespace Thread { + +class ThreadNetif; + +namespace Utils { + +class JamDetector +{ +public: + + /** + * This function pointer is called if jam state changes (assuming jamming detection is enabled). + * + * @param[in] aJamState `true` if jam is detected, `false` if jam is cleared. + * @param[in] aContext A pointer to application-specific context. + * + */ + typedef void (*Handler)(bool aJamState, void *aContext); + + /** + * This constructor initializes the object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * + */ + explicit JamDetector(ThreadNetif &aThreadNetif); + + /** + * Start the jamming detection. + * + * @param[in] aHandler A pointer to a function called when jamming is detected. + * @param[in] aContext A pointer to application-specific context. + * + * @retval kThreadErrorNone Successfully started the jamming detection. + * @retval kThreadErrorAlready Jam detection has been started before. + * + */ + ThreadError Start(Handler aHandler, void *aContext); + + /** + * Stop the jamming detection. + * + * @retval kThreadErrorNone Successfully stopped the jamming detection. + * @retval kThreadErrorAlready Jam detection is already stopped. + * + */ + ThreadError Stop(void); + + /** + * Get the Jam Detection Status + * + * @returns The Jam Detection status (true if enabled, false otherwise). + */ + bool IsEnabled(void) const { return mEnabled; } + + /** + * Get the current jam state. + * + * @returns The jamming state (`true` if jam is detected, `false` otherwise). + */ + bool GetState(void) const { return mJamState; } + + /** + * Set the Jam Detection RSSI Threshold (in dBm). + * + * @param[in] aRssiThreshold The RSSI threshold. + * + * @retval kThreadErrorNone Successfully set the threshold. + * + */ + ThreadError SetRssiThreshold(int8_t aThreshold); + + /** + * Get the Jam Detection RSSI Threshold (in dBm). + * + * @returns The Jam Detection RSSI Threshold. + */ + int8_t GetRssiThreshold(void) const { return mRssiThreshold; } + + /** + * Set the Jam Detection Detection Window (in seconds). + * + * @param[in] aWindow The Jam Detection window (valid range is 1 to 63) + * + * @retval kThreadErrorNone Successfully set the window. + * @retval kThreadErrorInvalidArgs The given input parameter not within valid range (1-63) + * + */ + ThreadError SetWindow(uint8_t aWindow); + + /** + * Get the Jam Detection Detection Window (in seconds). + * + * @returns The Jam Detection Window. + */ + uint8_t GetWindow(void) const { return mWindow; } + + /** + * Set the Jam Detection Busy Period (in seconds). + * + * The number of aggregate seconds within the detection window where the RSSI must be above + * threshold to trigger detection. + * + * @param[in] aBusyPeriod The Jam Detection busy period (should be non-zero and + less than or equal to Jam Detection Window) + * + * @retval kThreadErrorNone Successfully set the window. + * @retval kThreadErrorInvalidArgs The given input is not within the valid range. + * + */ + ThreadError SetBusyPeriod(uint8_t aBusyPeriod); + + /** + * Get the Jam Detection Busy Period (in seconds) + * + * @returns The Jam Detection Busy Period + */ + uint8_t GetBusyPeriod(void) const { return mBusyPeriod; } + +private: + static void HandleTimer(void *aContext); + void HandleTimer(void); + void UpdateHistory(bool aThresholdExceeded); + void UpdateJamState(void); + +private: + enum + { + kMaxWindow = 63, // Max window size + kDefaultRssiThreshold = 0, + + kMaxSampleInterval = 256, // in ms + kMinSampleInterval = 2, // in ms + kMaxRandomDelay = 4, // in ms + kOneSecondInterval = 1000 // in ms + + }; + + ThreadNetif &mNetif; + Handler mHandler; // Handler/callback to inform about jamming state + void *mContext; // Context for handler/callback + int8_t mRssiThreshold; // RSSI threshold for jam detection + Timer mTimer; // RSSI sample timer + uint64_t mHistoryBitmap; // History bitmap, each bit correspond to 1 sec interval + uint32_t mCurSecondStartTime; // Start time for current 1 sec interval + uint16_t mSampleInterval; // Current sample interval + uint8_t mWindow : 6; // Window (in sec) to monitor jamming + uint8_t mBusyPeriod : 6; // BusyPeriod (in sec) with mWindow to alert jamming + bool mEnabled : 1; // If jam detection is enabled + bool mAlwaysAboveThreshold : 1; // State for current 1 sec interval + bool mJamState : 1; // Current jam state +}; + +/** + * @} + * + */ + +} // namespace Utils +} // namespace Thread + +#endif // JAM_DETECTOR_HPP_ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index ec6b3d699..91904c97a 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -44,6 +44,9 @@ #include #include #include +#if OPENTHREAD_ENABLE_JAM_DETECTION +#include +#endif #include #include #include @@ -160,6 +163,14 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_STREAM_NET, &NcpBase::GetPropertyHandler_STREAM_NET }, +#if OPENTHREAD_ENABLE_JAM_DETECTION + { SPINEL_PROP_JAM_DETECT_ENABLE, &NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE }, + { SPINEL_PROP_JAM_DETECTED, &NcpBase::GetPropertyHandler_JAM_DETECTED }, + { SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, &NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD }, + { SPINEL_PROP_JAM_DETECT_WINDOW, &NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW }, + { SPINEL_PROP_JAM_DETECT_BUSY, &NcpBase::GetPropertyHandler_JAM_DETECT_BUSY }, +#endif + { SPINEL_PROP_CNTR_TX_PKT_TOTAL, &NcpBase::GetPropertyHandler_MAC_CNTR }, { SPINEL_PROP_CNTR_TX_PKT_ACK_REQ, &NcpBase::GetPropertyHandler_MAC_CNTR }, { SPINEL_PROP_CNTR_TX_PKT_ACKED, &NcpBase::GetPropertyHandler_MAC_CNTR }, @@ -253,6 +264,13 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = { SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER, &NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER }, { SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID, &NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID }, +#if OPENTHREAD_ENABLE_JAM_DETECTION + { SPINEL_PROP_JAM_DETECT_ENABLE, &NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE }, + { SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, &NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD }, + { SPINEL_PROP_JAM_DETECT_WINDOW, &NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW }, + { SPINEL_PROP_JAM_DETECT_BUSY, &NcpBase::SetPropertyHandler_JAM_DETECT_BUSY }, +#endif + #if OPENTHREAD_ENABLE_DIAG { SPINEL_PROP_NEST_STREAM_MFG, &NcpBase::SetPropertyHandler_NEST_STREAM_MFG }, #endif @@ -444,6 +462,9 @@ NcpBase::NcpBase(otInstance *aInstance): mChannelMask = mSupportedChannelMask; mScanPeriod = 200; // ms mShouldSignalEndOfScan = false; +#if OPENTHREAD_ENABLE_JAM_DETECTION + mShouldSignalJamStateChange = false; +#endif sNcpContext = this; mChangedFlags = NCP_PLAT_RESET_REASON; mAllowLocalNetworkDataChange = false; @@ -966,6 +987,22 @@ void NcpBase::HandleSpaceAvailableInTxBuffer(void) mShouldSignalEndOfScan = false; } +#if OPENTHREAD_ENABLE_JAM_DETECTION + if (mShouldSignalJamStateChange) + { + SuccessOrExit( + SendPropertyUpdate( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_JAM_DETECTED, + SPINEL_DATATYPE_BOOL_S, + otGetJamDetectionState(mInstance) + )); + + mShouldSignalJamStateChange = false; + } +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + UpdateChangedProps(); exit: @@ -1434,6 +1471,10 @@ ThreadError NcpBase::GetPropertyHandler_CAPS(uint8_t header, spinel_prop_key_t k SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_WHITELIST)); +#if OPENTHREAD_ENABLE_JAM_DETECTION + SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_JAM_DETECT)); +#endif + // TODO: Somehow get the following capability from the radio. SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_802_15_4_2450MHZ_OQPSK)); @@ -2379,6 +2420,65 @@ ThreadError NcpBase::GetPropertyHandler_STREAM_NET(uint8_t header, spinel_prop_k return SendLastStatus(header, SPINEL_STATUS_UNIMPLEMENTED); } +#if OPENTHREAD_ENABLE_JAM_DETECTION + +ThreadError NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_BOOL_S, + otIsJamDetectionEnabled(mInstance) + ); +} + +ThreadError NcpBase::GetPropertyHandler_JAM_DETECTED(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_BOOL_S, + otGetJamDetectionState(mInstance) + ); +} + +ThreadError NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_INT8_S, + otGetJamDetectionRssiThreshold(mInstance) + ); +} + +ThreadError NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_UINT8_S, + otGetJamDetectionWindow(mInstance) + ); +} + +ThreadError NcpBase::GetPropertyHandler_JAM_DETECT_BUSY(uint8_t header, spinel_prop_key_t key) +{ + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_UINT8_S, + otGetJamDetectionBusyPeriod(mInstance) + ); +} + +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + ThreadError NcpBase::GetPropertyHandler_MAC_CNTR(uint8_t header, spinel_prop_key_t key) { uint32_t value; @@ -4328,6 +4428,176 @@ ThreadError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t header return errorCode; } +#if OPENTHREAD_ENABLE_JAM_DETECTION + +ThreadError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + bool isEnabled; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_BOOL_S, + &isEnabled + ); + + if (parsedLength > 0) + { + if (isEnabled) + { + otStartJamDetection(mInstance, &NcpBase::HandleJamStateChange_Jump, this); + } + else + { + otStopJamDetection(mInstance); + } + + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +ThreadError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + int8_t value = 0; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_INT8_S, + &value + ); + + if (parsedLength > 0) + { + errorCode = otSetJamDetectionRssiThreshold(mInstance, value); + + if (errorCode == kThreadError_None) + { + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +ThreadError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t header, spinel_prop_key_t key, + const uint8_t *value_ptr, uint16_t value_len) +{ + uint8_t value = 0; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_UINT8_S, + &value + ); + + if (parsedLength > 0) + { + errorCode = otSetJamDetectionWindow(mInstance, value); + + if (errorCode == kThreadError_None) + { + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +ThreadError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, + uint16_t value_len) +{ + uint8_t value = 0; + spinel_ssize_t parsedLength; + ThreadError errorCode = kThreadError_None; + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + SPINEL_DATATYPE_UINT8_S, + &value + ); + + if (parsedLength > 0) + { + errorCode = otSetJamDetectionBusyPeriod(mInstance, value); + + if (errorCode == kThreadError_None) + { + errorCode = HandleCommandPropertyGet(header, key); + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + } + else + { + errorCode = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR); + } + + return errorCode; +} + +void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext) +{ + static_cast(aContext)->HandleJamStateChange(aJamState); +} + +void NcpBase::HandleJamStateChange(bool aJamState) +{ + ThreadError errorCode; + + errorCode = SendPropertyUpdate( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_JAM_DETECTED, + SPINEL_DATATYPE_BOOL_S, + aJamState + ); + + // If we could not send the jam state change indicator (no + // buffer space), we set `mShouldSignalJamStateChange` to true to send + // it out when buffer space becomes available. + if (errorCode != kThreadError_None) + { + mShouldSignalJamStateChange = true; + } +} + +#endif // OPENTHREAD_ENABLE_JAM_DETECTION + #if OPENTHREAD_ENABLE_DIAG ThreadError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index ef71587aa..b0fcf6f9c 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -166,6 +166,13 @@ private: void HandleEnergyScanResult(otEnergyScanResult *result); + /** + * Trampoline for HandleJamStateChange(). + */ + static void HandleJamStateChange_Jump(bool aJamState, void *aContext); + + void HandleJamStateChange(bool aJamState); + /** * Trampoline for UpdateChangedProps(). */ @@ -346,6 +353,14 @@ private: ThreadError GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t header, spinel_prop_key_t key); +#if OPENTHREAD_ENABLE_JAM_DETECTION + ThreadError GetPropertyHandler_JAM_DETECT_ENABLE(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_JAM_DETECTED(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_JAM_DETECT_WINDOW(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_JAM_DETECT_BUSY(uint8_t header, spinel_prop_key_t key); +#endif + #if OPENTHREAD_ENABLE_LEGACY ThreadError GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t header, spinel_prop_key_t key); #endif @@ -389,7 +404,7 @@ private: ThreadError SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, - uint16_t value_len); + uint16_t value_len); ThreadError SetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -422,6 +437,13 @@ private: ThreadError SetPropertyHandler_CNTR_RESET(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_JAM_DETECTION + ThreadError SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); + ThreadError SetPropertyHandler_JAM_DETECT_BUSY(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#endif + #if OPENTHREAD_ENABLE_DIAG ThreadError SetPropertyHandler_NEST_STREAM_MFG(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); @@ -479,6 +501,10 @@ private: bool mShouldSignalEndOfScan; +#if OPENTHREAD_ENABLE_JAM_DETECTION + bool mShouldSignalJamStateChange; +#endif + spinel_tid_t mDroppedReplyTid; uint16_t mDroppedReplyTidBitSet; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 26acc789e..9657f8f36 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -384,20 +384,21 @@ typedef enum * dBm) above which the jamming detection will consider the * channel blocked. */ - SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD = SPINEL_PROP_PHY_EXT__BEGIN + 2, + SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD + = SPINEL_PROP_PHY_EXT__BEGIN + 2, /// Jamming detection window size - /** Format: `c` - * Units: Seconds (1-64) + /** Format: `C` + * Units: Seconds (1-63) * * This parameter describes the window period for signal jamming * detection. */ - SPINEL_PROP_JAM_DETECT_WINDOW = SPINEL_PROP_PHY_EXT__BEGIN + 3, + SPINEL_PROP_JAM_DETECT_WINDOW = SPINEL_PROP_PHY_EXT__BEGIN + 3, /// Jamming detection busy period - /** Format: `c` - * Units: Seconds (1-64) + /** Format: `C` + * Units: Seconds (1-63) * * This parameter describes the number of aggregate seconds within * the detection window where the RSSI must be above @@ -406,7 +407,7 @@ typedef enum * The behavior of the jamming detection feature when `PROP_JAM_DETECT_BUSY` * is larger than `PROP_JAM_DETECT_WINDOW` is undefined. */ - SPINEL_PROP_JAM_DETECT_BUSY = SPINEL_PROP_PHY_EXT__BEGIN + 4, + SPINEL_PROP_JAM_DETECT_BUSY = SPINEL_PROP_PHY_EXT__BEGIN + 4, SPINEL_PROP_PHY_EXT__END = 0x1300,