mirror of
https://github.com/espressif/openthread.git
synced 2026-07-29 15:17:47 +00:00
[cli] make meshdiag cli as a separate module (#11105)
This commit is contained in:
@@ -55,6 +55,8 @@ openthread_cli_sources = [
|
||||
"cli_mac_filter.hpp",
|
||||
"cli_mdns.cpp",
|
||||
"cli_mdns.hpp",
|
||||
"cli_mesh_diag.cpp",
|
||||
"cli_mesh_diag.hpp",
|
||||
"cli_network_data.cpp",
|
||||
"cli_network_data.hpp",
|
||||
"cli_ping.cpp",
|
||||
|
||||
@@ -45,6 +45,7 @@ set(COMMON_SOURCES
|
||||
cli_link_metrics.cpp
|
||||
cli_mac_filter.cpp
|
||||
cli_mdns.cpp
|
||||
cli_mesh_diag.cpp
|
||||
cli_network_data.cpp
|
||||
cli_ping.cpp
|
||||
cli_srp_client.cpp
|
||||
|
||||
+4
-442
@@ -133,6 +133,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi
|
||||
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
|
||||
, mPing(aInstance, *this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
, mMeshDiag(aInstance, *this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
|
||||
, mLocateInProgress(false)
|
||||
#endif
|
||||
@@ -5022,448 +5025,7 @@ exit:
|
||||
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE
|
||||
|
||||
template <> otError Interpreter::Process<Cmd("meshdiag")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
/**
|
||||
* @cli meshdiag topology
|
||||
* @code
|
||||
* meshdiag topology
|
||||
* id:02 rloc16:0x0800 ext-addr:8aa57d2c603fe16c ver:4 - me - leader
|
||||
* 3-links:{ 46 }
|
||||
* id:46 rloc16:0xb800 ext-addr:fe109d277e0175cc ver:4
|
||||
* 3-links:{ 02 51 57 }
|
||||
* id:33 rloc16:0x8400 ext-addr:d2e511a146b9e54d ver:4
|
||||
* 3-links:{ 51 57 }
|
||||
* id:51 rloc16:0xcc00 ext-addr:9aab43ababf05352 ver:4
|
||||
* 3-links:{ 33 57 }
|
||||
* 2-links:{ 46 }
|
||||
* id:57 rloc16:0xe400 ext-addr:dae9c4c0e9da55ff ver:4
|
||||
* 3-links:{ 46 51 }
|
||||
* 1-links:{ 33 }
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Discover network topology (list of routers and their connections).
|
||||
* Parameters are optional and indicate additional items to discover. Can be added in any order.
|
||||
* * `ip6-addrs` to discover the list of IPv6 addresses of every router.
|
||||
* * `children` to discover the child table of every router.
|
||||
* @par
|
||||
* Information per router:
|
||||
* * Router ID
|
||||
* * RLOC16
|
||||
* * Extended MAC address
|
||||
* * Thread Version (if known)
|
||||
* * Whether the router is this device is itself (`me`)
|
||||
* * Whether the router is the parent of this device when device is a child (`parent`)
|
||||
* * Whether the router is `leader`
|
||||
* * Whether the router acts as a border router providing external connectivity (`br`)
|
||||
* * List of routers to which this router has a link:
|
||||
* * `3-links`: Router IDs to which this router has a incoming link with link quality 3
|
||||
* * `2-links`: Router IDs to which this router has a incoming link with link quality 2
|
||||
* * `1-links`: Router IDs to which this router has a incoming link with link quality 1
|
||||
* * If a list if empty, it is omitted in the out.
|
||||
* * If `ip6-addrs`, list of IPv6 addresses of the router
|
||||
* * If `children`, list of all children of the router. Information per child:
|
||||
* * RLOC16
|
||||
* * Incoming Link Quality from perspective of parent to child (zero indicates unknown)
|
||||
* * Child Device mode (`r` rx-on-when-idle, `d` Full Thread Device, `n` Full Network Data, `-` no flags set)
|
||||
* * Whether the child is this device itself (`me`)
|
||||
* * Whether the child acts as a border router providing external connectivity (`br`)
|
||||
* @cparam meshdiag topology [@ca{ip6-addrs}] [@ca{children}]
|
||||
* @sa otMeshDiagDiscoverTopology
|
||||
*/
|
||||
if (aArgs[0] == "topology")
|
||||
{
|
||||
otMeshDiagDiscoverConfig config;
|
||||
|
||||
config.mDiscoverIp6Addresses = false;
|
||||
config.mDiscoverChildTable = false;
|
||||
|
||||
aArgs++;
|
||||
|
||||
for (; !aArgs->IsEmpty(); aArgs++)
|
||||
{
|
||||
if (*aArgs == "ip6-addrs")
|
||||
{
|
||||
config.mDiscoverIp6Addresses = true;
|
||||
}
|
||||
else if (*aArgs == "children")
|
||||
{
|
||||
config.mDiscoverChildTable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otMeshDiagDiscoverTopology(GetInstancePtr(), &config, HandleMeshDiagDiscoverDone, this));
|
||||
error = OT_ERROR_PENDING;
|
||||
}
|
||||
/**
|
||||
* @cli meshdiag childtable
|
||||
* @code
|
||||
* meshdiag childtable 0x6400
|
||||
* rloc16:0x6402 ext-addr:8e6f4d323bbed1fe ver:4
|
||||
* timeout:120 age:36 supvn:129 q-msg:0
|
||||
* rx-on:yes type:ftd full-net:yes
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:11.51% msg:0.76%
|
||||
* conn-time:00:11:07
|
||||
* csl - sync:no period:0 timeout:0 channel:0
|
||||
* rloc16:0x6403 ext-addr:ee24e64ecf8c079a ver:4
|
||||
* timeout:120 age:19 supvn:129 q-msg:0
|
||||
* rx-on:no type:mtd full-net:no
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:0.73% msg:0.00%
|
||||
* conn-time:01:08:53
|
||||
* csl - sync:no period:0 timeout:0 channel:0
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Start a query for child table of a router with a given RLOC16.
|
||||
* Output lists all child entries. Information per child:
|
||||
* - RLOC16
|
||||
* - Extended MAC address
|
||||
* - Thread Version
|
||||
* - Timeout (in seconds)
|
||||
* - Age (seconds since last heard)
|
||||
* - Supervision interval (in seconds)
|
||||
* - Number of queued messages (in case child is sleepy)
|
||||
* - Device Mode
|
||||
* - RSS (average and last)
|
||||
* - Error rates: frame tx (at MAC layer), IPv6 message tx (above MAC)
|
||||
* - Connection time (seconds since link establishment `{dd}d.{hh}:{mm}:{ss}` format)
|
||||
* - CSL info:
|
||||
* - If synchronized
|
||||
* - Period (in unit of 10-symbols-time)
|
||||
* - Timeout (in seconds)
|
||||
*
|
||||
* @cparam meshdiag childtable @ca{router-rloc16}
|
||||
* @sa otMeshDiagQueryChildTable
|
||||
*/
|
||||
else if (aArgs[0] == "childtable")
|
||||
{
|
||||
uint16_t routerRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[1].ParseAsUint16(routerRloc16));
|
||||
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMeshDiagQueryChildTable(GetInstancePtr(), routerRloc16,
|
||||
HandleMeshDiagQueryChildTableResult, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
}
|
||||
/**
|
||||
* @cli meshdiag childip6
|
||||
* @code
|
||||
* meshdiag childip6 0xdc00
|
||||
* child-rloc16: 0xdc02
|
||||
* fdde:ad00:beef:0:ded8:cd58:b73:2c21
|
||||
* fd00:2:0:0:c24a:456:3b6b:c597
|
||||
* fd00:1:0:0:120b:95fe:3ecc:d238
|
||||
* child-rloc16: 0xdc03
|
||||
* fdde:ad00:beef:0:3aa6:b8bf:e7d6:eefe
|
||||
* fd00:2:0:0:8ff8:a188:7436:6720
|
||||
* fd00:1:0:0:1fcf:5495:790a:370f
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Send a query to a parent to retrieve the IPv6 addresses of all its MTD children.
|
||||
* @cparam meshdiag childip6 @ca{parent-rloc16}
|
||||
* @sa otMeshDiagQueryChildrenIp6Addrs
|
||||
*/
|
||||
else if (aArgs[0] == "childip6")
|
||||
{
|
||||
uint16_t parentRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[1].ParseAsUint16(parentRloc16));
|
||||
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMeshDiagQueryChildrenIp6Addrs(GetInstancePtr(), parentRloc16,
|
||||
HandleMeshDiagQueryChildIp6Addrs, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
}
|
||||
/**
|
||||
* @cli meshdiag routerneighbortable
|
||||
* @code
|
||||
* meshdiag routerneighbortable 0x7400
|
||||
* rloc16:0x9c00 ext-addr:764788cf6e57a4d2 ver:4
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:1.38% msg:0.00%
|
||||
* conn-time:01:54:02
|
||||
* rloc16:0x7c00 ext-addr:4ed24fceec9bf6d3 ver:4
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:0.72% msg:0.00%
|
||||
* conn-time:00:11:27
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Start a query for router neighbor table of a router with a given RLOC16.
|
||||
* Output lists all router neighbor entries. Information per entry:
|
||||
* - RLOC16
|
||||
* - Extended MAC address
|
||||
* - Thread Version
|
||||
* - RSS (average and last) and link margin
|
||||
* - Error rates, frame tx (at MAC layer), IPv6 message tx (above MAC)
|
||||
* - Connection time (seconds since link establishment `{dd}d.{hh}:{mm}:{ss}` format)
|
||||
* @cparam meshdiag routerneighbortable @ca{router-rloc16}
|
||||
* @sa otMeshDiagQueryRouterNeighborTable
|
||||
*/
|
||||
else if (aArgs[0] == "routerneighbortable")
|
||||
{
|
||||
uint16_t routerRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[1].ParseAsUint16(routerRloc16));
|
||||
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMeshDiagQueryRouterNeighborTable(GetInstancePtr(), routerRloc16,
|
||||
HandleMeshDiagQueryRouterNeighborTableResult, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext)
|
||||
{
|
||||
reinterpret_cast<Interpreter *>(aContext)->HandleMeshDiagDiscoverDone(aError, aRouterInfo);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo)
|
||||
{
|
||||
VerifyOrExit(aRouterInfo != nullptr);
|
||||
|
||||
OutputFormat("id:%02u rloc16:0x%04x ext-addr:", aRouterInfo->mRouterId, aRouterInfo->mRloc16);
|
||||
OutputExtAddress(aRouterInfo->mExtAddress);
|
||||
|
||||
if (aRouterInfo->mVersion != OT_MESH_DIAG_VERSION_UNKNOWN)
|
||||
{
|
||||
OutputFormat(" ver:%u", aRouterInfo->mVersion);
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsThisDevice)
|
||||
{
|
||||
OutputFormat(" - me");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsThisDeviceParent)
|
||||
{
|
||||
OutputFormat(" - parent");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsLeader)
|
||||
{
|
||||
OutputFormat(" - leader");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsBorderRouter)
|
||||
{
|
||||
OutputFormat(" - br");
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
|
||||
for (uint8_t linkQuality = 3; linkQuality > 0; linkQuality--)
|
||||
{
|
||||
bool hasLinkQuality = false;
|
||||
|
||||
for (uint8_t entryQuality : aRouterInfo->mLinkQualities)
|
||||
{
|
||||
if (entryQuality == linkQuality)
|
||||
{
|
||||
hasLinkQuality = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLinkQuality)
|
||||
{
|
||||
OutputFormat(kIndentSize, "%u-links:{ ", linkQuality);
|
||||
|
||||
for (uint8_t id = 0; id < static_cast<uint8_t>(OT_ARRAY_LENGTH(aRouterInfo->mLinkQualities)); id++)
|
||||
{
|
||||
if (aRouterInfo->mLinkQualities[id] == linkQuality)
|
||||
{
|
||||
OutputFormat("%02u ", id);
|
||||
}
|
||||
}
|
||||
|
||||
OutputLine("}");
|
||||
}
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIp6AddrIterator != nullptr)
|
||||
{
|
||||
otIp6Address ip6Address;
|
||||
|
||||
OutputLine(kIndentSize, "ip6-addrs:");
|
||||
|
||||
while (otMeshDiagGetNextIp6Address(aRouterInfo->mIp6AddrIterator, &ip6Address) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputSpaces(kIndentSize * 2);
|
||||
OutputIp6AddressLine(ip6Address);
|
||||
}
|
||||
}
|
||||
|
||||
if (aRouterInfo->mChildIterator != nullptr)
|
||||
{
|
||||
otMeshDiagChildInfo childInfo;
|
||||
char linkModeString[kLinkModeStringSize];
|
||||
bool isFirst = true;
|
||||
|
||||
while (otMeshDiagGetNextChildInfo(aRouterInfo->mChildIterator, &childInfo) == OT_ERROR_NONE)
|
||||
{
|
||||
if (isFirst)
|
||||
{
|
||||
OutputLine(kIndentSize, "children:");
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
OutputFormat(kIndentSize * 2, "rloc16:0x%04x lq:%u, mode:%s", childInfo.mRloc16, childInfo.mLinkQuality,
|
||||
LinkModeToString(childInfo.mMode, linkModeString));
|
||||
|
||||
if (childInfo.mIsThisDevice)
|
||||
{
|
||||
OutputFormat(" - me");
|
||||
}
|
||||
|
||||
if (childInfo.mIsBorderRouter)
|
||||
{
|
||||
OutputFormat(" - br");
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
}
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
OutputLine(kIndentSize, "children: none");
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryChildTableResult(otError aError,
|
||||
const otMeshDiagChildEntry *aChildEntry,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<Interpreter *>(aContext)->HandleMeshDiagQueryChildTableResult(aError, aChildEntry);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry)
|
||||
{
|
||||
PercentageStringBuffer stringBuffer;
|
||||
char string[OT_DURATION_STRING_SIZE];
|
||||
|
||||
VerifyOrExit(aChildEntry != nullptr);
|
||||
|
||||
OutputFormat("rloc16:0x%04x ext-addr:", aChildEntry->mRloc16);
|
||||
OutputExtAddress(aChildEntry->mExtAddress);
|
||||
OutputLine(" ver:%u", aChildEntry->mVersion);
|
||||
|
||||
OutputLine(kIndentSize, "timeout:%lu age:%lu supvn:%u q-msg:%u", ToUlong(aChildEntry->mTimeout),
|
||||
ToUlong(aChildEntry->mAge), aChildEntry->mSupervisionInterval, aChildEntry->mQueuedMessageCount);
|
||||
|
||||
OutputLine(kIndentSize, "rx-on:%s type:%s full-net:%s", aChildEntry->mRxOnWhenIdle ? "yes" : "no",
|
||||
aChildEntry->mDeviceTypeFtd ? "ftd" : "mtd", aChildEntry->mFullNetData ? "yes" : "no");
|
||||
|
||||
OutputLine(kIndentSize, "rss - ave:%d last:%d margin:%d", aChildEntry->mAverageRssi, aChildEntry->mLastRssi,
|
||||
aChildEntry->mLinkMargin);
|
||||
|
||||
if (aChildEntry->mSupportsErrRate)
|
||||
{
|
||||
OutputFormat(kIndentSize, "err-rate - frame:%s%% ",
|
||||
PercentageToString(aChildEntry->mFrameErrorRate, stringBuffer));
|
||||
OutputLine("msg:%s%% ", PercentageToString(aChildEntry->mMessageErrorRate, stringBuffer));
|
||||
}
|
||||
|
||||
otConvertDurationInSecondsToString(aChildEntry->mConnectionTime, string, sizeof(string));
|
||||
OutputLine(kIndentSize, "conn-time:%s", string);
|
||||
|
||||
OutputLine(kIndentSize, "csl - sync:%s period:%u timeout:%lu channel:%u",
|
||||
aChildEntry->mCslSynchronized ? "yes" : "no", aChildEntry->mCslPeriod, ToUlong(aChildEntry->mCslTimeout),
|
||||
aChildEntry->mCslChannel);
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<Interpreter *>(aContext)->HandleMeshDiagQueryRouterNeighborTableResult(aError, aNeighborEntry);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry)
|
||||
{
|
||||
PercentageStringBuffer stringBuffer;
|
||||
char string[OT_DURATION_STRING_SIZE];
|
||||
|
||||
VerifyOrExit(aNeighborEntry != nullptr);
|
||||
|
||||
OutputFormat("rloc16:0x%04x ext-addr:", aNeighborEntry->mRloc16);
|
||||
OutputExtAddress(aNeighborEntry->mExtAddress);
|
||||
OutputLine(" ver:%u", aNeighborEntry->mVersion);
|
||||
|
||||
OutputLine(kIndentSize, "rss - ave:%d last:%d margin:%d", aNeighborEntry->mAverageRssi, aNeighborEntry->mLastRssi,
|
||||
aNeighborEntry->mLinkMargin);
|
||||
|
||||
if (aNeighborEntry->mSupportsErrRate)
|
||||
{
|
||||
OutputFormat(kIndentSize, "err-rate - frame:%s%% ",
|
||||
PercentageToString(aNeighborEntry->mFrameErrorRate, stringBuffer));
|
||||
OutputLine("msg:%s%% ", PercentageToString(aNeighborEntry->mMessageErrorRate, stringBuffer));
|
||||
}
|
||||
|
||||
otConvertDurationInSecondsToString(aNeighborEntry->mConnectionTime, string, sizeof(string));
|
||||
OutputLine(kIndentSize, "conn-time:%s", string);
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<Interpreter *>(aContext)->HandleMeshDiagQueryChildIp6Addrs(aError, aChildRloc16, aIp6AddrIterator);
|
||||
}
|
||||
|
||||
void Interpreter::HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator)
|
||||
{
|
||||
otIp6Address ip6Address;
|
||||
|
||||
VerifyOrExit(aError == OT_ERROR_NONE || aError == OT_ERROR_PENDING);
|
||||
VerifyOrExit(aIp6AddrIterator != nullptr);
|
||||
|
||||
OutputLine("child-rloc16: 0x%04x", aChildRloc16);
|
||||
|
||||
while (otMeshDiagGetNextIp6Address(aIp6AddrIterator, &ip6Address) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputSpaces(kIndentSize);
|
||||
OutputIp6AddressLine(ip6Address);
|
||||
}
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
template <> otError Interpreter::Process<Cmd("meshdiag")>(Arg aArgs[]) { return mMeshDiag.Process(aArgs); }
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE
|
||||
|
||||
|
||||
+5
-22
@@ -48,7 +48,6 @@
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/link.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <openthread/mesh_diag.h>
|
||||
#include <openthread/netdata.h>
|
||||
#include <openthread/ping_sender.h>
|
||||
#include <openthread/sntp.h>
|
||||
@@ -70,6 +69,7 @@
|
||||
#include "cli/cli_link_metrics.hpp"
|
||||
#include "cli/cli_mac_filter.hpp"
|
||||
#include "cli/cli_mdns.hpp"
|
||||
#include "cli/cli_mesh_diag.hpp"
|
||||
#include "cli/cli_network_data.hpp"
|
||||
#include "cli/cli_ping.hpp"
|
||||
#include "cli/cli_srp_client.hpp"
|
||||
@@ -113,6 +113,7 @@ class Interpreter : public OutputImplementer, public Utils
|
||||
friend class Joiner;
|
||||
friend class LinkMetrics;
|
||||
friend class Mdns;
|
||||
friend class MeshDiag;
|
||||
friend class NetworkData;
|
||||
friend class PingSender;
|
||||
friend class SrpClient;
|
||||
@@ -231,27 +232,6 @@ private:
|
||||
uint16_t aRloc16);
|
||||
void HandleLocateResult(otError aError, const otIp6Address *aMeshLocalAddress, uint16_t aRloc16);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
static void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext);
|
||||
void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo);
|
||||
static void HandleMeshDiagQueryChildTableResult(otError aError,
|
||||
const otMeshDiagChildEntry *aChildEntry,
|
||||
void *aContext);
|
||||
void HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry);
|
||||
static void HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator,
|
||||
void *aContext);
|
||||
void HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator);
|
||||
static void HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry,
|
||||
void *aContext);
|
||||
void HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry);
|
||||
|
||||
#endif
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
|
||||
static void HandleMlrRegResult(void *aContext,
|
||||
otError aError,
|
||||
@@ -428,6 +408,9 @@ private:
|
||||
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
|
||||
PingSender mPing;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
MeshDiag mMeshDiag;
|
||||
#endif
|
||||
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
|
||||
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 CLI interpreter for Mesh Diagnostics function.
|
||||
*/
|
||||
|
||||
#include "cli_mesh_diag.hpp"
|
||||
|
||||
#include <openthread/mesh_diag.h>
|
||||
|
||||
#include "cli/cli.hpp"
|
||||
#include "cli/cli_utils.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
MeshDiag::MeshDiag(otInstance *aInstance, OutputImplementer &aOutputImplementer)
|
||||
: Utils(aInstance, aOutputImplementer)
|
||||
{
|
||||
}
|
||||
|
||||
template <> otError MeshDiag::Process<Cmd("topology")>(Arg aArgs[])
|
||||
{
|
||||
/**
|
||||
* @cli meshdiag topology
|
||||
* @code
|
||||
* meshdiag topology
|
||||
* id:02 rloc16:0x0800 ext-addr:8aa57d2c603fe16c ver:4 - me - leader
|
||||
* 3-links:{ 46 }
|
||||
* id:46 rloc16:0xb800 ext-addr:fe109d277e0175cc ver:4
|
||||
* 3-links:{ 02 51 57 }
|
||||
* id:33 rloc16:0x8400 ext-addr:d2e511a146b9e54d ver:4
|
||||
* 3-links:{ 51 57 }
|
||||
* id:51 rloc16:0xcc00 ext-addr:9aab43ababf05352 ver:4
|
||||
* 3-links:{ 33 57 }
|
||||
* 2-links:{ 46 }
|
||||
* id:57 rloc16:0xe400 ext-addr:dae9c4c0e9da55ff ver:4
|
||||
* 3-links:{ 46 51 }
|
||||
* 1-links:{ 33 }
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Discover network topology (list of routers and their connections).
|
||||
* Parameters are optional and indicate additional items to discover. Can be added in any order.
|
||||
* * `ip6-addrs` to discover the list of IPv6 addresses of every router.
|
||||
* * `children` to discover the child table of every router.
|
||||
* @par
|
||||
* Information per router:
|
||||
* * Router ID
|
||||
* * RLOC16
|
||||
* * Extended MAC address
|
||||
* * Thread Version (if known)
|
||||
* * Whether the router is this device is itself (`me`)
|
||||
* * Whether the router is the parent of this device when device is a child (`parent`)
|
||||
* * Whether the router is `leader`
|
||||
* * Whether the router acts as a border router providing external connectivity (`br`)
|
||||
* * List of routers to which this router has a link:
|
||||
* * `3-links`: Router IDs to which this router has a incoming link with link quality 3
|
||||
* * `2-links`: Router IDs to which this router has a incoming link with link quality 2
|
||||
* * `1-links`: Router IDs to which this router has a incoming link with link quality 1
|
||||
* * If a list if empty, it is omitted in the out.
|
||||
* * If `ip6-addrs`, list of IPv6 addresses of the router
|
||||
* * If `children`, list of all children of the router. Information per child:
|
||||
* * RLOC16
|
||||
* * Incoming Link Quality from perspective of parent to child (zero indicates unknown)
|
||||
* * Child Device mode (`r` rx-on-when-idle, `d` Full Thread Device, `n` Full Network Data, `-` no flags set)
|
||||
* * Whether the child is this device itself (`me`)
|
||||
* * Whether the child acts as a border router providing external connectivity (`br`)
|
||||
* @cparam meshdiag topology [@ca{ip6-addrs}] [@ca{children}]
|
||||
* @sa otMeshDiagDiscoverTopology
|
||||
*/
|
||||
otError error = OT_ERROR_NONE;
|
||||
otMeshDiagDiscoverConfig config;
|
||||
|
||||
config.mDiscoverIp6Addresses = false;
|
||||
config.mDiscoverChildTable = false;
|
||||
|
||||
for (; !aArgs->IsEmpty(); aArgs++)
|
||||
{
|
||||
if (*aArgs == "ip6-addrs")
|
||||
{
|
||||
config.mDiscoverIp6Addresses = true;
|
||||
}
|
||||
else if (*aArgs == "children")
|
||||
{
|
||||
config.mDiscoverChildTable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otMeshDiagDiscoverTopology(GetInstancePtr(), &config, HandleMeshDiagDiscoverDone, this));
|
||||
error = OT_ERROR_PENDING;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError MeshDiag::Process<Cmd("childtable")>(Arg aArgs[])
|
||||
{
|
||||
/**
|
||||
* @cli meshdiag childtable
|
||||
* @code
|
||||
* meshdiag childtable 0x6400
|
||||
* rloc16:0x6402 ext-addr:8e6f4d323bbed1fe ver:4
|
||||
* timeout:120 age:36 supvn:129 q-msg:0
|
||||
* rx-on:yes type:ftd full-net:yes
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:11.51% msg:0.76%
|
||||
* conn-time:00:11:07
|
||||
* csl - sync:no period:0 timeout:0 channel:0
|
||||
* rloc16:0x6403 ext-addr:ee24e64ecf8c079a ver:4
|
||||
* timeout:120 age:19 supvn:129 q-msg:0
|
||||
* rx-on:no type:mtd full-net:no
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:0.73% msg:0.00%
|
||||
* conn-time:01:08:53
|
||||
* csl - sync:no period:0 timeout:0 channel:0
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Start a query for child table of a router with a given RLOC16.
|
||||
* Output lists all child entries. Information per child:
|
||||
* - RLOC16
|
||||
* - Extended MAC address
|
||||
* - Thread Version
|
||||
* - Timeout (in seconds)
|
||||
* - Age (seconds since last heard)
|
||||
* - Supervision interval (in seconds)
|
||||
* - Number of queued messages (in case child is sleepy)
|
||||
* - Device Mode
|
||||
* - RSS (average and last)
|
||||
* - Error rates: frame tx (at MAC layer), IPv6 message tx (above MAC)
|
||||
* - Connection time (seconds since link establishment `{dd}d.{hh}:{mm}:{ss}` format)
|
||||
* - CSL info:
|
||||
* - If synchronized
|
||||
* - Period (in unit of 10-symbols-time)
|
||||
* - Timeout (in seconds)
|
||||
*
|
||||
* @cparam meshdiag childtable @ca{router-rloc16}
|
||||
* @sa otMeshDiagQueryChildTable
|
||||
*/
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t routerRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[0].ParseAsUint16(routerRloc16));
|
||||
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(
|
||||
error = otMeshDiagQueryChildTable(GetInstancePtr(), routerRloc16, HandleMeshDiagQueryChildTableResult, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError MeshDiag::Process<Cmd("childip6")>(Arg aArgs[])
|
||||
{
|
||||
/**
|
||||
* @cli meshdiag childip6
|
||||
* @code
|
||||
* meshdiag childip6 0xdc00
|
||||
* child-rloc16: 0xdc02
|
||||
* fdde:ad00:beef:0:ded8:cd58:b73:2c21
|
||||
* fd00:2:0:0:c24a:456:3b6b:c597
|
||||
* fd00:1:0:0:120b:95fe:3ecc:d238
|
||||
* child-rloc16: 0xdc03
|
||||
* fdde:ad00:beef:0:3aa6:b8bf:e7d6:eefe
|
||||
* fd00:2:0:0:8ff8:a188:7436:6720
|
||||
* fd00:1:0:0:1fcf:5495:790a:370f
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Send a query to a parent to retrieve the IPv6 addresses of all its MTD children.
|
||||
* @cparam meshdiag childip6 @ca{parent-rloc16}
|
||||
* @sa otMeshDiagQueryChildrenIp6Addrs
|
||||
*/
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t parentRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[0].ParseAsUint16(parentRloc16));
|
||||
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMeshDiagQueryChildrenIp6Addrs(GetInstancePtr(), parentRloc16,
|
||||
HandleMeshDiagQueryChildIp6Addrs, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError MeshDiag::Process<Cmd("routerneighbortable")>(Arg aArgs[])
|
||||
{
|
||||
/**
|
||||
* @cli meshdiag routerneighbortable
|
||||
* @code
|
||||
* meshdiag routerneighbortable 0x7400
|
||||
* rloc16:0x9c00 ext-addr:764788cf6e57a4d2 ver:4
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:1.38% msg:0.00%
|
||||
* conn-time:01:54:02
|
||||
* rloc16:0x7c00 ext-addr:4ed24fceec9bf6d3 ver:4
|
||||
* rss - ave:-20 last:-20 margin:80
|
||||
* err-rate - frame:0.72% msg:0.00%
|
||||
* conn-time:00:11:27
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Start a query for router neighbor table of a router with a given RLOC16.
|
||||
* Output lists all router neighbor entries. Information per entry:
|
||||
* - RLOC16
|
||||
* - Extended MAC address
|
||||
* - Thread Version
|
||||
* - RSS (average and last) and link margin
|
||||
* - Error rates, frame tx (at MAC layer), IPv6 message tx (above MAC)
|
||||
* - Connection time (seconds since link establishment `{dd}d.{hh}:{mm}:{ss}` format)
|
||||
* @cparam meshdiag routerneighbortable @ca{router-rloc16}
|
||||
* @sa otMeshDiagQueryRouterNeighborTable
|
||||
*/
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t routerRloc16;
|
||||
|
||||
SuccessOrExit(error = aArgs[0].ParseAsUint16(routerRloc16));
|
||||
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = otMeshDiagQueryRouterNeighborTable(GetInstancePtr(), routerRloc16,
|
||||
HandleMeshDiagQueryRouterNeighborTableResult, this));
|
||||
|
||||
error = OT_ERROR_PENDING;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError MeshDiag::Process(Arg aArgs[])
|
||||
{
|
||||
#define CmdEntry(aCommandString) \
|
||||
{ \
|
||||
aCommandString, &MeshDiag::Process<Cmd(aCommandString)> \
|
||||
}
|
||||
|
||||
static constexpr Command kCommands[] = {
|
||||
CmdEntry("childip6"),
|
||||
CmdEntry("childtable"),
|
||||
CmdEntry("routerneighbortable"),
|
||||
CmdEntry("topology"),
|
||||
};
|
||||
|
||||
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
|
||||
|
||||
otError error = OT_ERROR_INVALID_COMMAND;
|
||||
const Command *command;
|
||||
|
||||
if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
|
||||
{
|
||||
OutputCommandTable(kCommands);
|
||||
ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
|
||||
VerifyOrExit(command != nullptr);
|
||||
|
||||
error = (this->*command->mHandler)(aArgs + 1);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext)
|
||||
{
|
||||
reinterpret_cast<MeshDiag *>(aContext)->HandleMeshDiagDiscoverDone(aError, aRouterInfo);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo)
|
||||
{
|
||||
VerifyOrExit(aRouterInfo != nullptr);
|
||||
|
||||
OutputFormat("id:%02u rloc16:0x%04x ext-addr:", aRouterInfo->mRouterId, aRouterInfo->mRloc16);
|
||||
OutputExtAddress(aRouterInfo->mExtAddress);
|
||||
|
||||
if (aRouterInfo->mVersion != OT_MESH_DIAG_VERSION_UNKNOWN)
|
||||
{
|
||||
OutputFormat(" ver:%u", aRouterInfo->mVersion);
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsThisDevice)
|
||||
{
|
||||
OutputFormat(" - me");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsThisDeviceParent)
|
||||
{
|
||||
OutputFormat(" - parent");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsLeader)
|
||||
{
|
||||
OutputFormat(" - leader");
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIsBorderRouter)
|
||||
{
|
||||
OutputFormat(" - br");
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
|
||||
for (uint8_t linkQuality = 3; linkQuality > 0; linkQuality--)
|
||||
{
|
||||
bool hasLinkQuality = false;
|
||||
|
||||
for (uint8_t entryQuality : aRouterInfo->mLinkQualities)
|
||||
{
|
||||
if (entryQuality == linkQuality)
|
||||
{
|
||||
hasLinkQuality = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLinkQuality)
|
||||
{
|
||||
OutputFormat(kIndentSize, "%u-links:{ ", linkQuality);
|
||||
|
||||
for (uint8_t id = 0; id < static_cast<uint8_t>(OT_ARRAY_LENGTH(aRouterInfo->mLinkQualities)); id++)
|
||||
{
|
||||
if (aRouterInfo->mLinkQualities[id] == linkQuality)
|
||||
{
|
||||
OutputFormat("%02u ", id);
|
||||
}
|
||||
}
|
||||
|
||||
OutputLine("}");
|
||||
}
|
||||
}
|
||||
|
||||
if (aRouterInfo->mIp6AddrIterator != nullptr)
|
||||
{
|
||||
otIp6Address ip6Address;
|
||||
|
||||
OutputLine(kIndentSize, "ip6-addrs:");
|
||||
|
||||
while (otMeshDiagGetNextIp6Address(aRouterInfo->mIp6AddrIterator, &ip6Address) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputSpaces(kIndentSize * 2);
|
||||
OutputIp6AddressLine(ip6Address);
|
||||
}
|
||||
}
|
||||
|
||||
if (aRouterInfo->mChildIterator != nullptr)
|
||||
{
|
||||
otMeshDiagChildInfo childInfo;
|
||||
char linkModeString[kLinkModeStringSize];
|
||||
bool isFirst = true;
|
||||
|
||||
while (otMeshDiagGetNextChildInfo(aRouterInfo->mChildIterator, &childInfo) == OT_ERROR_NONE)
|
||||
{
|
||||
if (isFirst)
|
||||
{
|
||||
OutputLine(kIndentSize, "children:");
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
OutputFormat(kIndentSize * 2, "rloc16:0x%04x lq:%u, mode:%s", childInfo.mRloc16, childInfo.mLinkQuality,
|
||||
LinkModeToString(childInfo.mMode, linkModeString));
|
||||
|
||||
if (childInfo.mIsThisDevice)
|
||||
{
|
||||
OutputFormat(" - me");
|
||||
}
|
||||
|
||||
if (childInfo.mIsBorderRouter)
|
||||
{
|
||||
OutputFormat(" - br");
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
}
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
OutputLine(kIndentSize, "children: none");
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryChildTableResult(otError aError,
|
||||
const otMeshDiagChildEntry *aChildEntry,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<MeshDiag *>(aContext)->HandleMeshDiagQueryChildTableResult(aError, aChildEntry);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry)
|
||||
{
|
||||
PercentageStringBuffer stringBuffer;
|
||||
char string[OT_DURATION_STRING_SIZE];
|
||||
|
||||
VerifyOrExit(aChildEntry != nullptr);
|
||||
|
||||
OutputFormat("rloc16:0x%04x ext-addr:", aChildEntry->mRloc16);
|
||||
OutputExtAddress(aChildEntry->mExtAddress);
|
||||
OutputLine(" ver:%u", aChildEntry->mVersion);
|
||||
|
||||
OutputLine(kIndentSize, "timeout:%lu age:%lu supvn:%u q-msg:%u", ToUlong(aChildEntry->mTimeout),
|
||||
ToUlong(aChildEntry->mAge), aChildEntry->mSupervisionInterval, aChildEntry->mQueuedMessageCount);
|
||||
|
||||
OutputLine(kIndentSize, "rx-on:%s type:%s full-net:%s", aChildEntry->mRxOnWhenIdle ? "yes" : "no",
|
||||
aChildEntry->mDeviceTypeFtd ? "ftd" : "mtd", aChildEntry->mFullNetData ? "yes" : "no");
|
||||
|
||||
OutputLine(kIndentSize, "rss - ave:%d last:%d margin:%d", aChildEntry->mAverageRssi, aChildEntry->mLastRssi,
|
||||
aChildEntry->mLinkMargin);
|
||||
|
||||
if (aChildEntry->mSupportsErrRate)
|
||||
{
|
||||
OutputFormat(kIndentSize, "err-rate - frame:%s%% ",
|
||||
PercentageToString(aChildEntry->mFrameErrorRate, stringBuffer));
|
||||
OutputLine("msg:%s%% ", PercentageToString(aChildEntry->mMessageErrorRate, stringBuffer));
|
||||
}
|
||||
|
||||
otConvertDurationInSecondsToString(aChildEntry->mConnectionTime, string, sizeof(string));
|
||||
OutputLine(kIndentSize, "conn-time:%s", string);
|
||||
|
||||
OutputLine(kIndentSize, "csl - sync:%s period:%u timeout:%lu channel:%u",
|
||||
aChildEntry->mCslSynchronized ? "yes" : "no", aChildEntry->mCslPeriod, ToUlong(aChildEntry->mCslTimeout),
|
||||
aChildEntry->mCslChannel);
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<MeshDiag *>(aContext)->HandleMeshDiagQueryRouterNeighborTableResult(aError, aNeighborEntry);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry)
|
||||
{
|
||||
PercentageStringBuffer stringBuffer;
|
||||
char string[OT_DURATION_STRING_SIZE];
|
||||
|
||||
VerifyOrExit(aNeighborEntry != nullptr);
|
||||
|
||||
OutputFormat("rloc16:0x%04x ext-addr:", aNeighborEntry->mRloc16);
|
||||
OutputExtAddress(aNeighborEntry->mExtAddress);
|
||||
OutputLine(" ver:%u", aNeighborEntry->mVersion);
|
||||
|
||||
OutputLine(kIndentSize, "rss - ave:%d last:%d margin:%d", aNeighborEntry->mAverageRssi, aNeighborEntry->mLastRssi,
|
||||
aNeighborEntry->mLinkMargin);
|
||||
|
||||
if (aNeighborEntry->mSupportsErrRate)
|
||||
{
|
||||
OutputFormat(kIndentSize, "err-rate - frame:%s%% ",
|
||||
PercentageToString(aNeighborEntry->mFrameErrorRate, stringBuffer));
|
||||
OutputLine("msg:%s%% ", PercentageToString(aNeighborEntry->mMessageErrorRate, stringBuffer));
|
||||
}
|
||||
|
||||
otConvertDurationInSecondsToString(aNeighborEntry->mConnectionTime, string, sizeof(string));
|
||||
OutputLine(kIndentSize, "conn-time:%s", string);
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator,
|
||||
void *aContext)
|
||||
{
|
||||
reinterpret_cast<MeshDiag *>(aContext)->HandleMeshDiagQueryChildIp6Addrs(aError, aChildRloc16, aIp6AddrIterator);
|
||||
}
|
||||
|
||||
void MeshDiag::HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator)
|
||||
{
|
||||
otIp6Address ip6Address;
|
||||
|
||||
VerifyOrExit(aError == OT_ERROR_NONE || aError == OT_ERROR_PENDING);
|
||||
VerifyOrExit(aIp6AddrIterator != nullptr);
|
||||
|
||||
OutputLine("child-rloc16: 0x%04x", aChildRloc16);
|
||||
|
||||
while (otMeshDiagGetNextIp6Address(aIp6AddrIterator, &ip6Address) == OT_ERROR_NONE)
|
||||
{
|
||||
OutputSpaces(kIndentSize);
|
||||
OutputIp6AddressLine(ip6Address);
|
||||
}
|
||||
|
||||
exit:
|
||||
OutputResult(aError);
|
||||
}
|
||||
|
||||
void MeshDiag::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); }
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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 contains definitions for the CLI interpreter for Mesh Diagnostics function.
|
||||
*/
|
||||
|
||||
#ifndef CLI_MESH_DIAG_HPP_
|
||||
#define CLI_MESH_DIAG_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/mesh_diag.h>
|
||||
|
||||
#include "cli/cli_utils.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
/**
|
||||
* Implements the Mesh Diagnostics CLI interpreter.
|
||||
*/
|
||||
class MeshDiag : private Utils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] aInstance The OpenThread Instance.
|
||||
* @param[in] aOutputImplementer An `OutputImplementer`.
|
||||
*/
|
||||
MeshDiag(otInstance *aInstance, OutputImplementer &aOutputImplementer);
|
||||
|
||||
/**
|
||||
* Processes a CLI sub-command.
|
||||
*
|
||||
* @param[in] aArgs An array of command line arguments.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully executed the CLI command.
|
||||
* @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending.
|
||||
* @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command.
|
||||
* @retval OT_ERROR_INVALID_ARGS Invalid arguments.
|
||||
* @retval ... Error during execution of the CLI command.
|
||||
*/
|
||||
otError Process(Arg aArgs[]);
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kIndentSize = 4;
|
||||
|
||||
using Command = CommandEntry<MeshDiag>;
|
||||
|
||||
template <CommandId kCommandId> otError Process(Arg aArgs[]);
|
||||
|
||||
static void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo, void *aContext);
|
||||
|
||||
void HandleMeshDiagDiscoverDone(otError aError, otMeshDiagRouterInfo *aRouterInfo);
|
||||
|
||||
static void HandleMeshDiagQueryChildTableResult(otError aError,
|
||||
const otMeshDiagChildEntry *aChildEntry,
|
||||
void *aContext);
|
||||
|
||||
void HandleMeshDiagQueryChildTableResult(otError aError, const otMeshDiagChildEntry *aChildEntry);
|
||||
|
||||
static void HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry,
|
||||
void *aContext);
|
||||
|
||||
void HandleMeshDiagQueryRouterNeighborTableResult(otError aError,
|
||||
const otMeshDiagRouterNeighborEntry *aNeighborEntry);
|
||||
|
||||
static void HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator,
|
||||
void *aContext);
|
||||
|
||||
void HandleMeshDiagQueryChildIp6Addrs(otError aError,
|
||||
uint16_t aChildRloc16,
|
||||
otMeshDiagIp6AddrIterator *aIp6AddrIterator);
|
||||
|
||||
void OutputResult(otError aError);
|
||||
};
|
||||
|
||||
} // namespace Cli
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
|
||||
|
||||
#endif // CLI_MESH_DIAG_HPP_
|
||||
Reference in New Issue
Block a user