Energy scan. (#606)

This commit is contained in:
Jonathan Hui
2016-09-16 16:04:01 -07:00
committed by GitHub
parent d88dda56fc
commit 03fea69c1b
22 changed files with 1226 additions and 10 deletions
+55 -1
View File
@@ -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);
+4
View File
@@ -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
View File
@@ -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);
+3
View File
@@ -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[];
+4
View File
@@ -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 \
+1
View File
@@ -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),
+2
View File
@@ -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:
+239
View File
@@ -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
+109
View File
@@ -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_
+13
View File
@@ -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);
+10
View File
@@ -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
*
+9
View File
@@ -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)
+301
View File
@@ -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
+117
View File
@@ -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_
+157
View File
@@ -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.
*
+2 -1
View File
@@ -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));
}
+2
View File
@@ -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;
};
/**
+19 -3
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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)
+6 -1
View File
@@ -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)