mirror of
https://github.com/espressif/openthread.git
synced 2026-10-02 22:07:36 +00:00
Energy scan. (#606)
This commit is contained in:
@@ -66,9 +66,63 @@ ThreadError otCommissionerStart(otInstance *aInstance, const char *aPSKd);
|
||||
*/
|
||||
ThreadError otCommissionerStop(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function pointer is called when the Commissioner receives an Energy Report.
|
||||
*
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aEnergyList A pointer to the energy measurement list.
|
||||
* @param[in] aEnergyListLength Number of entries in @p aEnergyListLength.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
*/
|
||||
typedef void (*otCommissionerEnergyReportCallback)(uint32_t aChannelMask, const uint8_t *aEnergyList,
|
||||
uint8_t aEnergyListLength, void *aContext);
|
||||
|
||||
/**
|
||||
* This function sends an Energy Scan Query message.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aCount The number of energy measurements per channel.
|
||||
* @param[in] aPeriod The time between energy measurements (milliseconds).
|
||||
* @param[in] aScanDuration The scan duration for each energy measurement (milliseconds).
|
||||
* @param[in] aAddress A pointer to the IPv6 destination.
|
||||
* @param[in] aCallback A pointer to a function called on receiving an Energy Report message.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
* @retval kThreadError_None Successfully enqueued the Energy Scan Query message.
|
||||
* @retval kThreadError_NoBufs Insufficient buffers to generate an Energy Scan Query message.
|
||||
*
|
||||
*/
|
||||
ThreadError otCommissionerEnergyScan(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
|
||||
uint16_t aScanDuration, const otIp6Address *aAddress,
|
||||
otCommissionerEnergyReportCallback aCallback, void *aContext);
|
||||
|
||||
/**
|
||||
* This function pointer is called when the Commissioner receives a PAN ID Conflict message.
|
||||
*
|
||||
* @param[in] aPanId The PAN ID value.
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
*/
|
||||
typedef void (*otCommissionerPanIdConflictCallback)(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
|
||||
|
||||
ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aChannelMask,
|
||||
/**
|
||||
* This function sends a PAN ID Query message.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aPanId The PAN ID to query.
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aAddress A pointer to the IPv6 destination.
|
||||
* @param[in] aCallback A pointer to a function called on receiving an Energy Report message.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
* @retval kThreadError_None Successfully enqueued the PAN ID Query message.
|
||||
* @retval kThreadError_NoBufs Insufficient buffers to generate a PAN ID Query message.
|
||||
*
|
||||
*/
|
||||
ThreadError otCommissionerPanIdQuery(otInstance *aInstance, uint16_t aPanId, uint32_t aChannelMask,
|
||||
const otIp6Address *aAddress,
|
||||
otCommissionerPanIdConflictCallback aCallback, void *aContext);
|
||||
|
||||
|
||||
@@ -401,6 +401,10 @@ typedef enum otMeshcopTlvType
|
||||
OT_MESHCOP_TLV_PENDINGTIMESTAMP = 51, ///< meshcop Pending Timestamp TLV
|
||||
OT_MESHCOP_TLV_DELAYTIMER = 52, ///< meshcop Delay Timer TLV
|
||||
OT_MESHCOP_TLV_CHANNELMASK = 53, ///< meshcop Channel Mask TLV
|
||||
OT_MESHCOP_TLV_COUNT = 54, ///< meshcop Count TLV
|
||||
OT_MESHCOP_TLV_PERIOD = 55, ///< meshcop Period TLV
|
||||
OT_MESHCOP_TLV_SCAN_DURATION = 56, ///< meshcop Scan Duration TLV
|
||||
OT_MESHCOP_TLV_ENERGY_LIST = 57, ///< meshcop Energy List TLV
|
||||
OT_MESHCOP_TLV_DISCOVERYREQUEST = 128, ///< meshcop Discovery Request TLV
|
||||
OT_MESHCOP_TLV_DISCOVERYRESPONSE = 129, ///< meshcop Discovery Response TLV
|
||||
} otMeshcopTlvType;
|
||||
|
||||
+57
-2
@@ -1919,6 +1919,40 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[])
|
||||
{
|
||||
otCommissionerStop(mInstance);
|
||||
}
|
||||
else if (strcmp(argv[0], "energy") == 0)
|
||||
{
|
||||
long mask;
|
||||
long count;
|
||||
long period;
|
||||
long scanDuration;
|
||||
otIp6Address address;
|
||||
|
||||
VerifyOrExit(argc > 5, error = kThreadError_Parse);
|
||||
|
||||
// mask
|
||||
SuccessOrExit(error = ParseLong(argv[1], mask));
|
||||
|
||||
// count
|
||||
SuccessOrExit(error = ParseLong(argv[2], count));
|
||||
|
||||
// period
|
||||
SuccessOrExit(error = ParseLong(argv[3], period));
|
||||
|
||||
// scan duration
|
||||
SuccessOrExit(error = ParseLong(argv[4], scanDuration));
|
||||
|
||||
// destination
|
||||
SuccessOrExit(error = otIp6AddressFromString(argv[5], &address));
|
||||
|
||||
SuccessOrExit(error = otCommissionerEnergyScan(mInstance,
|
||||
static_cast<uint32_t>(mask),
|
||||
static_cast<uint8_t>(count),
|
||||
static_cast<uint16_t>(period),
|
||||
static_cast<uint16_t>(scanDuration),
|
||||
&address,
|
||||
Interpreter::s_HandleEnergyReport,
|
||||
this));
|
||||
}
|
||||
else if (strcmp(argv[0], "panid") == 0)
|
||||
{
|
||||
long panid;
|
||||
@@ -1936,15 +1970,36 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[])
|
||||
// destination
|
||||
SuccessOrExit(error = otIp6AddressFromString(argv[3], &address));
|
||||
|
||||
SuccessOrExit(error = otCommissionerPanIdQuery(mInstance, static_cast<uint16_t>(panid),
|
||||
SuccessOrExit(error = otCommissionerPanIdQuery(mInstance,
|
||||
static_cast<uint16_t>(panid),
|
||||
static_cast<uint32_t>(mask),
|
||||
&address, Interpreter::s_HandlePanIdConflict, this));
|
||||
&address,
|
||||
Interpreter::s_HandlePanIdConflict,
|
||||
this));
|
||||
}
|
||||
|
||||
exit:
|
||||
AppendResult(error);
|
||||
}
|
||||
|
||||
void Interpreter::s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
|
||||
void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleEnergyReport(aChannelMask, aEnergyList, aEnergyListLength);
|
||||
}
|
||||
|
||||
void Interpreter::HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength)
|
||||
{
|
||||
sServer->OutputFormat("Energy: %08x ", aChannelMask);
|
||||
|
||||
for (uint8_t i = 0; i < aEnergyListLength; i++)
|
||||
{
|
||||
sServer->OutputFormat("%d ", aEnergyList[i]);
|
||||
}
|
||||
|
||||
sServer->OutputFormat("\r\n");
|
||||
}
|
||||
|
||||
void Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandlePanIdConflict(aPanId, aChannelMask);
|
||||
|
||||
@@ -208,6 +208,8 @@ private:
|
||||
static void s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
|
||||
static void s_HandleNetifStateChanged(uint32_t aFlags, void *aContext);
|
||||
static void s_HandleLinkPcapReceive(const RadioPacket *aFrame, void *aContext);
|
||||
static void s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
|
||||
void *aContext);
|
||||
static void s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
|
||||
|
||||
void HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
@@ -215,6 +217,7 @@ private:
|
||||
void HandleActiveScanResult(otActiveScanResult *aResult);
|
||||
void HandleNetifStateChanged(uint32_t aFlags);
|
||||
void HandleLinkPcapReceive(const RadioPacket *aFrame);
|
||||
void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength);
|
||||
void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask);
|
||||
|
||||
static const struct Command sCommands[];
|
||||
|
||||
@@ -63,6 +63,7 @@ libopenthread_a_SOURCES = \
|
||||
net/netif.cpp \
|
||||
net/udp6.cpp \
|
||||
thread/address_resolver.cpp \
|
||||
thread/energy_scan_server.cpp \
|
||||
thread/key_manager.cpp \
|
||||
thread/link_quality.cpp \
|
||||
thread/lowpan.cpp \
|
||||
@@ -84,6 +85,7 @@ libopenthread_a_SOURCES = \
|
||||
if OPENTHREAD_ENABLE_COMMISSIONER
|
||||
libopenthread_a_SOURCES += \
|
||||
meshcop/commissioner.cpp \
|
||||
meshcop/energy_scan_client.cpp \
|
||||
meshcop/panid_query_client.cpp \
|
||||
$(NULL)
|
||||
endif # OPENTHREAD_ENABLE_COMMISSIONER
|
||||
@@ -124,6 +126,7 @@ noinst_HEADERS = \
|
||||
mac/mac_blacklist.hpp \
|
||||
meshcop/commissioner.hpp \
|
||||
meshcop/dtls.hpp \
|
||||
meshcop/energy_scan_client.hpp \
|
||||
meshcop/joiner.hpp \
|
||||
meshcop/joiner_router.hpp \
|
||||
meshcop/leader.hpp \
|
||||
@@ -140,6 +143,7 @@ noinst_HEADERS = \
|
||||
net/udp6.hpp \
|
||||
net/tcp.hpp \
|
||||
thread/address_resolver.hpp \
|
||||
thread/energy_scan_server.hpp \
|
||||
thread/key_manager.hpp \
|
||||
thread/link_quality.hpp \
|
||||
thread/lowpan.hpp \
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Thread {
|
||||
namespace MeshCoP {
|
||||
|
||||
Commissioner::Commissioner(ThreadNetif &aThreadNetif):
|
||||
mEnergyScan(aThreadNetif),
|
||||
mPanIdQuery(aThreadNetif),
|
||||
mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this),
|
||||
mTransmitTask(aThreadNetif.GetIp6().mTaskletScheduler, &HandleUdpTransmit, this),
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <meshcop/energy_scan_client.hpp>
|
||||
#include <meshcop/panid_query_client.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
#include <thread/mle.hpp>
|
||||
@@ -83,6 +84,7 @@ public:
|
||||
*/
|
||||
uint16_t GetSessionId(void) const;
|
||||
|
||||
EnergyScanClient mEnergyScan;
|
||||
PanIdQueryClient mPanIdQuery;
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 Energy Scan Client.
|
||||
*/
|
||||
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <common/code_utils.hpp>
|
||||
#include <common/debug.hpp>
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/logging.hpp>
|
||||
#include <meshcop/energy_scan_client.hpp>
|
||||
#include <thread/meshcop_tlvs.hpp>
|
||||
#include <thread/thread_netif.hpp>
|
||||
#include <thread/thread_uris.hpp>
|
||||
|
||||
using Thread::Encoding::BigEndian::HostSwap16;
|
||||
using Thread::Encoding::BigEndian::HostSwap32;
|
||||
|
||||
namespace Thread {
|
||||
|
||||
EnergyScanClient::EnergyScanClient(ThreadNetif &aThreadNetif) :
|
||||
mEnergyScan(OPENTHREAD_URI_ENERGY_REPORT, &HandleReport, this),
|
||||
mSocket(aThreadNetif.GetIp6().mUdp),
|
||||
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &HandleTimer, this),
|
||||
mCoapServer(aThreadNetif.GetCoapServer()),
|
||||
mNetif(aThreadNetif)
|
||||
{
|
||||
mCoapServer.AddResource(mEnergyScan);
|
||||
mSocket.Open(HandleUdpReceive, this);
|
||||
}
|
||||
|
||||
ThreadError EnergyScanClient::SendQuery(uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
|
||||
uint16_t aScanDuration, const Ip6::Address &aAddress,
|
||||
otCommissionerEnergyReportCallback aCallback, void *aContext)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Coap::Header header;
|
||||
MeshCoP::CommissionerSessionIdTlv sessionId;
|
||||
MeshCoP::ChannelMaskTlv channelMask;
|
||||
union
|
||||
{
|
||||
MeshCoP::ChannelMaskEntry channelMaskEntry;
|
||||
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(aChannelMask)];
|
||||
};
|
||||
MeshCoP::CountTlv count;
|
||||
MeshCoP::PeriodTlv period;
|
||||
MeshCoP::ScanDurationTlv scanDuration;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Message *message;
|
||||
|
||||
header.Init();
|
||||
header.SetVersion(1);
|
||||
header.SetType(aAddress.IsMulticast() ? Coap::Header::kTypeNonConfirmable : Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(0);
|
||||
header.SetToken(NULL, 0);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ENERGY_SCAN);
|
||||
header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
|
||||
header.Finalize();
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
|
||||
sessionId.Init();
|
||||
sessionId.SetCommissionerSessionId(mNetif.GetCommissioner().GetSessionId());
|
||||
SuccessOrExit(error = message->Append(&sessionId, sizeof(sessionId)));
|
||||
|
||||
channelMask.Init();
|
||||
channelMask.SetLength(sizeof(channelMaskBuf));
|
||||
SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask)));
|
||||
|
||||
channelMaskEntry.SetChannelPage(0);
|
||||
channelMaskEntry.SetMaskLength(sizeof(aChannelMask));
|
||||
|
||||
for (size_t i = 0; i < sizeof(aChannelMask); i++)
|
||||
{
|
||||
channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + i] = (aChannelMask >> (8 * i)) & 0xff;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = message->Append(channelMaskBuf, sizeof(channelMaskBuf)));
|
||||
|
||||
count.Init();
|
||||
count.SetCount(aCount);
|
||||
SuccessOrExit(error = message->Append(&count, sizeof(count)));
|
||||
|
||||
period.Init();
|
||||
period.SetPeriod(aPeriod);
|
||||
SuccessOrExit(error = message->Append(&period, sizeof(period)));
|
||||
|
||||
scanDuration.Init();
|
||||
scanDuration.SetScanDuration(aScanDuration);
|
||||
SuccessOrExit(error = message->Append(&scanDuration, sizeof(scanDuration)));
|
||||
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
messageInfo.GetPeerAddr() = aAddress;
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
|
||||
otLogInfoMeshCoP("sent energy scan query\r\n");
|
||||
|
||||
mCallback = aCallback;
|
||||
mContext = aContext;
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void EnergyScanClient::HandleReport(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
static_cast<EnergyScanClient *>(aContext)->HandleReport(aHeader, aMessage, aMessageInfo);
|
||||
}
|
||||
|
||||
void EnergyScanClient::HandleReport(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct
|
||||
{
|
||||
MeshCoP::ChannelMaskTlv tlv;
|
||||
MeshCoP::ChannelMaskEntry header;
|
||||
uint32_t mask;
|
||||
} OT_TOOL_PACKED_END channelMask;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct
|
||||
{
|
||||
MeshCoP::EnergyListTlv tlv;
|
||||
uint8_t list[OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS];
|
||||
} OT_TOOL_PACKED_END energyList;
|
||||
|
||||
VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeConfirmable &&
|
||||
aHeader.GetCode() == Coap::Header::kCodePost, ;);
|
||||
|
||||
otLogInfoMeshCoP("received energy scan report\r\n");
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kChannelMask, sizeof(channelMask), channelMask.tlv));
|
||||
VerifyOrExit(channelMask.tlv.IsValid() &&
|
||||
channelMask.header.GetChannelPage() == 0 &&
|
||||
channelMask.header.GetMaskLength() >= sizeof(uint32_t), ;);
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kEnergyList, sizeof(energyList), energyList.tlv));
|
||||
VerifyOrExit(energyList.tlv.IsValid(), ;);
|
||||
|
||||
if (mCallback != NULL)
|
||||
{
|
||||
mCallback(HostSwap32(channelMask.mask), energyList.list, energyList.tlv.GetLength(), mContext);
|
||||
}
|
||||
|
||||
SendResponse(aHeader, aMessageInfo);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError EnergyScanClient::SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestInfo)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *message;
|
||||
Coap::Header responseHeader;
|
||||
Ip6::MessageInfo responseInfo;
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
responseHeader.Init();
|
||||
responseHeader.SetVersion(1);
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
memcpy(&responseInfo, &aRequestInfo, sizeof(responseInfo));
|
||||
memset(&responseInfo.mSockAddr, 0, sizeof(responseInfo.mSockAddr));
|
||||
SuccessOrExit(error = mCoapServer.SendMessage(*message, responseInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void EnergyScanClient::HandleTimer(void *aContext)
|
||||
{
|
||||
static_cast<EnergyScanClient *>(aContext)->HandleTimer();
|
||||
}
|
||||
|
||||
void EnergyScanClient::HandleTimer(void)
|
||||
{
|
||||
}
|
||||
|
||||
void EnergyScanClient::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
otLogInfoMeshCoP("received energy scan query response\r\n");
|
||||
(void)aContext;
|
||||
(void)aMessage;
|
||||
(void)aMessageInfo;
|
||||
}
|
||||
|
||||
} // namespace Thread
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 responding to PANID Query Requests.
|
||||
*/
|
||||
|
||||
#ifndef ENERGY_SCAN_CLIENT_HPP_
|
||||
#define ENERGY_SCAN_CLIENT_HPP_
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread-types.h>
|
||||
#include <commissioning/commissioner.h>
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <net/ip6_address.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
|
||||
namespace Thread {
|
||||
|
||||
class ThreadNetif;
|
||||
|
||||
/**
|
||||
* This class implements handling PANID Query Requests.
|
||||
*
|
||||
*/
|
||||
class EnergyScanClient
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
*/
|
||||
EnergyScanClient(ThreadNetif &aThreadNetif);
|
||||
|
||||
/**
|
||||
* This method sends an Energy Scan Query message.
|
||||
*
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aCount The number of energy measurements per channel.
|
||||
* @param[in] aPeriod The time between energy measurements (milliseconds).
|
||||
* @param[in] aScanDuration The scan duration for each energy measurement (milliseconds).
|
||||
* @param[in] aAddress A pointer to the IPv6 destination.
|
||||
* @param[in] aCallback A pointer to a function called on receiving an Energy Report message.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
* @retval kThreadError_None Successfully enqueued the Energy Scan Query message.
|
||||
* @retval kThreadError_NoBufs Insufficient buffers to generate an Energy Scan Query message.
|
||||
*
|
||||
*/
|
||||
ThreadError SendQuery(uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod, uint16_t aScanDuration,
|
||||
const Ip6::Address &aAddress, otCommissionerEnergyReportCallback aCallback, void *aContext);
|
||||
|
||||
private:
|
||||
static void HandleReport(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo);
|
||||
void HandleReport(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
static void HandleTimer(void *aContext);
|
||||
void HandleTimer(void);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
|
||||
|
||||
ThreadError SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestMessageInfo);
|
||||
|
||||
otCommissionerEnergyReportCallback mCallback;
|
||||
void *mContext;
|
||||
|
||||
Coap::Resource mEnergyScan;
|
||||
Ip6::UdpSocket mSocket;
|
||||
Timer mTimer;
|
||||
|
||||
Coap::Server &mCoapServer;
|
||||
ThreadNetif &mNetif;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace Thread
|
||||
|
||||
#endif // ENERGY_SCAN_CLIENT_HPP_
|
||||
@@ -59,6 +59,19 @@ public:
|
||||
*/
|
||||
PanIdQueryClient(ThreadNetif &aThreadNetif);
|
||||
|
||||
/**
|
||||
* This method sends a PAN ID Query message.
|
||||
*
|
||||
* @param[in] aPanId The PAN ID to query.
|
||||
* @param[in] aChannelMask The channel mask value.
|
||||
* @param[in] aAddress A pointer to the IPv6 destination.
|
||||
* @param[in] aCallback A pointer to a function called on receiving an Energy Report message.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
* @retval kThreadError_None Successfully enqueued the PAN ID Query message.
|
||||
* @retval kThreadError_NoBufs Insufficient buffers to generate a PAN ID Query message.
|
||||
*
|
||||
*/
|
||||
ThreadError SendQuery(uint16_t aPanId, uint32_t aChannelMask, const Ip6::Address &aAddress,
|
||||
otCommissionerPanIdConflictCallback aCallback, void *aContext);
|
||||
|
||||
|
||||
@@ -165,6 +165,16 @@
|
||||
#define OPENTHREAD_CONFIG_JOINER_UDP_PORT 1000
|
||||
#endif // OPENTHREAD_CONFIG_JOINER_UDP_PORT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS
|
||||
*
|
||||
* The maximum number of Energy List entries.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS
|
||||
#define OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS 64
|
||||
#endif // OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_LOG_LEVEL
|
||||
*
|
||||
|
||||
@@ -1325,6 +1325,15 @@ ThreadError otCommissionerStop(otInstance *)
|
||||
return sThreadNetif->GetCommissioner().Stop();
|
||||
}
|
||||
|
||||
ThreadError otCommissionerEnergyScan(otInstance *, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
|
||||
uint16_t aScanDuration, const otIp6Address *aAddress,
|
||||
otCommissionerEnergyReportCallback aCallback, void *aContext)
|
||||
{
|
||||
return sThreadNetif->GetCommissioner().mEnergyScan.SendQuery(aChannelMask, aCount, aPeriod, aScanDuration,
|
||||
*static_cast<const Ip6::Address *>(aAddress),
|
||||
aCallback, aContext);
|
||||
}
|
||||
|
||||
ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aChannelMask,
|
||||
const otIp6Address *aAddress,
|
||||
otCommissionerPanIdConflictCallback aCallback, void *aContext)
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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 Energy Scan Server.
|
||||
*/
|
||||
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <common/code_utils.hpp>
|
||||
#include <common/debug.hpp>
|
||||
#include <common/logging.hpp>
|
||||
#include <thread/meshcop_tlvs.hpp>
|
||||
#include <thread/energy_scan_server.hpp>
|
||||
#include <thread/thread_netif.hpp>
|
||||
#include <thread/thread_uris.hpp>
|
||||
|
||||
namespace Thread {
|
||||
|
||||
EnergyScanServer::EnergyScanServer(ThreadNetif &aThreadNetif) :
|
||||
mActive(false),
|
||||
mEnergyScan(OPENTHREAD_URI_ENERGY_SCAN, &HandleRequest, this),
|
||||
mSocket(aThreadNetif.GetIp6().mUdp),
|
||||
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &HandleTimer, this),
|
||||
mCoapServer(aThreadNetif.GetCoapServer()),
|
||||
mNetif(aThreadNetif)
|
||||
{
|
||||
mNetifCallback.Set(&HandleNetifStateChanged, this);
|
||||
mNetif.RegisterCallback(mNetifCallback);
|
||||
|
||||
mCoapServer.AddResource(mEnergyScan);
|
||||
mSocket.Open(HandleUdpReceive, this);
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleRequest(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
static_cast<EnergyScanServer *>(aContext)->HandleRequest(aHeader, aMessage, aMessageInfo);
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleRequest(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
MeshCoP::CountTlv count;
|
||||
MeshCoP::PeriodTlv period;
|
||||
MeshCoP::ScanDurationTlv scanDuration;
|
||||
union
|
||||
{
|
||||
MeshCoP::ChannelMaskEntry channelMaskEntry;
|
||||
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(uint32_t)];
|
||||
};
|
||||
uint16_t offset;
|
||||
uint16_t length;
|
||||
|
||||
VerifyOrExit(aHeader.GetCode() == Coap::Header::kCodePost, ;);
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kCount, sizeof(count), count));
|
||||
VerifyOrExit(count.IsValid(), ;);
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kPeriod, sizeof(period), period));
|
||||
VerifyOrExit(period.IsValid(), ;);
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kScanDuration, sizeof(scanDuration), scanDuration));
|
||||
VerifyOrExit(scanDuration.IsValid(), ;);
|
||||
|
||||
SuccessOrExit(MeshCoP::Tlv::GetValueOffset(aMessage, MeshCoP::Tlv::kChannelMask, offset, length));
|
||||
aMessage.Read(offset, sizeof(channelMaskBuf), channelMaskBuf);
|
||||
VerifyOrExit(channelMaskEntry.GetChannelPage() == 0 &&
|
||||
channelMaskEntry.GetMaskLength() == sizeof(uint32_t), ;);
|
||||
|
||||
mChannelMask =
|
||||
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 0]) << 0) |
|
||||
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 1]) << 8) |
|
||||
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 2]) << 16) |
|
||||
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 3]) << 24);
|
||||
|
||||
mChannelMaskCurrent = mChannelMask;
|
||||
mCount = count.GetCount();
|
||||
mPeriod = period.GetPeriod();
|
||||
mScanDuration = scanDuration.GetScanDuration();
|
||||
mScanResultsLength = 0;
|
||||
mActive = true;
|
||||
mTimer.Start(kScanDelay);
|
||||
|
||||
mCommissioner = aMessageInfo.GetPeerAddr();
|
||||
SendResponse(aHeader, aMessageInfo);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError EnergyScanServer::SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestInfo)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *message;
|
||||
Coap::Header responseHeader;
|
||||
Ip6::MessageInfo responseInfo;
|
||||
|
||||
VerifyOrExit(aRequestHeader.GetType() == Coap::Header::kTypeConfirmable, ;);
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
responseHeader.Init();
|
||||
responseHeader.SetVersion(1);
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
memcpy(&responseInfo, &aRequestInfo, sizeof(responseInfo));
|
||||
memset(&responseInfo.mSockAddr, 0, sizeof(responseInfo.mSockAddr));
|
||||
SuccessOrExit(error = mCoapServer.SendMessage(*message, responseInfo));
|
||||
|
||||
otLogInfoMeshCoP("sent energy scan query response\r\n");
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleTimer(void *aContext)
|
||||
{
|
||||
static_cast<EnergyScanServer *>(aContext)->HandleTimer();
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleTimer(void)
|
||||
{
|
||||
VerifyOrExit(mActive, ;);
|
||||
|
||||
if (mCount)
|
||||
{
|
||||
// grab the lowest channel to scan
|
||||
uint32_t channelMask = mChannelMaskCurrent & ~(mChannelMaskCurrent - 1);
|
||||
otLogInfoMeshCoP("%x\r\n", channelMask);
|
||||
mNetif.GetMac().EnergyScan(channelMask, mScanDuration, HandleScanResult, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendReport();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleScanResult(void *aContext, otEnergyScanResult *aResult)
|
||||
{
|
||||
static_cast<EnergyScanServer *>(aContext)->HandleScanResult(aResult);
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleScanResult(otEnergyScanResult *aResult)
|
||||
{
|
||||
VerifyOrExit(mActive, ;);
|
||||
|
||||
if (aResult)
|
||||
{
|
||||
mScanResults[mScanResultsLength++] = aResult->mMaxRssi;
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear the lowest channel to scan
|
||||
mChannelMaskCurrent &= mChannelMaskCurrent - 1;
|
||||
|
||||
if (mChannelMaskCurrent == 0)
|
||||
{
|
||||
mChannelMaskCurrent = mChannelMask;
|
||||
mCount--;
|
||||
}
|
||||
|
||||
if (mCount)
|
||||
{
|
||||
mTimer.Start(mPeriod);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTimer.Start(kReportDelay);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError EnergyScanServer::SendReport(void)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Coap::Header header;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct
|
||||
{
|
||||
MeshCoP::ChannelMaskTlv tlv;
|
||||
MeshCoP::ChannelMaskEntry entry;
|
||||
uint32_t mask;
|
||||
} OT_TOOL_PACKED_END channelMask;
|
||||
|
||||
MeshCoP::EnergyListTlv energyList;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Message *message;
|
||||
|
||||
header.Init();
|
||||
header.SetVersion(1);
|
||||
header.SetType(Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(0);
|
||||
header.SetToken(NULL, 0);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ENERGY_REPORT);
|
||||
header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
|
||||
header.Finalize();
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
|
||||
channelMask.tlv.Init();
|
||||
channelMask.tlv.SetLength(sizeof(channelMask) - sizeof(channelMask.tlv));
|
||||
channelMask.entry.SetChannelPage(0);
|
||||
channelMask.entry.SetMaskLength(sizeof(channelMask.mask));
|
||||
channelMask.mask = HostSwap32(mChannelMask);
|
||||
SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask)));
|
||||
|
||||
energyList.Init();
|
||||
energyList.SetLength(mScanResultsLength);
|
||||
SuccessOrExit(error = message->Append(&energyList, sizeof(energyList)));
|
||||
SuccessOrExit(error = message->Append(mScanResults, mScanResultsLength));
|
||||
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
messageInfo.GetPeerAddr() = mCommissioner;
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
|
||||
otLogInfoMeshCoP("sent scan results\r\n");
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
mActive = false;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
(void)aContext;
|
||||
(void)aMessage;
|
||||
(void)aMessageInfo;
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleNetifStateChanged(uint32_t aFlags, void *aContext)
|
||||
{
|
||||
static_cast<EnergyScanServer *>(aContext)->HandleNetifStateChanged(aFlags);
|
||||
}
|
||||
|
||||
void EnergyScanServer::HandleNetifStateChanged(uint32_t aFlags)
|
||||
{
|
||||
uint8_t length;
|
||||
|
||||
if ((aFlags & OT_THREAD_NETDATA_UPDATED) != 0 &&
|
||||
!mActive &&
|
||||
mNetif.GetNetworkDataLeader().GetCommissioningData(length) == NULL)
|
||||
{
|
||||
mActive = false;
|
||||
mTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Thread
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 responding to Energy Scan Requests.
|
||||
*/
|
||||
|
||||
#ifndef ENERGY_SCAN_SERVER_HPP_
|
||||
#define ENERGY_SCAN_SERVER_HPP_
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread-types.h>
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <net/ip6_address.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
|
||||
namespace Thread {
|
||||
|
||||
class MeshForwarder;
|
||||
class ThreadLastTransactionTimeTlv;
|
||||
class ThreadMeshLocalEidTlv;
|
||||
class ThreadNetif;
|
||||
class ThreadTargetTlv;
|
||||
|
||||
/**
|
||||
* This class implements handling Energy Scan Requests.
|
||||
*
|
||||
*/
|
||||
class EnergyScanServer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
*/
|
||||
EnergyScanServer(ThreadNetif &aThreadNetif);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kScanDelay = 1000, ///< SCAN_DELAY (milliseconds)
|
||||
kReportDelay = 500, ///< Delay before sending a report (milliseconds)
|
||||
};
|
||||
|
||||
static void HandleRequest(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo);
|
||||
void HandleRequest(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
static void HandleScanResult(void *aContext, otEnergyScanResult *aResult);
|
||||
void HandleScanResult(otEnergyScanResult *aResult);
|
||||
|
||||
static void HandleTimer(void *aContext);
|
||||
void HandleTimer(void);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
|
||||
|
||||
static void HandleNetifStateChanged(uint32_t aFlags, void *aContext);
|
||||
void HandleNetifStateChanged(uint32_t aFlags);
|
||||
|
||||
ThreadError SendReport();
|
||||
ThreadError SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestMessageInfo);
|
||||
|
||||
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_MAX_ENERGY_RESULTS];
|
||||
uint8_t mScanResultsLength;
|
||||
|
||||
Coap::Resource mEnergyScan;
|
||||
Ip6::UdpSocket mSocket;
|
||||
Timer mTimer;
|
||||
|
||||
Ip6::NetifCallback mNetifCallback;
|
||||
|
||||
Coap::Server &mCoapServer;
|
||||
ThreadNetif &mNetif;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace Thread
|
||||
|
||||
#endif // ENERGY_SCAN_SERVER_HPP_
|
||||
@@ -83,6 +83,10 @@ public:
|
||||
kPendingTimestamp = OT_MESHCOP_TLV_PENDINGTIMESTAMP, ///< Pending Timestamp TLV
|
||||
kDelayTimer = OT_MESHCOP_TLV_DELAYTIMER, ///< Delay Timer TLV
|
||||
kChannelMask = OT_MESHCOP_TLV_CHANNELMASK, ///< Channel Mask TLV
|
||||
kCount = OT_MESHCOP_TLV_COUNT, ///< Count TLV
|
||||
kPeriod = OT_MESHCOP_TLV_PERIOD, ///< Period TLV
|
||||
kScanDuration = OT_MESHCOP_TLV_SCAN_DURATION, ///< Scan Duration TLV
|
||||
kEnergyList = OT_MESHCOP_TLV_ENERGY_LIST, ///< Energy List TLV
|
||||
kDiscoveryRequest = OT_MESHCOP_TLV_DISCOVERYREQUEST, ///< Discovery Request TLV
|
||||
kDiscoveryResponse = OT_MESHCOP_TLV_DISCOVERYRESPONSE, ///< Discovery Response TLV
|
||||
};
|
||||
@@ -1289,6 +1293,159 @@ public:
|
||||
bool IsValid(void) const { return true; }
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Count TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class CountTlv: public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void) { SetType(kCount); SetLength(sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the Count value.
|
||||
*
|
||||
* @returns The Count value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetCount(void) const { return mCount; }
|
||||
|
||||
/**
|
||||
* This method sets the Count value.
|
||||
*
|
||||
* @param[in] aCount The Count value.
|
||||
*
|
||||
*/
|
||||
void SetCount(uint8_t aCount) { mCount = aCount; }
|
||||
|
||||
private:
|
||||
uint8_t mCount;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Period TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class PeriodTlv: public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void) { SetType(kPeriod); SetLength(sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the Period value.
|
||||
*
|
||||
* @returns The Period value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetPeriod(void) const { return HostSwap16(mPeriod); }
|
||||
|
||||
/**
|
||||
* This method sets the Period value.
|
||||
*
|
||||
* @param[in] aPeriod The Period value.
|
||||
*
|
||||
*/
|
||||
void SetPeriod(uint16_t aPeriod) { mPeriod = HostSwap16(aPeriod); }
|
||||
|
||||
private:
|
||||
uint16_t mPeriod;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Scan Duration TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ScanDurationTlv: public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void) { SetType(kScanDuration); SetLength(sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the Scan Duration value.
|
||||
*
|
||||
* @returns The Scan Duration value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetScanDuration(void) const { return HostSwap16(mScanDuration); }
|
||||
|
||||
/**
|
||||
* This method sets the Scan Duration value.
|
||||
*
|
||||
* @param[in] aScanDuration The Scan Duration value.
|
||||
*
|
||||
*/
|
||||
void SetScanDuration(uint16_t aScanDuration) { mScanDuration = HostSwap16(aScanDuration); }
|
||||
|
||||
private:
|
||||
uint16_t mScanDuration;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Energy List TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class EnergyListTlv: public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void) { SetType(kEnergyList); SetLength(sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return true; }
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Discovery Request TLV generation and parsing.
|
||||
*
|
||||
|
||||
@@ -78,7 +78,8 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
|
||||
#endif // OPENTHREAD_ENABLE_JOINER
|
||||
mJoinerRouter(*this),
|
||||
mLeader(*this),
|
||||
mPanIdQuery(*this)
|
||||
mPanIdQuery(*this),
|
||||
mEnergyScan(*this)
|
||||
{
|
||||
mKeyManager.SetMasterKey(kThreadMasterKey, sizeof(kThreadMasterKey));
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <net/ip6_filter.hpp>
|
||||
#include <net/netif.hpp>
|
||||
#include <thread/address_resolver.hpp>
|
||||
#include <thread/energy_scan_server.hpp>
|
||||
#include <thread/key_manager.hpp>
|
||||
#include <thread/meshcop_dataset_manager.hpp>
|
||||
#include <thread/mesh_forwarder.hpp>
|
||||
@@ -278,6 +279,7 @@ private:
|
||||
MeshCoP::JoinerRouter mJoinerRouter;
|
||||
MeshCoP::Leader mLeader;
|
||||
PanIdQueryServer mPanIdQuery;
|
||||
EnergyScanServer mEnergyScan;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,13 +90,29 @@ namespace Thread {
|
||||
*/
|
||||
#define OPENTHREAD_URI_ACTIVE_SET "c/as"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_ENERGY_SCAN
|
||||
*
|
||||
* The URI Path for Energy Scan
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_URI_ENERGY_SCAN "c/es"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_ENERGY_REPORT
|
||||
*
|
||||
* The URI Path for Energy Report
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_URI_ENERGY_REPORT "c/er"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_PENDING_GET
|
||||
*
|
||||
* The URI Path for MGMT_PENDING_GET
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_URI_PENDING_GET "c/pg"
|
||||
#define OPENTHREAD_URI_PENDING_GET "c/pg"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_PENDING_SET
|
||||
@@ -104,7 +120,7 @@ namespace Thread {
|
||||
* The URI Path for MGMT_PENDING_SET
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_URI_PENDING_SET "c/ps"
|
||||
#define OPENTHREAD_URI_PENDING_SET "c/ps"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_SERVER_DATA
|
||||
@@ -160,7 +176,7 @@ namespace Thread {
|
||||
* The URI Path for Leader Keep Alive
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la"
|
||||
#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_URI_PANID_CONFLICT
|
||||
|
||||
@@ -102,6 +102,7 @@ EXTRA_DIST = \
|
||||
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
|
||||
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_9_2_13_EnergyScan.py \
|
||||
thread-cert/Cert_9_2_14_PanIdQuery.py \
|
||||
thread-cert/node.py \
|
||||
$(NULL)
|
||||
@@ -217,6 +218,7 @@ check_SCRIPTS += \
|
||||
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
|
||||
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_9_2_13_EnergyScan.py \
|
||||
thread-cert/Cert_9_2_14_PanIdQuery.py \
|
||||
$(NULL)
|
||||
|
||||
@@ -249,6 +251,7 @@ XFAIL_NCP_TESTS = \
|
||||
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
|
||||
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
|
||||
thread-cert/Cert_9_2_13_EnergyScan.py \
|
||||
thread-cert/Cert_9_2_14_PanIdQuery.py \
|
||||
$(NULL)
|
||||
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import node
|
||||
|
||||
COMMISSIONER = 1
|
||||
LEADER = 2
|
||||
ROUTER1 = 3
|
||||
ED1 = 4
|
||||
|
||||
class Cert_9_2_13_EnergyScan(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.nodes = {}
|
||||
for i in range(1,5):
|
||||
self.nodes[i] = node.Node(i)
|
||||
|
||||
self.nodes[COMMISSIONER].set_panid(0xface)
|
||||
self.nodes[COMMISSIONER].set_mode('rsdn')
|
||||
self.nodes[COMMISSIONER].add_whitelist(self.nodes[LEADER].get_addr64())
|
||||
self.nodes[COMMISSIONER].enable_whitelist()
|
||||
|
||||
self.nodes[LEADER].set_panid(0xface)
|
||||
self.nodes[LEADER].set_mode('rsdn')
|
||||
self.nodes[LEADER].add_whitelist(self.nodes[COMMISSIONER].get_addr64())
|
||||
self.nodes[LEADER].add_whitelist(self.nodes[ROUTER1].get_addr64())
|
||||
self.nodes[LEADER].enable_whitelist()
|
||||
|
||||
self.nodes[ROUTER1].set_panid(0xface)
|
||||
self.nodes[ROUTER1].set_mode('rsdn')
|
||||
self.nodes[ROUTER1].add_whitelist(self.nodes[LEADER].get_addr64())
|
||||
self.nodes[ROUTER1].add_whitelist(self.nodes[ED1].get_addr64())
|
||||
self.nodes[ROUTER1].enable_whitelist()
|
||||
|
||||
self.nodes[ED1].set_panid(0xface)
|
||||
self.nodes[ED1].set_mode('rs')
|
||||
self.nodes[ED1].add_whitelist(self.nodes[ROUTER1].get_addr64())
|
||||
self.nodes[ED1].enable_whitelist()
|
||||
|
||||
def tearDown(self):
|
||||
for node in list(self.nodes.values()):
|
||||
node.stop()
|
||||
del self.nodes
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.nodes[LEADER].set_state('leader')
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[COMMISSIONER].start()
|
||||
time.sleep(3)
|
||||
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
time.sleep(3)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
self.nodes[ED1].start()
|
||||
time.sleep(3)
|
||||
self.assertEqual(self.nodes[ED1].get_state(), 'child')
|
||||
|
||||
ipaddrs = self.nodes[ROUTER1].get_addrs()
|
||||
for ipaddr in ipaddrs:
|
||||
if ipaddr[0:4] != 'fe80':
|
||||
break
|
||||
|
||||
self.nodes[COMMISSIONER].ping(ipaddr)
|
||||
self.nodes[COMMISSIONER].energy_scan(0x50000, 0x02, 0x20, 0x3e8, ipaddr)
|
||||
|
||||
ipaddrs = self.nodes[ED1].get_addrs()
|
||||
for ipaddr in ipaddrs:
|
||||
if ipaddr[0:4] != 'fe80':
|
||||
break
|
||||
|
||||
self.nodes[COMMISSIONER].ping(ipaddr)
|
||||
self.nodes[COMMISSIONER].energy_scan(0x50000, 0x02, 0x20, 0x3e8, ipaddr)
|
||||
|
||||
self.nodes[COMMISSIONER].energy_scan(0x50000, 0x02, 0x20, 0x3e8, 'ff33:0040:fdde:ad00:beef:0:0:1')
|
||||
|
||||
self.nodes[COMMISSIONER].ping(ipaddr)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -92,9 +92,9 @@ class Cert_9_2_14_PanIdQuery(unittest.TestCase):
|
||||
if ipaddr[0:4] != 'fe80':
|
||||
break
|
||||
|
||||
self.nodes[COMMISSIONER].panid_query('0xdead', '0xffffffff', ipaddr)
|
||||
self.nodes[COMMISSIONER].panid_query(0xdead, 0xffffffff, ipaddr)
|
||||
|
||||
self.nodes[COMMISSIONER].panid_query('0xdead', '0xffffffff', 'ff33:0040:fdde:ad00:beef:0:0:1')
|
||||
self.nodes[COMMISSIONER].panid_query(0xdead, 0xffffffff, 'ff33:0040:fdde:ad00:beef:0:0:1')
|
||||
|
||||
self.nodes[COMMISSIONER].ping(ipaddr)
|
||||
|
||||
|
||||
@@ -322,8 +322,13 @@ class Node:
|
||||
self.send_command('netdataregister')
|
||||
self.pexpect.expect('Done')
|
||||
|
||||
def energy_scan(self, mask, count, period, scan_duration, ipaddr):
|
||||
cmd = 'commissioner energy ' + str(mask) + ' ' + str(count) + ' ' + str(period) + ' ' + str(scan_duration) + ' ' + ipaddr
|
||||
self.send_command(cmd)
|
||||
self.pexpect.expect('Energy:', timeout=8)
|
||||
|
||||
def panid_query(self, panid, mask, ipaddr):
|
||||
cmd = 'commissioner panid ' + panid + ' ' + mask + ' ' + ipaddr
|
||||
cmd = 'commissioner panid ' + str(panid) + ' ' + str(mask) + ' ' + ipaddr
|
||||
self.send_command(cmd)
|
||||
self.pexpect.expect('Conflict:', timeout=8)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user