From 4c06b47c34a6493d443e2ae292f649efd49c56b9 Mon Sep 17 00:00:00 2001 From: Shu Chen Date: Tue, 9 Apr 2019 01:35:18 +0800 Subject: [PATCH] [channelmask] add radio supported and preferred channel mask (#3732) Add new radio platform APIs: * otPlatRadioGetSupportedChannelMask(); // supported channel mask: the device is allowed to be on; * otPlatRadioGetPreferredChannelMask(); // preferred channel mask: the device prefers to form on. Implement some default radio platform APIs. Add spinel property `SPINEL_PROP_PHY_CHAN_PREFERRED` to retrieve Preferred ChannelMask. --- Android.mk | 1 + etc/visual-studio/libopenthread.vcxproj | 1 + .../libopenthread.vcxproj.filters | 3 ++ etc/visual-studio/libopenthread_k.vcxproj | 1 + .../libopenthread_k.vcxproj.filters | 3 ++ include/openthread/link.h | 10 ---- include/openthread/platform/radio.h | 20 ++++++++ src/core/Makefile.am | 2 + src/core/api/link_api.cpp | 6 --- src/core/mac/mac.cpp | 6 +-- src/core/meshcop/dataset_manager.cpp | 2 +- src/core/phy/radio_weak.cpp | 49 +++++++++++++++++++ src/core/thread/announce_sender.cpp | 2 +- src/core/thread/mesh_forwarder.cpp | 5 +- src/core/utils/channel_manager.cpp | 4 +- src/ncp/ncp_base.cpp | 14 ++++++ src/ncp/ncp_base_dispatcher.cpp | 9 ++-- src/ncp/ncp_base_mtd.cpp | 5 -- src/ncp/spinel.c | 4 ++ src/ncp/spinel.h | 1 + src/posix/platform/radio_spinel.cpp | 42 ++++++++++++++++ src/posix/platform/radio_spinel.hpp | 21 ++++++-- 22 files changed, 174 insertions(+), 37 deletions(-) create mode 100644 src/core/phy/radio_weak.cpp diff --git a/Android.mk b/Android.mk index 025bc66f9..ee4bbb8c5 100644 --- a/Android.mk +++ b/Android.mk @@ -163,6 +163,7 @@ LOCAL_SRC_FILES := \ src/core/net/ip6_routes.cpp \ src/core/net/netif.cpp \ src/core/net/udp6.cpp \ + src/core/phy/radio_weak.cpp \ src/core/thread/address_resolver.cpp \ src/core/thread/announce_begin_server.cpp \ src/core/thread/announce_sender.cpp \ diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index 712b55d6c..f31d2fc74 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -126,6 +126,7 @@ + diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index d9c6e7127..69b3ab7fd 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -213,6 +213,9 @@ Source Files\net + + Source Files\phy + Source Files\thread diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index cb35102bf..4f905aedb 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -133,6 +133,7 @@ + diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 5ad9902e6..8a8a9bad8 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -207,6 +207,9 @@ Source Files\net + + Source Files\phy + Source Files\thread diff --git a/include/openthread/link.h b/include/openthread/link.h index 85711058d..446e42700 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -821,16 +821,6 @@ OTAPI uint8_t OTCALL otLinkGetPhyChannelMin(otInstance *aInstance); */ OTAPI uint8_t OTCALL otLinkGetPhyChannelMax(otInstance *aInstance); -/** - * This function gets the supported channel mask of IEEE 802.15.4 physical layer. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @returns The supported channel mask as `uint32_t` with bit 0 (lsb) mapping to channel 0, bit 1 to channel 1, so on. - * - */ -OTAPI uint32_t OTCALL otLinkGetPhySupportedChannelMask(otInstance *aInstance); - /** * @} * diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index d9d822e1f..7712b2c18 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -694,6 +694,26 @@ void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance); */ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance); +/** + * Get the radio supported channel mask that the device is allowed to be on. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @returns The radio supported channel mask. + * + */ +uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance); + +/** + * Get the radio preferred channel mask that the device prefers to form on. + * + * @param[in] aInstance The OpenThread instance strucyyture. + * + * @returns The radio preferred channel mask. + * + */ +uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance); + /** * @} * diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 5e866f970..7126099e8 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -187,6 +187,7 @@ SOURCES_COMMON = \ net/netif.cpp \ net/sntp_client.cpp \ net/udp6.cpp \ + phy/radio_weak.cpp \ thread/address_resolver.cpp \ thread/announce_begin_server.cpp \ thread/announce_sender.cpp \ @@ -244,6 +245,7 @@ libopenthread_radio_a_SOURCES = \ mac/mac_frame.cpp \ mac/sub_mac.cpp \ mac/sub_mac_callbacks.cpp \ + phy/radio_weak.cpp \ thread/link_quality.cpp \ utils/missing_strlcat.c \ utils/missing_strlcpy.c \ diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp index bdea5c70a..27203d8c5 100644 --- a/src/core/api/link_api.cpp +++ b/src/core/api/link_api.cpp @@ -443,9 +443,3 @@ uint8_t otLinkGetPhyChannelMax(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); return Phy::kChannelMax; } - -uint32_t otLinkGetPhySupportedChannelMask(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return Phy::kSupportedChannels; -} diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index a30ef01d7..ebdf1412c 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -91,7 +91,7 @@ Mac::Mac(Instance &aInstance) , mPanChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL) , mRadioChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL) , mRadioChannelAcquisitionId(0) - , mSupportedChannelMask(Phy::kSupportedChannels) + , mSupportedChannelMask(otPlatRadioGetSupportedChannelMask(&aInstance)) , mScanChannel(Phy::kChannelMin) , mScanDuration(0) , mScanChannelMask() @@ -166,7 +166,7 @@ void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanD if (aScanChannels == 0) { - aScanChannels = Phy::kSupportedChannels; + aScanChannels = GetSupportedChannelMask().GetMask(); } mScanChannelMask.SetMask(aScanChannels); @@ -425,7 +425,7 @@ void Mac::SetSupportedChannelMask(const ChannelMask &aMask) { ChannelMask newMask = aMask; - newMask.Intersect(ChannelMask(Phy::kSupportedChannels)); + newMask.Intersect(ChannelMask(otPlatRadioGetSupportedChannelMask(&GetInstance()))); VerifyOrExit(newMask != mSupportedChannelMask, Get().SignalIfFirst(OT_CHANGED_SUPPORTED_CHANNEL_MASK)); mSupportedChannelMask = newMask; diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 04a64f3a8..29c836e27 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -227,7 +227,7 @@ otError DatasetManager::GetChannelMask(Mac::ChannelMask &aChannelMask) const VerifyOrExit(channelMaskTlv != NULL, error = OT_ERROR_NOT_FOUND); VerifyOrExit((mask = channelMaskTlv->GetChannelMask()) != 0); - aChannelMask.SetMask(mask & Phy::kSupportedChannels); + aChannelMask.SetMask(mask & Get().GetSupportedChannelMask().GetMask()); VerifyOrExit(!aChannelMask.IsEmpty(), error = OT_ERROR_NOT_FOUND); diff --git a/src/core/phy/radio_weak.cpp b/src/core/phy/radio_weak.cpp new file mode 100644 index 000000000..e377c58a8 --- /dev/null +++ b/src/core/phy/radio_weak.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, 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 default radio platform APIs. + */ + +#include + +#include "phy/phy.hpp" + +using namespace ot; + +OT_TOOL_WEAK uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + + return Phy::kSupportedChannels; +} + +OT_TOOL_WEAK uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance) +{ + return otPlatRadioGetSupportedChannelMask(aInstance); +} diff --git a/src/core/thread/announce_sender.cpp b/src/core/thread/announce_sender.cpp index cb2f45a9e..b24b12760 100644 --- a/src/core/thread/announce_sender.cpp +++ b/src/core/thread/announce_sender.cpp @@ -69,7 +69,7 @@ otError AnnounceSenderBase::SendAnnounce(Mac::ChannelMask aChannelMask, VerifyOrExit(aPeriod != 0, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(aJitter < aPeriod, error = OT_ERROR_INVALID_ARGS); - aChannelMask.Intersect(Mac::ChannelMask(Phy::kSupportedChannels)); + aChannelMask.Intersect(Get().GetSupportedChannelMask()); VerifyOrExit(!aChannelMask.IsEmpty(), error = OT_ERROR_INVALID_ARGS); mChannelMask = aChannelMask; diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index a439da9de..4da73e537 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1153,9 +1153,10 @@ exit: void MeshForwarder::SetDiscoverParameters(const Mac::ChannelMask &aScanChannels) { uint32_t mask; + uint32_t supportedMask = Get().GetSupportedChannelMask().GetMask(); - mask = aScanChannels.IsEmpty() ? static_cast(Phy::kSupportedChannels) : aScanChannels.GetMask(); - mScanChannels.SetMask(mask & Phy::kSupportedChannels); + mask = aScanChannels.IsEmpty() ? supportedMask : aScanChannels.GetMask(); + mScanChannels.SetMask(mask & supportedMask); } void MeshForwarder::HandleDiscoverTimer(Timer &aTimer) diff --git a/src/core/utils/channel_manager.cpp b/src/core/utils/channel_manager.cpp index b9a37ab02..ab356d6d5 100644 --- a/src/core/utils/channel_manager.cpp +++ b/src/core/utils/channel_manager.cpp @@ -480,14 +480,14 @@ exit: void ChannelManager::SetSupportedChannels(uint32_t aChannelMask) { - mSupportedChannelMask.SetMask(aChannelMask & Phy::kSupportedChannels); + mSupportedChannelMask.SetMask(aChannelMask & Get().GetSupportedChannelMask().GetMask()); otLogInfoUtil("ChannelManager: Supported channels: %s", mSupportedChannelMask.ToString().AsCString()); } void ChannelManager::SetFavoredChannels(uint32_t aChannelMask) { - mFavoredChannelMask.SetMask(aChannelMask & Phy::kSupportedChannels); + mFavoredChannelMask.SetMask(aChannelMask & Get().GetSupportedChannelMask().GetMask()); otLogInfoUtil("ChannelManager: Favored channels: %s", mFavoredChannelMask.ToString().AsCString()); } diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 68e60b63c..3f960ede5 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -2173,6 +2173,20 @@ exit: return error; } +template <> otError NcpBase::HandlePropertyGet(void) +{ +#if OPENTHREAD_RADIO + return EncodeChannelMask(otPlatRadioGetSupportedChannelMask(mInstance)); +#else + return EncodeChannelMask(otLinkGetSupportedChannelMask(mInstance)); +#endif // OPENTHREAD_RADIO +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return EncodeChannelMask(otPlatRadioGetPreferredChannelMask(mInstance)); +} + } // namespace Ncp } // namespace ot diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 5d269e3df..cdd9792af 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -134,6 +134,12 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_VENDOR_ID: handler = &NcpBase::HandlePropertyGet; break; + case SPINEL_PROP_PHY_CHAN_SUPPORTED: + handler = &NcpBase::HandlePropertyGet; + break; + case SPINEL_PROP_PHY_CHAN_PREFERRED: + handler = &NcpBase::HandlePropertyGet; + break; // -------------------------------------------------------------------------- // MTD (or FTD) Properties (Get Handler) @@ -171,9 +177,6 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) case SPINEL_PROP_MSG_BUFFER_COUNTERS: handler = &NcpBase::HandlePropertyGet; break; - case SPINEL_PROP_PHY_CHAN_SUPPORTED: - handler = &NcpBase::HandlePropertyGet; - break; case SPINEL_PROP_PHY_FREQ: handler = &NcpBase::HandlePropertyGet; break; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 845624b3f..649443882 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -207,11 +207,6 @@ template <> otError NcpBase::HandlePropertyGet(void) return mEncoder.WriteUint32(freq_khz); } -template <> otError NcpBase::HandlePropertyGet(void) -{ - return EncodeChannelMask(otLinkGetPhySupportedChannelMask(mInstance)); -} - template <> otError NcpBase::HandlePropertySet(void) { uint32_t newMask = 0; diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index 2175cbe44..b71c37f4a 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1295,6 +1295,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PHY_PCAP_ENABLED"; break; + case SPINEL_PROP_PHY_CHAN_PREFERRED: + ret = "PHY_CHAN_PREFERRED"; + break; + case SPINEL_PROP_JAM_DETECT_ENABLE: ret = "JAM_DETECT_ENABLE"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 3eed685c4..5403f75f5 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -1198,6 +1198,7 @@ typedef enum SPINEL_PROP_PHY_RSSI = SPINEL_PROP_PHY__BEGIN + 6, ///< dBm [c] SPINEL_PROP_PHY_RX_SENSITIVITY = SPINEL_PROP_PHY__BEGIN + 7, ///< dBm [c] SPINEL_PROP_PHY_PCAP_ENABLED = SPINEL_PROP_PHY__BEGIN + 8, ///< [b] + SPINEL_PROP_PHY_CHAN_PREFERRED = SPINEL_PROP_PHY__BEGIN + 9, ///< [A(C)] SPINEL_PROP_PHY__END = 0x30, SPINEL_PROP_PHY_EXT__BEGIN = 0x1200, diff --git a/src/posix/platform/radio_spinel.cpp b/src/posix/platform/radio_spinel.cpp index 412b3b827..6d3b07160 100644 --- a/src/posix/platform/radio_spinel.cpp +++ b/src/posix/platform/radio_spinel.cpp @@ -1361,6 +1361,36 @@ otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t } #endif +uint32_t RadioSpinel::GetRadioChannelMask(bool aPreferred) +{ + uint8_t maskBuffer[kChannelMaskBufferSize]; + otError error = OT_ERROR_NONE; + uint32_t channelMask = 0; + const uint8_t *maskData = maskBuffer; + spinel_size_t maskLength = sizeof(maskBuffer); + + SuccessOrExit(error = Get(aPreferred ? SPINEL_PROP_PHY_CHAN_PREFERRED : SPINEL_PROP_PHY_CHAN_SUPPORTED, + SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength)); + + while (maskLength > 0) + { + uint8_t channel; + spinel_ssize_t unpacked; + + unpacked = spinel_datatype_unpack(maskData, maskLength, SPINEL_DATATYPE_UINT8_S, &channel); + VerifyOrExit(unpacked > 0, error = OT_ERROR_FAILED); + VerifyOrExit(channel < kChannelMaskBufferSize, error = OT_ERROR_PARSE); + channelMask |= (1UL << channel); + + maskData += unpacked; + maskLength -= static_cast(unpacked); + } + +exit: + LogIfFail("Get radio channel mask failed", error); + return channelMask; +} + } // namespace PosixApp } // namespace ot @@ -1695,3 +1725,15 @@ void otPlatDiagAlarmCallback(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); } #endif // OPENTHREAD_ENABLE_DIAG + +uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRadioChannelMask(false); +} + +uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRadioChannelMask(true); +} diff --git a/src/posix/platform/radio_spinel.hpp b/src/posix/platform/radio_spinel.hpp index eeb1435d0..8800363a4 100644 --- a/src/posix/platform/radio_spinel.hpp +++ b/src/posix/platform/radio_spinel.hpp @@ -439,6 +439,18 @@ public: otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen); #endif + /** + * This method returns the radio channel mask. + * + * @param[in] aPreferred TRUE to get preferred channel mask, FALSE to get supported channel mask. + * + * @returns The radio channel mask according to @aPreferred: + * The radio supported channel mask that the device is allowed to be on. + * The radio preferred channel mask that the device prefers to form on. + * + */ + uint32_t GetRadioChannelMask(bool aPreferred); + /** * This method processes a received Spinel frame. * @@ -449,10 +461,11 @@ public: private: enum { - kMaxSpinelFrame = HdlcInterface::kMaxFrameSize, - kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds. - kVersionStringSize = 128, ///< Max size of version string. - kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value. + kMaxSpinelFrame = HdlcInterface::kMaxFrameSize, + kMaxWaitTime = 2000, ///< Max time to wait for response in milliseconds. + kVersionStringSize = 128, ///< Max size of version string. + kCapsBufferSize = 100, ///< Max buffer size used to store `SPINEL_PROP_CAPS` value. + kChannelMaskBufferSize = 32, ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value. }; enum State