diff --git a/src/core/meshcop/energy_scan_client.cpp b/src/core/meshcop/energy_scan_client.cpp index 09e8fbdd1..ab80da113 100644 --- a/src/core/meshcop/energy_scan_client.cpp +++ b/src/core/meshcop/energy_scan_client.cpp @@ -43,6 +43,7 @@ #include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "common/num_utils.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" @@ -111,14 +112,8 @@ void EnergyScanClient::HandleReport(void *aContext, otMessage *aMessage, const o void EnergyScanClient::HandleReport(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - uint32_t mask; - - OT_TOOL_PACKED_BEGIN - struct - { - MeshCoP::EnergyListTlv tlv; - uint8_t list[OPENTHREAD_CONFIG_TMF_ENERGY_SCAN_MAX_RESULTS]; - } OT_TOOL_PACKED_END energyList; + uint32_t mask; + MeshCoP::EnergyListTlv energyListTlv; VerifyOrExit(aMessage.IsConfirmablePostRequest()); @@ -126,12 +121,11 @@ void EnergyScanClient::HandleReport(Coap::Message &aMessage, const Ip6::MessageI VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); - SuccessOrExit(MeshCoP::Tlv::FindTlv(aMessage, MeshCoP::Tlv::kEnergyList, sizeof(energyList), energyList.tlv)); - VerifyOrExit(energyList.tlv.IsValid()); + SuccessOrExit(MeshCoP::Tlv::FindTlv(aMessage, MeshCoP::Tlv::kEnergyList, sizeof(energyListTlv), energyListTlv)); if (mCallback != nullptr) { - mCallback(mask, energyList.list, energyList.tlv.GetLength(), mContext); + mCallback(mask, energyListTlv.GetEnergyList(), energyListTlv.GetEnergyListLength(), mContext); } SuccessOrExit(Get().SendEmptyAck(aMessage, aMessageInfo)); diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index c21e79984..9cc84aa0a 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -44,6 +44,7 @@ #include "common/const_cast.hpp" #include "common/encoding.hpp" #include "common/message.hpp" +#include "common/num_utils.hpp" #include "common/string.hpp" #include "common/tlvs.hpp" #include "mac/mac_types.hpp" @@ -1557,6 +1558,27 @@ public: * */ bool IsValid(void) const { return true; } + + /** + * This method returns a pointer to the start of energy measurement list. + * + * @returns A pointer to the start start of energy energy measurement list. + * + */ + const uint8_t *GetEnergyList(void) const { return mEnergyList; } + + /** + * This method returns the length of energy measurement list. + * + * @returns The length of energy measurement list. + * + */ + uint8_t GetEnergyListLength(void) const { return Min(kMaxListLength, GetLength()); } + +private: + static constexpr uint8_t kMaxListLength = OPENTHREAD_CONFIG_TMF_ENERGY_SCAN_MAX_RESULTS; + + uint8_t mEnergyList[kMaxListLength]; } OT_TOOL_PACKED_END; /** diff --git a/src/core/thread/energy_scan_server.cpp b/src/core/thread/energy_scan_server.cpp index 75e4e9d66..06728ea99 100644 --- a/src/core/thread/energy_scan_server.cpp +++ b/src/core/thread/energy_scan_server.cpp @@ -56,8 +56,7 @@ EnergyScanServer::EnergyScanServer(Instance &aInstance) , mPeriod(0) , mScanDuration(0) , mCount(0) - , mActive(false) - , mScanResultsLength(0) + , mReportMessage(nullptr) , mTimer(aInstance) , mEnergyScan(UriPath::kEnergyScan, &EnergyScanServer::HandleRequest, this) { @@ -71,11 +70,12 @@ void EnergyScanServer::HandleRequest(void *aContext, otMessage *aMessage, const void EnergyScanServer::HandleRequest(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - uint8_t count; - uint16_t period; - uint16_t scanDuration; - Ip6::MessageInfo responseInfo(aMessageInfo); - uint32_t mask; + uint8_t count; + uint16_t period; + uint16_t scanDuration; + uint32_t mask; + MeshCoP::Tlv tlv; + MeshCoP::ChannelMaskTlv channelMaskTlv; VerifyOrExit(aMessage.IsPostRequest()); @@ -85,20 +85,30 @@ void EnergyScanServer::HandleRequest(Coap::Message &aMessage, const Ip6::Message VerifyOrExit((mask = MeshCoP::ChannelMaskTlv::GetChannelMask(aMessage)) != 0); + FreeMessage(mReportMessage); + mReportMessage = Get().NewPriorityConfirmablePostMessage(UriPath::kEnergyReport); + VerifyOrExit(mReportMessage != nullptr); + + channelMaskTlv.Init(); + channelMaskTlv.SetChannelMask(mask); + SuccessOrExit(channelMaskTlv.AppendTo(*mReportMessage)); + + tlv.SetType(MeshCoP::Tlv::kEnergyList); + SuccessOrExit(mReportMessage->Append(tlv)); + + mNumScanResults = 0; mChannelMask = mask; mChannelMaskCurrent = mChannelMask; mCount = count; mPeriod = period; mScanDuration = scanDuration; - mScanResultsLength = 0; - mActive = true; mTimer.Start(kScanDelay); mCommissioner = aMessageInfo.GetPeerAddr(); if (aMessage.IsConfirmable() && !aMessageInfo.GetSockAddr().IsMulticast()) { - SuccessOrExit(Get().SendEmptyAck(aMessage, responseInfo)); + SuccessOrExit(Get().SendEmptyAck(aMessage, aMessageInfo)); LogInfo("sent energy scan query response"); } @@ -108,12 +118,13 @@ exit: void EnergyScanServer::HandleTimer(void) { - VerifyOrExit(mActive); + VerifyOrExit(mReportMessage != nullptr); if (mCount) { // grab the lowest channel to scan uint32_t channelMask = mChannelMaskCurrent & ~(mChannelMaskCurrent - 1); + IgnoreError(Get().EnergyScan(channelMask, mScanDuration, HandleScanResult, this)); } else @@ -132,16 +143,31 @@ void EnergyScanServer::HandleScanResult(Mac::EnergyScanResult *aResult, void *aC void EnergyScanServer::HandleScanResult(Mac::EnergyScanResult *aResult) { - VerifyOrExit(mActive); + VerifyOrExit(mReportMessage != nullptr); if (aResult) { - VerifyOrExit(mScanResultsLength < OPENTHREAD_CONFIG_TMF_ENERGY_SCAN_MAX_RESULTS); - mScanResults[mScanResultsLength++] = aResult->mMaxRssi; + if (mReportMessage->Append(aResult->mMaxRssi) != kErrorNone) + { + FreeMessage(mReportMessage); + mReportMessage = nullptr; + ExitNow(); + } + + mNumScanResults++; + + if (mNumScanResults == NumericLimits::kMax) + { + // If we reach the max length that fit in the Energy List + // TLV we send the current set of energy scan data. + + mCount = 0; + mTimer.Start(kReportDelay); + } } else { - // clear the lowest channel to scan + // Clear the lowest channel to scan mChannelMaskCurrent &= mChannelMaskCurrent - 1; if (mChannelMaskCurrent == 0) @@ -166,42 +192,33 @@ exit: void EnergyScanServer::SendReport(void) { - Error error = kErrorNone; - MeshCoP::ChannelMaskTlv channelMask; - MeshCoP::EnergyListTlv energyList; - Tmf::MessageInfo messageInfo(GetInstance()); - Coap::Message * message; + Error error = kErrorNone; + Tmf::MessageInfo messageInfo(GetInstance()); + uint16_t offset; - message = Get().NewPriorityConfirmablePostMessage(UriPath::kEnergyReport); - VerifyOrExit(message != nullptr, error = kErrorNoBufs); - - channelMask.Init(); - channelMask.SetChannelMask(mChannelMask); - SuccessOrExit(error = channelMask.AppendTo(*message)); - - energyList.Init(); - energyList.SetLength(mScanResultsLength); - SuccessOrExit(error = message->Append(energyList)); - SuccessOrExit(error = message->AppendBytes(mScanResults, mScanResultsLength)); + // Update the Energy List TLV length in Report message + offset = mReportMessage->GetLength() - mNumScanResults - sizeof(uint8_t); + mReportMessage->Write(offset, mNumScanResults); messageInfo.SetSockAddrToRlocPeerAddrTo(mCommissioner); - SuccessOrExit(error = Get().SendMessage(*message, messageInfo)); + SuccessOrExit(error = Get().SendMessage(*mReportMessage, messageInfo)); LogInfo("sent scan results"); exit: - FreeMessageOnError(message, error); + FreeMessageOnError(mReportMessage, error); MeshCoP::LogError("send scan results", error); - mActive = false; + mReportMessage = nullptr; } void EnergyScanServer::HandleNotifierEvents(Events aEvents) { - if (aEvents.Contains(kEventThreadNetdataChanged) && !mActive && + if (aEvents.Contains(kEventThreadNetdataChanged) && (mReportMessage != nullptr) && Get().GetCommissioningData() == nullptr) { - mActive = false; + mReportMessage->Free(); + mReportMessage = nullptr; mTimer.Stop(); } } diff --git a/src/core/thread/energy_scan_server.hpp b/src/core/thread/energy_scan_server.hpp index bb51c4ba4..da01da667 100644 --- a/src/core/thread/energy_scan_server.hpp +++ b/src/core/thread/energy_scan_server.hpp @@ -63,8 +63,8 @@ public: explicit EnergyScanServer(Instance &aInstance); private: - static constexpr uint32_t kScanDelay = 1000; ///< SCAN_DELAY (milliseconds) - static constexpr uint32_t kReportDelay = 500; ///< Delay before sending a report (milliseconds) + static constexpr uint32_t kScanDelay = 1000; // SCAN_DELAY (milliseconds) + static constexpr uint32_t kReportDelay = 500; // Delay before sending a report (milliseconds) static void HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleRequest(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -80,18 +80,15 @@ private: using ScanTimer = TimerMilliIn; - Ip6::Address mCommissioner; - uint32_t mChannelMask; - uint32_t mChannelMaskCurrent; - uint16_t mPeriod; - uint16_t mScanDuration; - uint8_t mCount; - bool mActive; - - int8_t mScanResults[OPENTHREAD_CONFIG_TMF_ENERGY_SCAN_MAX_RESULTS]; - uint8_t mScanResultsLength; - - ScanTimer mTimer; + Ip6::Address mCommissioner; + uint32_t mChannelMask; + uint32_t mChannelMaskCurrent; + uint16_t mPeriod; + uint16_t mScanDuration; + uint8_t mCount; + uint8_t mNumScanResults; + Coap::Message *mReportMessage; + ScanTimer mTimer; Coap::Resource mEnergyScan; };