/src/openthread/src/cli/cli.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016, The OpenThread Authors. |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions are met: |
7 | | * 1. Redistributions of source code must retain the above copyright |
8 | | * notice, this list of conditions and the following disclaimer. |
9 | | * 2. Redistributions in binary form must reproduce the above copyright |
10 | | * notice, this list of conditions and the following disclaimer in the |
11 | | * documentation and/or other materials provided with the distribution. |
12 | | * 3. Neither the name of the copyright holder nor the |
13 | | * names of its contributors may be used to endorse or promote products |
14 | | * derived from this software without specific prior written permission. |
15 | | * |
16 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
17 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
20 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | | * POSSIBILITY OF SUCH DAMAGE. |
27 | | */ |
28 | | |
29 | | /** |
30 | | * @file |
31 | | * This file implements the CLI interpreter. |
32 | | */ |
33 | | |
34 | | #include "cli.hpp" |
35 | | |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | |
40 | | #include <openthread/platform/debug_uart.h> |
41 | | |
42 | | #include <openthread/backbone_router.h> |
43 | | #include <openthread/backbone_router_ftd.h> |
44 | | #include <openthread/border_router.h> |
45 | | #include <openthread/channel_manager.h> |
46 | | #include <openthread/channel_monitor.h> |
47 | | #include <openthread/child_supervision.h> |
48 | | #include <openthread/dataset_ftd.h> |
49 | | #include <openthread/diag.h> |
50 | | #include <openthread/dns.h> |
51 | | #include <openthread/icmp6.h> |
52 | | #include <openthread/nat64.h> |
53 | | #include <openthread/ncp.h> |
54 | | #include <openthread/network_time.h> |
55 | | #include <openthread/radio_stats.h> |
56 | | #include <openthread/server.h> |
57 | | #include <openthread/thread.h> |
58 | | #include <openthread/thread_ftd.h> |
59 | | #include <openthread/trel.h> |
60 | | #include <openthread/verhoeff_checksum.h> |
61 | | #include <openthread/platform/misc.h> |
62 | | |
63 | | #include "common/new.hpp" |
64 | | #include "common/num_utils.hpp" |
65 | | #include "common/numeric_limits.hpp" |
66 | | #include "common/string.hpp" |
67 | | #include "mac/channel_mask.hpp" |
68 | | |
69 | | namespace ot { |
70 | | namespace Cli { |
71 | | |
72 | | Interpreter *Interpreter::sInterpreter = nullptr; |
73 | | static OT_DEFINE_ALIGNED_VAR(sInterpreterRaw, sizeof(Interpreter), uint64_t); |
74 | | |
75 | | Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, void *aContext) |
76 | 7.46k | : OutputImplementer(aCallback, aContext) |
77 | 7.46k | , Utils(aInstance, *this) |
78 | 7.46k | , mCommandIsPending(false) |
79 | 7.46k | , mInternalDebugCommand(false) |
80 | 7.46k | , mTimer(*aInstance, HandleTimer, this) |
81 | | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
82 | | #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
83 | 7.46k | , mSntpQueryingInProgress(false) |
84 | | #endif |
85 | 7.46k | , mDataset(aInstance, *this) |
86 | 7.46k | , mNetworkData(aInstance, *this) |
87 | 7.46k | , mUdp(aInstance, *this) |
88 | | #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |
89 | 7.46k | , mMacFilter(aInstance, *this) |
90 | | #endif |
91 | | #if OPENTHREAD_CLI_DNS_ENABLE |
92 | 7.46k | , mDns(aInstance, *this) |
93 | | #endif |
94 | | #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE |
95 | | , mMdns(aInstance, *this) |
96 | | #endif |
97 | | #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
98 | 7.46k | , mBbr(aInstance, *this) |
99 | | #endif |
100 | | #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
101 | 7.46k | , mBr(aInstance, *this) |
102 | | #endif |
103 | | #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE |
104 | 7.46k | , mTcp(aInstance, *this) |
105 | | #endif |
106 | | #if OPENTHREAD_CONFIG_COAP_API_ENABLE |
107 | 7.46k | , mCoap(aInstance, *this) |
108 | | #endif |
109 | | #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE |
110 | 7.46k | , mCoapSecure(aInstance, *this) |
111 | | #endif |
112 | | #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD |
113 | 7.46k | , mCommissioner(aInstance, *this) |
114 | | #endif |
115 | | #if OPENTHREAD_CONFIG_JOINER_ENABLE |
116 | 7.46k | , mJoiner(aInstance, *this) |
117 | | #endif |
118 | | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE |
119 | 7.46k | , mSrpClient(aInstance, *this) |
120 | | #endif |
121 | | #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
122 | 7.46k | , mSrpServer(aInstance, *this) |
123 | | #endif |
124 | | #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE |
125 | 7.46k | , mHistory(aInstance, *this) |
126 | | #endif |
127 | | #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE |
128 | | , mLinkMetrics(aInstance, *this) |
129 | | #endif |
130 | | #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE |
131 | | , mTcat(aInstance, *this) |
132 | | #endif |
133 | | #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE |
134 | 7.46k | , mPing(aInstance, *this) |
135 | | #endif |
136 | | #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD |
137 | 7.46k | , mMeshDiag(aInstance, *this) |
138 | | #endif |
139 | | #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE |
140 | | , mLocateInProgress(false) |
141 | | #endif |
142 | | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
143 | 7.46k | { |
144 | | #if (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK |
145 | | otIp6SetReceiveCallback(GetInstancePtr(), &Interpreter::HandleIp6Receive, this); |
146 | | #endif |
147 | | #if OPENTHREAD_CONFIG_DIAG_ENABLE |
148 | | otDiagSetOutputCallback(GetInstancePtr(), &Interpreter::HandleDiagOutput, this); |
149 | | #endif |
150 | | |
151 | 7.46k | ClearAllBytes(mUserCommands); |
152 | | |
153 | 7.46k | OutputPrompt(); |
154 | 7.46k | } |
155 | | |
156 | | void Interpreter::OutputResult(otError aError) |
157 | 8.39k | { |
158 | 8.39k | if (mInternalDebugCommand) |
159 | 544 | { |
160 | 544 | if (aError != OT_ERROR_NONE) |
161 | 51 | { |
162 | 51 | OutputLine("Error %u: %s", aError, otThreadErrorToString(aError)); |
163 | 51 | } |
164 | | |
165 | 544 | ExitNow(); |
166 | 544 | } |
167 | | |
168 | 7.84k | OT_ASSERT(mCommandIsPending); |
169 | | |
170 | 7.84k | VerifyOrExit(aError != OT_ERROR_PENDING); |
171 | | |
172 | 6.83k | if (aError == OT_ERROR_NONE) |
173 | 2.27k | { |
174 | 2.27k | OutputLine("Done"); |
175 | 2.27k | } |
176 | 4.55k | else |
177 | 4.55k | { |
178 | 4.55k | OutputLine("Error %u: %s", aError, otThreadErrorToString(aError)); |
179 | 4.55k | } |
180 | | |
181 | 6.83k | mCommandIsPending = false; |
182 | 6.83k | mTimer.Stop(); |
183 | 6.83k | OutputPrompt(); |
184 | | |
185 | 8.39k | exit: |
186 | 8.39k | return; |
187 | 6.83k | } |
188 | | |
189 | | #if OPENTHREAD_CONFIG_DIAG_ENABLE |
190 | | template <> otError Interpreter::Process<Cmd("diag")>(Arg aArgs[]) |
191 | | { |
192 | | char *args[kMaxArgs]; |
193 | | |
194 | | // all diagnostics related features are processed within diagnostics module |
195 | | Arg::CopyArgsToStringArray(aArgs, args); |
196 | | |
197 | | return otDiagProcessCmd(GetInstancePtr(), Arg::GetArgsLength(aArgs), args); |
198 | | } |
199 | | |
200 | | void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext) |
201 | | { |
202 | | static_cast<Interpreter *>(aContext)->HandleDiagOutput(aFormat, aArguments); |
203 | | } |
204 | | |
205 | | void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments) |
206 | | { |
207 | | if (strcmp(aFormat, "OT_ERROR_NONE") == 0) |
208 | | { |
209 | | OutputResult(OT_ERROR_NONE); |
210 | | } |
211 | | else |
212 | | { |
213 | | OutputFormatV(aFormat, aArguments); |
214 | | } |
215 | | } |
216 | | #endif |
217 | | |
218 | | template <> otError Interpreter::Process<Cmd("version")>(Arg aArgs[]) |
219 | 19 | { |
220 | 19 | otError error = OT_ERROR_NONE; |
221 | | |
222 | | /** |
223 | | * @cli version |
224 | | * @code |
225 | | * version |
226 | | * OPENTHREAD/gf4f2f04; Jul 1 2016 17:00:09 |
227 | | * Done |
228 | | * @endcode |
229 | | * @par api_copy |
230 | | * #otGetVersionString |
231 | | */ |
232 | 19 | if (aArgs[0].IsEmpty()) |
233 | 17 | { |
234 | 17 | OutputLine("%s", otGetVersionString()); |
235 | 17 | } |
236 | | |
237 | | /** |
238 | | * @cli version api |
239 | | * @code |
240 | | * version api |
241 | | * 28 |
242 | | * Done |
243 | | * @endcode |
244 | | * @par |
245 | | * Prints the API version number. |
246 | | */ |
247 | 2 | else if (aArgs[0] == "api") |
248 | 1 | { |
249 | 1 | OutputLine("%u", OPENTHREAD_API_VERSION); |
250 | 1 | } |
251 | 1 | else |
252 | 1 | { |
253 | 1 | error = OT_ERROR_INVALID_COMMAND; |
254 | 1 | } |
255 | | |
256 | 19 | return error; |
257 | 19 | } |
258 | | |
259 | | template <> otError Interpreter::Process<Cmd("reset")>(Arg aArgs[]) |
260 | 2 | { |
261 | 2 | otError error = OT_ERROR_NONE; |
262 | | |
263 | 2 | if (aArgs[0].IsEmpty()) |
264 | 1 | { |
265 | 1 | otInstanceReset(GetInstancePtr()); |
266 | 1 | } |
267 | | |
268 | | #if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE |
269 | | /** |
270 | | * @cli reset bootloader |
271 | | * @code |
272 | | * reset bootloader |
273 | | * @endcode |
274 | | * @cparam reset bootloader |
275 | | * @par api_copy |
276 | | * #otInstanceResetToBootloader |
277 | | */ |
278 | | else if (aArgs[0] == "bootloader") |
279 | | { |
280 | | error = otInstanceResetToBootloader(GetInstancePtr()); |
281 | | } |
282 | | #endif |
283 | 1 | else |
284 | 1 | { |
285 | 1 | error = OT_ERROR_INVALID_COMMAND; |
286 | 1 | } |
287 | | |
288 | 2 | return error; |
289 | 2 | } |
290 | | |
291 | | void Interpreter::ProcessLine(char *aLine) |
292 | 8.01k | { |
293 | 8.01k | static const char kCmdFactoryReset[] = "factoryreset"; |
294 | 8.01k | Arg args[kMaxArgs + 1]; |
295 | 8.01k | otError error = OT_ERROR_PARSE; |
296 | 8.01k | bool shouldOutputResult = true; |
297 | | |
298 | 8.01k | OT_ASSERT(aLine != nullptr); |
299 | | |
300 | 8.01k | args[0].Clear(); |
301 | | |
302 | | // Validate and parse the input command line. The `error` is |
303 | | // checked later after other conditions are handled. |
304 | | |
305 | 8.01k | if (StringLength(aLine, kMaxLineLength) <= kMaxLineLength - 1) |
306 | 8.00k | { |
307 | 8.00k | error = ot::Utils::CmdLineParser::ParseCmd(aLine, args, kMaxArgs); |
308 | 8.00k | } |
309 | | |
310 | 8.01k | if (mInternalDebugCommand) |
311 | 544 | { |
312 | | // The `mInternalDebugCommand` indicates that we are executing |
313 | | // the "debug" command which itself will emit a sequence of |
314 | | // CLI commands. During this, `mCommandIsPending` is `true` |
315 | | // and should remain `true` until all emitted commands by |
316 | | // "debug" are processed. |
317 | | |
318 | 544 | OT_ASSERT((error == OT_ERROR_NONE) && !args[0].IsEmpty()); |
319 | 544 | error = ProcessCommand(args); |
320 | 544 | ExitNow(); |
321 | 544 | } |
322 | | |
323 | 7.46k | if (mCommandIsPending && (args[0] != kCmdFactoryReset)) |
324 | 0 | { |
325 | | // If a previous command is still pending, ignore the new |
326 | | // command (even if there is a parse error). We do not |
327 | | // need to `OutputPrompt()` either. |
328 | |
|
329 | 0 | shouldOutputResult = false; |
330 | 0 | ExitNow(); |
331 | 0 | } |
332 | | |
333 | 7.46k | mCommandIsPending = true; |
334 | | |
335 | | // Make sure the parsing of the command at the top of this |
336 | | // method did not fail. |
337 | | |
338 | 7.46k | SuccessOrExit(error); |
339 | | |
340 | 7.46k | if (args[0].IsEmpty()) |
341 | 23 | { |
342 | | // Got an empty command line. |
343 | | |
344 | 23 | mCommandIsPending = false; |
345 | 23 | shouldOutputResult = false; |
346 | 23 | OutputPrompt(); |
347 | 23 | ExitNow(); |
348 | 23 | } |
349 | | |
350 | 7.43k | LogInput(args); |
351 | | |
352 | | #if OPENTHREAD_CONFIG_DIAG_ENABLE |
353 | | if (otDiagIsEnabled(GetInstancePtr()) && (args[0] != "diag") && (args[0] != kCmdFactoryReset)) |
354 | | { |
355 | | OutputLine("under diagnostics mode, execute 'diag stop' before running any other commands."); |
356 | | ExitNow(error = OT_ERROR_INVALID_STATE); |
357 | | } |
358 | | #endif |
359 | | |
360 | 7.43k | error = ProcessCommand(args); |
361 | | |
362 | 8.01k | exit: |
363 | 8.01k | if (shouldOutputResult) |
364 | 7.98k | { |
365 | 7.98k | OutputResult(error); |
366 | 7.98k | } |
367 | 8.01k | } |
368 | | |
369 | | otError Interpreter::ProcessUserCommands(Arg aArgs[]) |
370 | 289 | { |
371 | 289 | otError error = OT_ERROR_INVALID_COMMAND; |
372 | | |
373 | 289 | for (const UserCommandsEntry &entry : mUserCommands) |
374 | 289 | { |
375 | 289 | for (uint8_t i = 0; i < entry.mLength; i++) |
376 | 0 | { |
377 | 0 | if (aArgs[0] == entry.mCommands[i].mName) |
378 | 0 | { |
379 | 0 | char *args[kMaxArgs]; |
380 | |
|
381 | 0 | Arg::CopyArgsToStringArray(aArgs, args); |
382 | 0 | error = entry.mCommands[i].mCommand(entry.mContext, Arg::GetArgsLength(aArgs) - 1, args + 1); |
383 | 0 | break; |
384 | 0 | } |
385 | 0 | } |
386 | 289 | } |
387 | | |
388 | 289 | return error; |
389 | 289 | } |
390 | | |
391 | | otError Interpreter::SetUserCommands(const otCliCommand *aCommands, uint8_t aLength, void *aContext) |
392 | 0 | { |
393 | 0 | otError error = OT_ERROR_FAILED; |
394 | |
|
395 | 0 | for (UserCommandsEntry &entry : mUserCommands) |
396 | 0 | { |
397 | 0 | if (entry.mCommands == nullptr) |
398 | 0 | { |
399 | 0 | entry.mCommands = aCommands; |
400 | 0 | entry.mLength = aLength; |
401 | 0 | entry.mContext = aContext; |
402 | |
|
403 | 0 | error = OT_ERROR_NONE; |
404 | 0 | break; |
405 | 0 | } |
406 | 0 | } |
407 | |
|
408 | 0 | return error; |
409 | 0 | } |
410 | | |
411 | | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
412 | | |
413 | | /** |
414 | | * @cli attachtime |
415 | | * @code |
416 | | * attachtime |
417 | | * 01:38:25 |
418 | | * Done |
419 | | * @endcode |
420 | | * @par |
421 | | * Prints the current attach time (duration since device was last attached). |
422 | | * Duration is formatted as `{hh}:{mm}:{ss}` for hours, minutes, and seconds if it is less than one day. If the |
423 | | * duration is longer than one day, the format is `{dd}d.{hh}:{mm}:{ss}`. |
424 | | */ |
425 | | template <> otError Interpreter::Process<Cmd("attachtime")>(Arg aArgs[]) |
426 | 2 | { |
427 | 2 | otError error = OT_ERROR_NONE; |
428 | 2 | char string[OT_DURATION_STRING_SIZE]; |
429 | | |
430 | 2 | VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
431 | | |
432 | 1 | otConvertDurationInSecondsToString(otThreadGetCurrentAttachDuration(GetInstancePtr()), string, sizeof(string)); |
433 | 1 | OutputLine("%s", string); |
434 | | |
435 | 2 | exit: |
436 | 2 | return error; |
437 | 1 | } |
438 | | |
439 | | #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE |
440 | 149 | template <> otError Interpreter::Process<Cmd("history")>(Arg aArgs[]) { return mHistory.Process(aArgs); } |
441 | | #endif |
442 | | |
443 | | #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE |
444 | | template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[]) |
445 | 37 | { |
446 | 37 | otError error = OT_ERROR_NONE; |
447 | | |
448 | | /** |
449 | | * @cli ba (enable, disable) |
450 | | * @code |
451 | | * ba enable |
452 | | * Done |
453 | | * @endcode |
454 | | * @code |
455 | | * ba disable |
456 | | * Done |
457 | | * @endcode |
458 | | * @cparam ba @ca{enable|disable} |
459 | | * @par api_copy |
460 | | * #otBorderAgentSetEnabled |
461 | | */ |
462 | 37 | if (ProcessEnableDisable(aArgs, otBorderAgentSetEnabled) == OT_ERROR_NONE) |
463 | 2 | { |
464 | 2 | } |
465 | | /** |
466 | | * @cli ba port |
467 | | * @code |
468 | | * ba port |
469 | | * 49153 |
470 | | * Done |
471 | | * @endcode |
472 | | * @par api_copy |
473 | | * #otBorderAgentGetUdpPort |
474 | | */ |
475 | 35 | else if (aArgs[0] == "port") |
476 | 1 | { |
477 | 1 | OutputLine("%u", otBorderAgentGetUdpPort(GetInstancePtr())); |
478 | 1 | } |
479 | | /** |
480 | | * @cli ba state |
481 | | * @code |
482 | | * ba state |
483 | | * Active |
484 | | * Done |
485 | | * @endcode |
486 | | * @par |
487 | | * Prints the current state of the Border Agent service. Possible states are: |
488 | | * - `Disabled`: Border Agent service is disabled. |
489 | | * - `Inactive`: Border Agent service is enabled but not yet active. |
490 | | * - `Active`: Border Agent service is enabled and active. External commissioner can connect and establish secure |
491 | | * DTLS sessions with the Border Agent using PSKc |
492 | | * @sa #otBorderAgentIsActive |
493 | | */ |
494 | 34 | else if (aArgs[0] == "state") |
495 | 1 | { |
496 | 1 | if (!otBorderAgentIsEnabled(GetInstancePtr())) |
497 | 0 | { |
498 | 0 | OutputLine("Disabled"); |
499 | 0 | } |
500 | 1 | else |
501 | 1 | { |
502 | 1 | OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive"); |
503 | 1 | } |
504 | 1 | } |
505 | 33 | #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE |
506 | | /** |
507 | | * @cli ba servicebasename |
508 | | * @code |
509 | | * ba servicebasename OpenThreadBorderAgent |
510 | | * Done |
511 | | * @endcode |
512 | | * @par api_copy |
513 | | * #otBorderAgentSetMeshCoPServiceBaseName |
514 | | */ |
515 | 33 | else if (aArgs[0] == "servicebasename") |
516 | 0 | { |
517 | 0 | VerifyOrExit(!aArgs[1].IsEmpty() && aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
518 | 0 | error = otBorderAgentSetMeshCoPServiceBaseName(GetInstancePtr(), aArgs[1].GetCString()); |
519 | 0 | } |
520 | 33 | #endif |
521 | | /** |
522 | | * @cli ba sessions |
523 | | * @code |
524 | | * ba sessions |
525 | | * [fe80:0:0:0:cc79:2a29:d311:1aea]:9202 connected:yes commissioner:no lifetime:1860 |
526 | | * Done |
527 | | * @endcode |
528 | | * @par |
529 | | * Prints the list of Border Agent's sessions. Information per session: |
530 | | * * Peer socket address (IPv6 address and port). |
531 | | * * Whether or not the session is connected. |
532 | | * * Whether or not the session is accepted as full commissioner. |
533 | | * * Session lifetime in milliseconds (calculated from the time the session was first established). |
534 | | */ |
535 | 33 | else if (aArgs[0] == "sessions") |
536 | 0 | { |
537 | 0 | otBorderAgentSessionIterator iterator; |
538 | 0 | otBorderAgentSessionInfo info; |
539 | 0 | char sockAddrString[OT_IP6_SOCK_ADDR_STRING_SIZE]; |
540 | 0 | Uint64StringBuffer lifetimeString; |
541 | |
|
542 | 0 | otBorderAgentInitSessionIterator(GetInstancePtr(), &iterator); |
543 | |
|
544 | 0 | while (otBorderAgentGetNextSessionInfo(&iterator, &info) == OT_ERROR_NONE) |
545 | 0 | { |
546 | 0 | otIp6SockAddrToString(&info.mPeerSockAddr, sockAddrString, sizeof(sockAddrString)); |
547 | |
|
548 | 0 | OutputLine("%s connected:%s commissioner:%s lifetime:%s", sockAddrString, info.mIsConnected ? "yes" : "no", |
549 | 0 | info.mIsCommissioner ? "yes" : "no", Uint64ToString(info.mLifetime, lifetimeString)); |
550 | 0 | } |
551 | 0 | } |
552 | 33 | #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE |
553 | | /** |
554 | | * @cli ba id (get,set) |
555 | | * @code |
556 | | * ba id |
557 | | * cb6da1e0c0448aaec39fa90f3d58f45c |
558 | | * Done |
559 | | * @endcode |
560 | | * @code |
561 | | * ba id 00112233445566778899aabbccddeeff |
562 | | * Done |
563 | | * @endcode |
564 | | * @cparam ba id [@ca{border-agent-id}] |
565 | | * Use the optional `border-agent-id` argument to set the Border Agent ID. |
566 | | * @par |
567 | | * Gets or sets the 16 bytes Border Router ID which can uniquely identifies the device among multiple BRs. |
568 | | * @sa otBorderAgentGetId |
569 | | * @sa otBorderAgentSetId |
570 | | */ |
571 | 33 | else if (aArgs[0] == "id") |
572 | 25 | { |
573 | 25 | otBorderAgentId id; |
574 | | |
575 | 25 | if (aArgs[1].IsEmpty()) |
576 | 5 | { |
577 | 5 | SuccessOrExit(error = otBorderAgentGetId(GetInstancePtr(), &id)); |
578 | 5 | OutputBytesLine(id.mId); |
579 | 5 | } |
580 | 20 | else |
581 | 20 | { |
582 | 20 | uint16_t idLength = sizeof(id); |
583 | | |
584 | 20 | SuccessOrExit(error = aArgs[1].ParseAsHexString(idLength, id.mId)); |
585 | 14 | VerifyOrExit(idLength == sizeof(id), error = OT_ERROR_INVALID_ARGS); |
586 | 2 | error = otBorderAgentSetId(GetInstancePtr(), &id); |
587 | 2 | } |
588 | 25 | } |
589 | 8 | #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE |
590 | | #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
591 | | else if (aArgs[0] == "ephemeralkey") |
592 | | { |
593 | | bool enable; |
594 | | |
595 | | /** |
596 | | * @cli ba ephemeralkey |
597 | | * @code |
598 | | * ba ephemeralkey |
599 | | * Stopped |
600 | | * Done |
601 | | * @endcode |
602 | | * @par api_copy |
603 | | * #otBorderAgentEphemeralKeyGetState |
604 | | */ |
605 | | if (aArgs[1].IsEmpty()) |
606 | | { |
607 | | otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr()); |
608 | | |
609 | | OutputLine("%s", otBorderAgentEphemeralKeyStateToString(state)); |
610 | | } |
611 | | /** |
612 | | * @cli ba ephemeralkey (enable, disable) |
613 | | * @code |
614 | | * ba ephemeralkey enable |
615 | | * Done |
616 | | * @endcode |
617 | | * @code |
618 | | * ba ephemeralkey |
619 | | * Enabled |
620 | | * Done |
621 | | * @endcode |
622 | | * @cparam ba ephemeralkey @ca{enable|disable} |
623 | | * @par api_copy |
624 | | * #otBorderAgentEphemeralKeySetEnabled |
625 | | */ |
626 | | else if (ProcessEnableDisable(aArgs + 1, otBorderAgentEphemeralKeySetEnabled) == OT_ERROR_NONE) |
627 | | { |
628 | | } |
629 | | /** |
630 | | * @cli ba ephemeralkey start <keystring> [timeout-in-msec] [port] |
631 | | * @code |
632 | | * ba ephemeralkey start Z10X20g3J15w1000P60m16 5000 1234 |
633 | | * Done |
634 | | * @endcode |
635 | | * @cparam ba ephemeralkey start @ca{keystring} [@ca{timeout-in-msec}] [@ca{port}] |
636 | | * @par api_copy |
637 | | * #otBorderAgentEphemeralKeyStart |
638 | | */ |
639 | | else if (aArgs[1] == "start") |
640 | | { |
641 | | uint32_t timeout = 0; |
642 | | uint16_t port = 0; |
643 | | |
644 | | VerifyOrExit(!aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
645 | | |
646 | | if (!aArgs[3].IsEmpty()) |
647 | | { |
648 | | SuccessOrExit(error = aArgs[3].ParseAsUint32(timeout)); |
649 | | } |
650 | | |
651 | | if (!aArgs[4].IsEmpty()) |
652 | | { |
653 | | SuccessOrExit(error = aArgs[4].ParseAsUint16(port)); |
654 | | } |
655 | | |
656 | | error = otBorderAgentEphemeralKeyStart(GetInstancePtr(), aArgs[2].GetCString(), timeout, port); |
657 | | } |
658 | | /** |
659 | | * @cli ba ephemeralkey stop |
660 | | * @code |
661 | | * ba ephemeralkey stop |
662 | | * Done |
663 | | * @endcode |
664 | | * @par api_copy |
665 | | * #otBorderAgentEphemeralKeyStop |
666 | | */ |
667 | | else if (aArgs[1] == "stop") |
668 | | { |
669 | | otBorderAgentEphemeralKeyStop(GetInstancePtr()); |
670 | | } |
671 | | /** |
672 | | * @cli ba ephemeralkey port |
673 | | * @code |
674 | | * ba ephemeralkey port |
675 | | * 49153 |
676 | | * Done |
677 | | * @endcode |
678 | | * @par api_copy |
679 | | * #otBorderAgentEphemeralKeyGetUdpPort |
680 | | */ |
681 | | else if (aArgs[1] == "port") |
682 | | { |
683 | | OutputLine("%u", otBorderAgentEphemeralKeyGetUdpPort(GetInstancePtr())); |
684 | | } |
685 | | /** |
686 | | * @cli ba ephemeralkey callback (enable, disable) |
687 | | * @code |
688 | | * ba ephemeralkey callback enable |
689 | | * Done |
690 | | * @endcode |
691 | | * @code |
692 | | * ba ephemeralkey start W10X10 5000 49155 |
693 | | * Done |
694 | | * BorderAgentEphemeralKey callback - state:Started |
695 | | * BorderAgentEphemeralKey callback - state:Connected |
696 | | * @endcode |
697 | | * @cparam ba ephemeralkey callback @ca{enable|disable} |
698 | | * @par api_copy |
699 | | * #otBorderAgentEphemeralKeySetCallback |
700 | | */ |
701 | | else if (aArgs[1] == "callback") |
702 | | { |
703 | | SuccessOrExit(error = ParseEnableOrDisable(aArgs[2], enable)); |
704 | | |
705 | | if (enable) |
706 | | { |
707 | | otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), HandleBorderAgentEphemeralKeyStateChange, this); |
708 | | } |
709 | | else |
710 | | { |
711 | | otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), nullptr, nullptr); |
712 | | } |
713 | | } |
714 | | else |
715 | | { |
716 | | error = OT_ERROR_INVALID_ARGS; |
717 | | } |
718 | | } |
719 | | #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
720 | | /** |
721 | | * @cli ba counters |
722 | | * @code |
723 | | * ba counters |
724 | | * epskcActivation: 0 |
725 | | * epskcApiDeactivation: 0 |
726 | | * epskcTimeoutDeactivation: 0 |
727 | | * epskcMaxAttemptDeactivation: 0 |
728 | | * epskcDisconnectDeactivation: 0 |
729 | | * epskcInvalidBaStateError: 0 |
730 | | * epskcInvalidArgsError: 0 |
731 | | * epskcStartSecureSessionError: 0 |
732 | | * epskcSecureSessionSuccess: 0 |
733 | | * epskcSecureSessionFailure: 0 |
734 | | * epskcCommissionerPetition: 0 |
735 | | * pskcSecureSessionSuccess: 0 |
736 | | * pskcSecureSessionFailure: 0 |
737 | | * pskcCommissionerPetition: 0 |
738 | | * mgmtActiveGet: 0 |
739 | | * mgmtPendingGet: 0 |
740 | | * Done |
741 | | * @endcode |
742 | | * @par |
743 | | * Gets the border agent counters. |
744 | | * @sa otBorderAgentGetCounters |
745 | | */ |
746 | 8 | else if (aArgs[0] == "counters") |
747 | 1 | { |
748 | 1 | OutputBorderAgentCounters(*otBorderAgentGetCounters(GetInstancePtr())); |
749 | 1 | } |
750 | 7 | else |
751 | 7 | { |
752 | 7 | ExitNow(error = OT_ERROR_INVALID_COMMAND); |
753 | 7 | } |
754 | | |
755 | 37 | exit: |
756 | 37 | return error; |
757 | 37 | } |
758 | | |
759 | | void Interpreter::OutputBorderAgentCounters(const otBorderAgentCounters &aCounters) |
760 | 1 | { |
761 | 1 | struct BaCounterName |
762 | 1 | { |
763 | 1 | const uint32_t otBorderAgentCounters::*mValuePtr; |
764 | 1 | const char *mName; |
765 | 1 | }; |
766 | | |
767 | 1 | static const BaCounterName kBaCounterNames[] = { |
768 | | #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
769 | | {&otBorderAgentCounters::mEpskcActivations, "epskcActivation"}, |
770 | | {&otBorderAgentCounters::mEpskcDeactivationClears, "epskcApiDeactivation"}, |
771 | | {&otBorderAgentCounters::mEpskcDeactivationTimeouts, "epskcTimeoutDeactivation"}, |
772 | | {&otBorderAgentCounters::mEpskcDeactivationMaxAttempts, "epskcMaxAttemptDeactivation"}, |
773 | | {&otBorderAgentCounters::mEpskcDeactivationDisconnects, "epskcDisconnectDeactivation"}, |
774 | | {&otBorderAgentCounters::mEpskcInvalidBaStateErrors, "epskcInvalidBaStateError"}, |
775 | | {&otBorderAgentCounters::mEpskcInvalidArgsErrors, "epskcInvalidArgsError"}, |
776 | | {&otBorderAgentCounters::mEpskcStartSecureSessionErrors, "epskcStartSecureSessionError"}, |
777 | | {&otBorderAgentCounters::mEpskcSecureSessionSuccesses, "epskcSecureSessionSuccess"}, |
778 | | {&otBorderAgentCounters::mEpskcSecureSessionFailures, "epskcSecureSessionFailure"}, |
779 | | {&otBorderAgentCounters::mEpskcCommissionerPetitions, "epskcCommissionerPetition"}, |
780 | | #endif |
781 | 1 | {&otBorderAgentCounters::mPskcSecureSessionSuccesses, "pskcSecureSessionSuccess"}, |
782 | 1 | {&otBorderAgentCounters::mPskcSecureSessionFailures, "pskcSecureSessionFailure"}, |
783 | 1 | {&otBorderAgentCounters::mPskcCommissionerPetitions, "pskcCommissionerPetition"}, |
784 | 1 | {&otBorderAgentCounters::mMgmtActiveGets, "mgmtActiveGet"}, |
785 | 1 | {&otBorderAgentCounters::mMgmtPendingGets, "mgmtPendingGet"}, |
786 | 1 | }; |
787 | | |
788 | 1 | for (const BaCounterName &counter : kBaCounterNames) |
789 | 5 | { |
790 | 5 | OutputLine("%s: %lu", counter.mName, ToUlong(aCounters.*counter.mValuePtr)); |
791 | 5 | } |
792 | 1 | } |
793 | | |
794 | | #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
795 | | void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void *aContext) |
796 | | { |
797 | | reinterpret_cast<Interpreter *>(aContext)->HandleBorderAgentEphemeralKeyStateChange(); |
798 | | } |
799 | | |
800 | | void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void) |
801 | | { |
802 | | otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr()); |
803 | | |
804 | | OutputLine("BorderAgentEphemeralKey callback - state:%s", otBorderAgentEphemeralKeyStateToString(state)); |
805 | | } |
806 | | #endif |
807 | | |
808 | | #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE |
809 | | |
810 | | #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
811 | 658 | template <> otError Interpreter::Process<Cmd("br")>(Arg aArgs[]) { return mBr.Process(aArgs); } |
812 | | #endif |
813 | | |
814 | | #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE |
815 | | template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[]) |
816 | | { |
817 | | otError error = OT_ERROR_NONE; |
818 | | |
819 | | if (aArgs[0].IsEmpty()) |
820 | | { |
821 | | ExitNow(error = OT_ERROR_INVALID_COMMAND); |
822 | | } |
823 | | |
824 | | /** |
825 | | * @cli nat64 (enable,disable) |
826 | | * @code |
827 | | * nat64 enable |
828 | | * Done |
829 | | * @endcode |
830 | | * @code |
831 | | * nat64 disable |
832 | | * Done |
833 | | * @endcode |
834 | | * @cparam nat64 @ca{enable|disable} |
835 | | * @par api_copy |
836 | | * #otNat64SetEnabled |
837 | | */ |
838 | | if (ProcessEnableDisable(aArgs, otNat64SetEnabled) == OT_ERROR_NONE) |
839 | | { |
840 | | } |
841 | | /** |
842 | | * @cli nat64 state |
843 | | * @code |
844 | | * nat64 state |
845 | | * PrefixManager: Active |
846 | | * Translator: Active |
847 | | * Done |
848 | | * @endcode |
849 | | * @par |
850 | | * Gets the state of NAT64 functions. |
851 | | * @par |
852 | | * `PrefixManager` state is available when `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled. |
853 | | * `Translator` state is available when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled. |
854 | | * @par |
855 | | * When `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled, `PrefixManager` returns one of the following |
856 | | * states: |
857 | | * - `Disabled`: NAT64 prefix manager is disabled. |
858 | | * - `NotRunning`: NAT64 prefix manager is enabled, but is not running. This could mean that the routing manager is |
859 | | * disabled. |
860 | | * - `Idle`: NAT64 prefix manager is enabled and is running, but is not publishing a NAT64 prefix. This can happen |
861 | | * when there is another border router publishing a NAT64 prefix with a higher priority. |
862 | | * - `Active`: NAT64 prefix manager is enabled, running, and publishing a NAT64 prefix. |
863 | | * @par |
864 | | * When `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled, `Translator` returns one of the following states: |
865 | | * - `Disabled`: NAT64 translator is disabled. |
866 | | * - `NotRunning`: NAT64 translator is enabled, but is not translating packets. This could mean that the Translator |
867 | | * is not configured with a NAT64 prefix or a CIDR for NAT64. |
868 | | * - `Active`: NAT64 translator is enabled and is translating packets. |
869 | | * @sa otNat64GetPrefixManagerState |
870 | | * @sa otNat64GetTranslatorState |
871 | | */ |
872 | | else if (aArgs[0] == "state") |
873 | | { |
874 | | static const char *const kNat64State[] = {"Disabled", "NotRunning", "Idle", "Active"}; |
875 | | |
876 | | static_assert(0 == OT_NAT64_STATE_DISABLED, "OT_NAT64_STATE_DISABLED value is incorrect"); |
877 | | static_assert(1 == OT_NAT64_STATE_NOT_RUNNING, "OT_NAT64_STATE_NOT_RUNNING value is incorrect"); |
878 | | static_assert(2 == OT_NAT64_STATE_IDLE, "OT_NAT64_STATE_IDLE value is incorrect"); |
879 | | static_assert(3 == OT_NAT64_STATE_ACTIVE, "OT_NAT64_STATE_ACTIVE value is incorrect"); |
880 | | |
881 | | #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE |
882 | | OutputLine("PrefixManager: %s", kNat64State[otNat64GetPrefixManagerState(GetInstancePtr())]); |
883 | | #endif |
884 | | #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE |
885 | | OutputLine("Translator: %s", kNat64State[otNat64GetTranslatorState(GetInstancePtr())]); |
886 | | #endif |
887 | | } |
888 | | #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE |
889 | | else if (aArgs[0] == "cidr") |
890 | | { |
891 | | otIp4Cidr cidr; |
892 | | |
893 | | /** |
894 | | * @cli nat64 cidr |
895 | | * @code |
896 | | * nat64 cidr |
897 | | * 192.168.255.0/24 |
898 | | * Done |
899 | | * @endcode |
900 | | * @par api_copy |
901 | | * #otNat64GetCidr |
902 | | */ |
903 | | if (aArgs[1].IsEmpty()) |
904 | | { |
905 | | char cidrString[OT_IP4_CIDR_STRING_SIZE]; |
906 | | |
907 | | SuccessOrExit(error = otNat64GetCidr(GetInstancePtr(), &cidr)); |
908 | | otIp4CidrToString(&cidr, cidrString, sizeof(cidrString)); |
909 | | OutputLine("%s", cidrString); |
910 | | } |
911 | | /** |
912 | | * @cli nat64 cidr <cidr> |
913 | | * @code |
914 | | * nat64 cidr 192.168.255.0/24 |
915 | | * Done |
916 | | * @endcode |
917 | | * @par api_copy |
918 | | * #otPlatNat64SetIp4Cidr |
919 | | */ |
920 | | else |
921 | | { |
922 | | SuccessOrExit(error = otIp4CidrFromString(aArgs[1].GetCString(), &cidr)); |
923 | | error = otNat64SetIp4Cidr(GetInstancePtr(), &cidr); |
924 | | } |
925 | | } |
926 | | /** |
927 | | * @cli nat64 mappings |
928 | | * @code |
929 | | * nat64 mappings |
930 | | * | | Address | Ports or ICMP Ids | | 4 to 6 | 6 to 4 | |
931 | | * +----------+---------------------------+-----------------------+--------+--------------+--------------+ |
932 | | * | ID | IPv6 | IPv4 | v6 | v4 | Expiry | Pkts | Bytes | Pkts | Bytes | |
933 | | * +----------+------------+--------------+-----------------------+--------+------+-------+------+-------+ |
934 | | * | 00021cb9 | fdc7::df79 | 192.168.64.2 | 65100 | 65200 | 7196s | 6 | 456 | 11 | 1928 | |
935 | | * | TCP | 0 | 0 | 0 | 0 | |
936 | | * | UDP | 1 | 136 | 16 | 1608 | |
937 | | * | ICMP | 5 | 320 | 5 | 320 | |
938 | | * @endcode |
939 | | * @par api_copy |
940 | | * #otNat64GetNextAddressMapping |
941 | | */ |
942 | | else if (aArgs[0] == "mappings") |
943 | | { |
944 | | static const char *const kNat64StatusLevel1Title[] = {"", "Address", "Ports or ICMP Ids", |
945 | | "", "4 to 6", "6 to 4"}; |
946 | | |
947 | | static const uint8_t kNat64StatusLevel1ColumnWidths[] = { |
948 | | 18, 61, 19, 8, 25, 25, |
949 | | }; |
950 | | |
951 | | static const char *const kNat64StatusTableHeader[] = { |
952 | | "ID", "IPv6", "IPv4", "v6", "v4", "Expiry", "Pkts", "Bytes", "Pkts", "Bytes", |
953 | | }; |
954 | | |
955 | | static const uint8_t kNat64StatusTableColumnWidths[] = { |
956 | | 18, 42, 18, 9, 9, 8, 10, 14, 10, 14, |
957 | | }; |
958 | | |
959 | | otNat64AddressMappingIterator iterator; |
960 | | otNat64AddressMapping mapping; |
961 | | |
962 | | OutputTableHeader(kNat64StatusLevel1Title, kNat64StatusLevel1ColumnWidths); |
963 | | OutputTableHeader(kNat64StatusTableHeader, kNat64StatusTableColumnWidths); |
964 | | |
965 | | otNat64InitAddressMappingIterator(GetInstancePtr(), &iterator); |
966 | | while (otNat64GetNextAddressMapping(GetInstancePtr(), &iterator, &mapping) == OT_ERROR_NONE) |
967 | | { |
968 | | char ip4AddressString[OT_IP4_ADDRESS_STRING_SIZE]; |
969 | | char ip6AddressString[OT_IP6_PREFIX_STRING_SIZE]; |
970 | | |
971 | | otIp6AddressToString(&mapping.mIp6, ip6AddressString, sizeof(ip6AddressString)); |
972 | | otIp4AddressToString(&mapping.mIp4, ip4AddressString, sizeof(ip4AddressString)); |
973 | | |
974 | | OutputFormat("| %08lx%08lx ", ToUlong(static_cast<uint32_t>(mapping.mId >> 32)), |
975 | | ToUlong(static_cast<uint32_t>(mapping.mId & 0xffffffff))); |
976 | | OutputFormat("| %40s ", ip6AddressString); |
977 | | OutputFormat("| %16s ", ip4AddressString); |
978 | | #if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE |
979 | | OutputFormat("| %6u ", mapping.mSrcPortOrId); |
980 | | OutputFormat("| %6u ", mapping.mTranslatedPortOrId); |
981 | | #else |
982 | | OutputFormat("| N/A "); |
983 | | OutputFormat("| N/A "); |
984 | | #endif |
985 | | OutputFormat("| %5lus ", ToUlong(mapping.mRemainingTimeMs / 1000)); |
986 | | OutputNat64Counters(mapping.mCounters.mTotal); |
987 | | |
988 | | OutputFormat("| %16s ", ""); |
989 | | OutputFormat("| %88s ", "TCP"); |
990 | | OutputNat64Counters(mapping.mCounters.mTcp); |
991 | | |
992 | | OutputFormat("| %16s ", ""); |
993 | | OutputFormat("| %88s ", "UDP"); |
994 | | OutputNat64Counters(mapping.mCounters.mUdp); |
995 | | |
996 | | OutputFormat("| %16s ", ""); |
997 | | OutputFormat("| %88s ", "ICMP"); |
998 | | OutputNat64Counters(mapping.mCounters.mIcmp); |
999 | | } |
1000 | | } |
1001 | | /** |
1002 | | * @cli nat64 counters |
1003 | | * @code |
1004 | | * nat64 counters |
1005 | | * | | 4 to 6 | 6 to 4 | |
1006 | | * +---------------+-------------------------+-------------------------+ |
1007 | | * | Protocol | Pkts | Bytes | Pkts | Bytes | |
1008 | | * +---------------+----------+--------------+----------+--------------+ |
1009 | | * | Total | 11 | 704 | 11 | 704 | |
1010 | | * | TCP | 0 | 0 | 0 | 0 | |
1011 | | * | UDP | 0 | 0 | 0 | 0 | |
1012 | | * | ICMP | 11 | 704 | 11 | 704 | |
1013 | | * | Errors | Pkts | Pkts | |
1014 | | * +---------------+-------------------------+-------------------------+ |
1015 | | * | Total | 8 | 4 | |
1016 | | * | Illegal Pkt | 0 | 0 | |
1017 | | * | Unsup Proto | 0 | 0 | |
1018 | | * | No Mapping | 2 | 0 | |
1019 | | * Done |
1020 | | * @endcode |
1021 | | * @par |
1022 | | * Gets the NAT64 translator packet and error counters. |
1023 | | * @par |
1024 | | * Available when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled. |
1025 | | * @sa otNat64GetCounters |
1026 | | * @sa otNat64GetErrorCounters |
1027 | | */ |
1028 | | else if (aArgs[0] == "counters") |
1029 | | { |
1030 | | static const char *const kNat64CounterTableHeader[] = { |
1031 | | "", |
1032 | | "4 to 6", |
1033 | | "6 to 4", |
1034 | | }; |
1035 | | static const uint8_t kNat64CounterTableHeaderColumns[] = {15, 25, 25}; |
1036 | | static const char *const kNat64CounterTableSubHeader[] = { |
1037 | | "Protocol", "Pkts", "Bytes", "Pkts", "Bytes", |
1038 | | }; |
1039 | | static const uint8_t kNat64CounterTableSubHeaderColumns[] = { |
1040 | | 15, 10, 14, 10, 14, |
1041 | | }; |
1042 | | static const char *const kNat64CounterTableErrorSubHeader[] = { |
1043 | | "Errors", |
1044 | | "Pkts", |
1045 | | "Pkts", |
1046 | | }; |
1047 | | static const uint8_t kNat64CounterTableErrorSubHeaderColumns[] = { |
1048 | | 15, |
1049 | | 25, |
1050 | | 25, |
1051 | | }; |
1052 | | static const char *const kNat64CounterErrorType[] = { |
1053 | | "Unknown", |
1054 | | "Illegal Pkt", |
1055 | | "Unsup Proto", |
1056 | | "No Mapping", |
1057 | | }; |
1058 | | |
1059 | | otNat64ProtocolCounters counters; |
1060 | | otNat64ErrorCounters errorCounters; |
1061 | | Uint64StringBuffer u64StringBuffer; |
1062 | | |
1063 | | OutputTableHeader(kNat64CounterTableHeader, kNat64CounterTableHeaderColumns); |
1064 | | OutputTableHeader(kNat64CounterTableSubHeader, kNat64CounterTableSubHeaderColumns); |
1065 | | |
1066 | | otNat64GetCounters(GetInstancePtr(), &counters); |
1067 | | otNat64GetErrorCounters(GetInstancePtr(), &errorCounters); |
1068 | | |
1069 | | OutputFormat("| %13s ", "Total"); |
1070 | | OutputNat64Counters(counters.mTotal); |
1071 | | |
1072 | | OutputFormat("| %13s ", "TCP"); |
1073 | | OutputNat64Counters(counters.mTcp); |
1074 | | |
1075 | | OutputFormat("| %13s ", "UDP"); |
1076 | | OutputNat64Counters(counters.mUdp); |
1077 | | |
1078 | | OutputFormat("| %13s ", "ICMP"); |
1079 | | OutputNat64Counters(counters.mIcmp); |
1080 | | |
1081 | | OutputTableHeader(kNat64CounterTableErrorSubHeader, kNat64CounterTableErrorSubHeaderColumns); |
1082 | | for (uint8_t i = 0; i < OT_NAT64_DROP_REASON_COUNT; i++) |
1083 | | { |
1084 | | OutputFormat("| %13s | %23s ", kNat64CounterErrorType[i], |
1085 | | Uint64ToString(errorCounters.mCount4To6[i], u64StringBuffer)); |
1086 | | OutputLine("| %23s |", Uint64ToString(errorCounters.mCount6To4[i], u64StringBuffer)); |
1087 | | } |
1088 | | } |
1089 | | #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE |
1090 | | else |
1091 | | { |
1092 | | ExitNow(error = OT_ERROR_INVALID_COMMAND); |
1093 | | } |
1094 | | |
1095 | | exit: |
1096 | | return error; |
1097 | | } |
1098 | | |
1099 | | #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE |
1100 | | void Interpreter::OutputNat64Counters(const otNat64Counters &aCounters) |
1101 | | { |
1102 | | Uint64StringBuffer u64StringBuffer; |
1103 | | |
1104 | | OutputFormat("| %8s ", Uint64ToString(aCounters.m4To6Packets, u64StringBuffer)); |
1105 | | OutputFormat("| %12s ", Uint64ToString(aCounters.m4To6Bytes, u64StringBuffer)); |
1106 | | OutputFormat("| %8s ", Uint64ToString(aCounters.m6To4Packets, u64StringBuffer)); |
1107 | | OutputLine("| %12s |", Uint64ToString(aCounters.m6To4Bytes, u64StringBuffer)); |
1108 | | } |
1109 | | #endif |
1110 | | |
1111 | | #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE |
1112 | | |
1113 | | #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
1114 | | |
1115 | 2 | template <> otError Interpreter::Process<Cmd("bbr")>(Arg aArgs[]) { return mBbr.Process(aArgs); } |
1116 | | |
1117 | | /** |
1118 | | * @cli domainname |
1119 | | * @code |
1120 | | * domainname |
1121 | | * Thread |
1122 | | * Done |
1123 | | * @endcode |
1124 | | * @par api_copy |
1125 | | * #otThreadGetDomainName |
1126 | | */ |
1127 | | template <> otError Interpreter::Process<Cmd("domainname")>(Arg aArgs[]) |
1128 | 3 | { |
1129 | | /** |
1130 | | * @cli domainname (set) |
1131 | | * @code |
1132 | | * domainname Test\ Thread |
1133 | | * Done |
1134 | | * @endcode |
1135 | | * @cparam domainname @ca{name} |
1136 | | * Use a `backslash` to escape spaces. |
1137 | | * @par api_copy |
1138 | | * #otThreadSetDomainName |
1139 | | */ |
1140 | 3 | return ProcessGetSet(aArgs, otThreadGetDomainName, otThreadSetDomainName); |
1141 | 3 | } |
1142 | | |
1143 | | #if OPENTHREAD_CONFIG_DUA_ENABLE |
1144 | | template <> otError Interpreter::Process<Cmd("dua")>(Arg aArgs[]) |
1145 | | { |
1146 | | otError error = OT_ERROR_NONE; |
1147 | | |
1148 | | /** |
1149 | | * @cli dua iid |
1150 | | * @code |
1151 | | * dua iid |
1152 | | * 0004000300020001 |
1153 | | * Done |
1154 | | * @endcode |
1155 | | * @par api_copy |
1156 | | * #otThreadGetFixedDuaInterfaceIdentifier |
1157 | | */ |
1158 | | if (aArgs[0] == "iid") |
1159 | | { |
1160 | | if (aArgs[1].IsEmpty()) |
1161 | | { |
1162 | | const otIp6InterfaceIdentifier *iid = otThreadGetFixedDuaInterfaceIdentifier(GetInstancePtr()); |
1163 | | |
1164 | | if (iid != nullptr) |
1165 | | { |
1166 | | OutputBytesLine(iid->mFields.m8); |
1167 | | } |
1168 | | } |
1169 | | /** |
1170 | | * @cli dua iid (set,clear) |
1171 | | * @code |
1172 | | * dua iid 0004000300020001 |
1173 | | * Done |
1174 | | * @endcode |
1175 | | * @code |
1176 | | * dua iid clear |
1177 | | * Done |
1178 | | * @endcode |
1179 | | * @cparam dua iid @ca{iid|clear} |
1180 | | * `dua iid clear` passes a `nullptr` to #otThreadSetFixedDuaInterfaceIdentifier. |
1181 | | * Otherwise, you can pass the `iid`. |
1182 | | * @par api_copy |
1183 | | * #otThreadSetFixedDuaInterfaceIdentifier |
1184 | | */ |
1185 | | else if (aArgs[1] == "clear") |
1186 | | { |
1187 | | error = otThreadSetFixedDuaInterfaceIdentifier(GetInstancePtr(), nullptr); |
1188 | | } |
1189 | | else |
1190 | | { |
1191 | | otIp6InterfaceIdentifier iid; |
1192 | | |
1193 | | SuccessOrExit(error = aArgs[1].ParseAsHexString(iid.mFields.m8)); |
1194 | | error = otThreadSetFixedDuaInterfaceIdentifier(GetInstancePtr(), &iid); |
1195 | | } |
1196 | | } |
1197 | | else |
1198 | | { |
1199 | | error = OT_ERROR_INVALID_COMMAND; |
1200 | | } |
1201 | | |
1202 | | exit: |
1203 | | return error; |
1204 | | } |
1205 | | #endif // OPENTHREAD_CONFIG_DUA_ENABLE |
1206 | | |
1207 | | #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
1208 | | |
1209 | | /** |
1210 | | * @cli bufferinfo |
1211 | | * @code |
1212 | | * bufferinfo |
1213 | | * total: 40 |
1214 | | * free: 40 |
1215 | | * max-used: 5 |
1216 | | * 6lo send: 0 0 0 |
1217 | | * 6lo reas: 0 0 0 |
1218 | | * ip6: 0 0 0 |
1219 | | * mpl: 0 0 0 |
1220 | | * mle: 0 0 0 |
1221 | | * coap: 0 0 0 |
1222 | | * coap secure: 0 0 0 |
1223 | | * application coap: 0 0 0 |
1224 | | * Done |
1225 | | * @endcode |
1226 | | * @par |
1227 | | * Gets the current message buffer information. |
1228 | | * * `total` displays the total number of message buffers in pool. |
1229 | | * * `free` displays the number of free message buffers. |
1230 | | * * `max-used` displays max number of used buffers at the same time since OT stack |
1231 | | * initialization or last `bufferinfo reset`. |
1232 | | * @par |
1233 | | * Next, the CLI displays info about different queues used by the OpenThread stack, |
1234 | | * for example `6lo send`. Each line after the queue represents info about a queue: |
1235 | | * * The first number shows number messages in the queue. |
1236 | | * * The second number shows number of buffers used by all messages in the queue. |
1237 | | * * The third number shows total number of bytes of all messages in the queue. |
1238 | | * @sa otMessageGetBufferInfo |
1239 | | */ |
1240 | | template <> otError Interpreter::Process<Cmd("bufferinfo")>(Arg aArgs[]) |
1241 | 19 | { |
1242 | 19 | struct BufferInfoName |
1243 | 19 | { |
1244 | 19 | const otMessageQueueInfo otBufferInfo::*mQueuePtr; |
1245 | 19 | const char *mName; |
1246 | 19 | }; |
1247 | | |
1248 | 19 | static const BufferInfoName kBufferInfoNames[] = { |
1249 | 19 | {&otBufferInfo::m6loSendQueue, "6lo send"}, |
1250 | 19 | {&otBufferInfo::m6loReassemblyQueue, "6lo reas"}, |
1251 | 19 | {&otBufferInfo::mIp6Queue, "ip6"}, |
1252 | 19 | {&otBufferInfo::mMplQueue, "mpl"}, |
1253 | 19 | {&otBufferInfo::mMleQueue, "mle"}, |
1254 | 19 | {&otBufferInfo::mCoapQueue, "coap"}, |
1255 | 19 | {&otBufferInfo::mCoapSecureQueue, "coap secure"}, |
1256 | 19 | {&otBufferInfo::mApplicationCoapQueue, "application coap"}, |
1257 | 19 | }; |
1258 | | |
1259 | 19 | otError error = OT_ERROR_NONE; |
1260 | | |
1261 | 19 | if (aArgs[0].IsEmpty()) |
1262 | 17 | { |
1263 | 17 | otBufferInfo bufferInfo; |
1264 | | |
1265 | 17 | otMessageGetBufferInfo(GetInstancePtr(), &bufferInfo); |
1266 | | |
1267 | 17 | OutputLine("total: %u", bufferInfo.mTotalBuffers); |
1268 | 17 | OutputLine("free: %u", bufferInfo.mFreeBuffers); |
1269 | 17 | OutputLine("max-used: %u", bufferInfo.mMaxUsedBuffers); |
1270 | | |
1271 | 17 | for (const BufferInfoName &info : kBufferInfoNames) |
1272 | 136 | { |
1273 | 136 | OutputLine("%s: %u %u %lu", info.mName, (bufferInfo.*info.mQueuePtr).mNumMessages, |
1274 | 136 | (bufferInfo.*info.mQueuePtr).mNumBuffers, ToUlong((bufferInfo.*info.mQueuePtr).mTotalBytes)); |
1275 | 136 | } |
1276 | 17 | } |
1277 | | /** |
1278 | | * @cli bufferinfo reset |
1279 | | * @code |
1280 | | * bufferinfo reset |
1281 | | * Done |
1282 | | * @endcode |
1283 | | * @par api_copy |
1284 | | * #otMessageResetBufferInfo |
1285 | | */ |
1286 | 2 | else if (aArgs[0] == "reset") |
1287 | 1 | { |
1288 | 1 | otMessageResetBufferInfo(GetInstancePtr()); |
1289 | 1 | } |
1290 | 1 | else |
1291 | 1 | { |
1292 | 1 | error = OT_ERROR_INVALID_ARGS; |
1293 | 1 | } |
1294 | | |
1295 | 19 | return error; |
1296 | 19 | } |
1297 | | |
1298 | | /** |
1299 | | * @cli ccathreshold (get,set) |
1300 | | * @code |
1301 | | * ccathreshold |
1302 | | * -75 dBm |
1303 | | * Done |
1304 | | * @endcode |
1305 | | * @code |
1306 | | * ccathreshold -62 |
1307 | | * Done |
1308 | | * @endcode |
1309 | | * @cparam ccathreshold [@ca{CCA-threshold-dBm}] |
1310 | | * Use the optional `CCA-threshold-dBm` argument to set the CCA threshold. |
1311 | | * @par |
1312 | | * Gets or sets the CCA threshold in dBm measured at the antenna connector per |
1313 | | * IEEE 802.15.4 - 2015 section 10.1.4. |
1314 | | * @sa otPlatRadioGetCcaEnergyDetectThreshold |
1315 | | * @sa otPlatRadioSetCcaEnergyDetectThreshold |
1316 | | */ |
1317 | | template <> otError Interpreter::Process<Cmd("ccathreshold")>(Arg aArgs[]) |
1318 | 3 | { |
1319 | 3 | otError error = OT_ERROR_NONE; |
1320 | 3 | int8_t cca; |
1321 | | |
1322 | 3 | if (aArgs[0].IsEmpty()) |
1323 | 1 | { |
1324 | 1 | SuccessOrExit(error = otPlatRadioGetCcaEnergyDetectThreshold(GetInstancePtr(), &cca)); |
1325 | 0 | OutputLine("%d dBm", cca); |
1326 | 0 | } |
1327 | 2 | else |
1328 | 2 | { |
1329 | 2 | SuccessOrExit(error = aArgs[0].ParseAsInt8(cca)); |
1330 | 1 | error = otPlatRadioSetCcaEnergyDetectThreshold(GetInstancePtr(), cca); |
1331 | 1 | } |
1332 | | |
1333 | 3 | exit: |
1334 | 3 | return error; |
1335 | 3 | } |
1336 | | |
1337 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
1338 | | template <> otError Interpreter::Process<Cmd("ccm")>(Arg aArgs[]) |
1339 | | { |
1340 | | return ProcessEnableDisable(aArgs, otThreadSetCcmEnabled); |
1341 | | } |
1342 | | |
1343 | | template <> otError Interpreter::Process<Cmd("test")>(Arg aArgs[]) |
1344 | | { |
1345 | | otError error = OT_ERROR_NONE; |
1346 | | |
1347 | | /** |
1348 | | * @cli test tmforiginfilter |
1349 | | * @code |
1350 | | * test tmforiginfilter |
1351 | | * Enabled |
1352 | | * @endcode |
1353 | | * @code |
1354 | | * test tmforiginfilter enable |
1355 | | * Done |
1356 | | * @endcode |
1357 | | * @code |
1358 | | * test tmforiginfilter disable |
1359 | | * Done |
1360 | | * @endcode |
1361 | | * @cparam test tmforiginfilter [@ca{enable|disable}] |
1362 | | * @par |
1363 | | * Enables or disables the filter to drop TMF UDP messages from untrusted origin. |
1364 | | * @par |
1365 | | * By default the filter that drops TMF UDP messages from untrusted origin |
1366 | | * is enabled. When disabled, UDP messages sent to the TMF port that originate |
1367 | | * from untrusted origin (such as host, CLI or an external IPv6 node) will be |
1368 | | * allowed. |
1369 | | * @note `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. |
1370 | | */ |
1371 | | if (aArgs[0] == "tmforiginfilter") |
1372 | | { |
1373 | | error = ProcessEnableDisable(aArgs + 1, otThreadIsTmfOriginFilterEnabled, otThreadSetTmfOriginFilterEnabled); |
1374 | | } |
1375 | | |
1376 | | return error; |
1377 | | } |
1378 | | |
1379 | | /** |
1380 | | * @cli tvcheck (enable,disable) |
1381 | | * @code |
1382 | | * tvcheck enable |
1383 | | * Done |
1384 | | * @endcode |
1385 | | * @code |
1386 | | * tvcheck disable |
1387 | | * Done |
1388 | | * @endcode |
1389 | | * @par |
1390 | | * Enables or disables the Thread version check when upgrading to router or leader. |
1391 | | * This check is enabled by default. |
1392 | | * @note `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. |
1393 | | * @sa otThreadSetThreadVersionCheckEnabled |
1394 | | */ |
1395 | | template <> otError Interpreter::Process<Cmd("tvcheck")>(Arg aArgs[]) |
1396 | | { |
1397 | | return ProcessEnableDisable(aArgs, otThreadSetThreadVersionCheckEnabled); |
1398 | | } |
1399 | | #endif |
1400 | | |
1401 | | /** |
1402 | | * @cli channel (get,set) |
1403 | | * @code |
1404 | | * channel |
1405 | | * 11 |
1406 | | * Done |
1407 | | * @endcode |
1408 | | * @code |
1409 | | * channel 11 |
1410 | | * Done |
1411 | | * @endcode |
1412 | | * @cparam channel [@ca{channel-num}] |
1413 | | * Use `channel-num` to set the channel. |
1414 | | * @par |
1415 | | * Gets or sets the IEEE 802.15.4 Channel value. |
1416 | | */ |
1417 | | template <> otError Interpreter::Process<Cmd("channel")>(Arg aArgs[]) |
1418 | 147 | { |
1419 | 147 | otError error = OT_ERROR_NONE; |
1420 | | |
1421 | | /** |
1422 | | * @cli channel supported |
1423 | | * @code |
1424 | | * channel supported |
1425 | | * 0x7fff800 |
1426 | | * Done |
1427 | | * @endcode |
1428 | | * @par api_copy |
1429 | | * #otPlatRadioGetSupportedChannelMask |
1430 | | */ |
1431 | 147 | if (aArgs[0] == "supported") |
1432 | 1 | { |
1433 | 1 | OutputLine("0x%lx", ToUlong(otPlatRadioGetSupportedChannelMask(GetInstancePtr()))); |
1434 | 1 | } |
1435 | | /** |
1436 | | * @cli channel preferred |
1437 | | * @code |
1438 | | * channel preferred |
1439 | | * 0x7fff800 |
1440 | | * Done |
1441 | | * @endcode |
1442 | | * @par api_copy |
1443 | | * #otPlatRadioGetPreferredChannelMask |
1444 | | */ |
1445 | 146 | else if (aArgs[0] == "preferred") |
1446 | 1 | { |
1447 | 1 | OutputLine("0x%lx", ToUlong(otPlatRadioGetPreferredChannelMask(GetInstancePtr()))); |
1448 | 1 | } |
1449 | 145 | #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
1450 | | /** |
1451 | | * @cli channel monitor |
1452 | | * @code |
1453 | | * channel monitor |
1454 | | * enabled: 1 |
1455 | | * interval: 41000 |
1456 | | * threshold: -75 |
1457 | | * window: 960 |
1458 | | * count: 10552 |
1459 | | * occupancies: |
1460 | | * ch 11 (0x0cb7) 4.96% busy |
1461 | | * ch 12 (0x2e2b) 18.03% busy |
1462 | | * ch 13 (0x2f54) 18.48% busy |
1463 | | * ch 14 (0x0fef) 6.22% busy |
1464 | | * ch 15 (0x1536) 8.28% busy |
1465 | | * ch 16 (0x1746) 9.09% busy |
1466 | | * ch 17 (0x0b8b) 4.50% busy |
1467 | | * ch 18 (0x60a7) 37.75% busy |
1468 | | * ch 19 (0x0810) 3.14% busy |
1469 | | * ch 20 (0x0c2a) 4.75% busy |
1470 | | * ch 21 (0x08dc) 3.46% busy |
1471 | | * ch 22 (0x101d) 6.29% busy |
1472 | | * ch 23 (0x0092) 0.22% busy |
1473 | | * ch 24 (0x0028) 0.06% busy |
1474 | | * ch 25 (0x0063) 0.15% busy |
1475 | | * ch 26 (0x058c) 2.16% busy |
1476 | | * Done |
1477 | | * @endcode |
1478 | | * @par |
1479 | | * Get the current channel monitor state and channel occupancy. |
1480 | | * `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` is required. |
1481 | | */ |
1482 | 145 | else if (aArgs[0] == "monitor") |
1483 | 4 | { |
1484 | 4 | if (aArgs[1].IsEmpty()) |
1485 | 1 | { |
1486 | 1 | OutputLine("enabled: %d", otChannelMonitorIsEnabled(GetInstancePtr())); |
1487 | 1 | if (otChannelMonitorIsEnabled(GetInstancePtr())) |
1488 | 1 | { |
1489 | 1 | uint32_t channelMask = otLinkGetSupportedChannelMask(GetInstancePtr()); |
1490 | 1 | uint8_t channelNum = BitSizeOf(channelMask); |
1491 | | |
1492 | 1 | OutputLine("interval: %lu", ToUlong(otChannelMonitorGetSampleInterval(GetInstancePtr()))); |
1493 | 1 | OutputLine("threshold: %d", otChannelMonitorGetRssiThreshold(GetInstancePtr())); |
1494 | 1 | OutputLine("window: %lu", ToUlong(otChannelMonitorGetSampleWindow(GetInstancePtr()))); |
1495 | 1 | OutputLine("count: %lu", ToUlong(otChannelMonitorGetSampleCount(GetInstancePtr()))); |
1496 | | |
1497 | 1 | OutputLine("occupancies:"); |
1498 | | |
1499 | 33 | for (uint8_t channel = 0; channel < channelNum; channel++) |
1500 | 32 | { |
1501 | 32 | uint16_t occupancy; |
1502 | 32 | PercentageStringBuffer stringBuffer; |
1503 | | |
1504 | 32 | if (!((1UL << channel) & channelMask)) |
1505 | 16 | { |
1506 | 16 | continue; |
1507 | 16 | } |
1508 | | |
1509 | 16 | occupancy = otChannelMonitorGetChannelOccupancy(GetInstancePtr(), channel); |
1510 | | |
1511 | 16 | OutputLine("ch %u (0x%04x) %6s%% busy", channel, occupancy, |
1512 | 16 | PercentageToString(occupancy, stringBuffer)); |
1513 | 16 | } |
1514 | | |
1515 | 1 | OutputNewLine(); |
1516 | 1 | } |
1517 | 1 | } |
1518 | | /** |
1519 | | * @cli channel monitor start |
1520 | | * @code |
1521 | | * channel monitor start |
1522 | | * channel monitor start |
1523 | | * Done |
1524 | | * @endcode |
1525 | | * @par |
1526 | | * Start the channel monitor. |
1527 | | * OT CLI sends a boolean value of `true` to #otChannelMonitorSetEnabled. |
1528 | | * `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` is required. |
1529 | | * @sa otChannelMonitorSetEnabled |
1530 | | */ |
1531 | 3 | else if (aArgs[1] == "start") |
1532 | 1 | { |
1533 | 1 | error = otChannelMonitorSetEnabled(GetInstancePtr(), true); |
1534 | 1 | } |
1535 | | /** |
1536 | | * @cli channel monitor stop |
1537 | | * @code |
1538 | | * channel monitor stop |
1539 | | * channel monitor stop |
1540 | | * Done |
1541 | | * @endcode |
1542 | | * @par |
1543 | | * Stop the channel monitor. |
1544 | | * OT CLI sends a boolean value of `false` to #otChannelMonitorSetEnabled. |
1545 | | * `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` is required. |
1546 | | * @sa otChannelMonitorSetEnabled |
1547 | | */ |
1548 | 2 | else if (aArgs[1] == "stop") |
1549 | 1 | { |
1550 | 1 | error = otChannelMonitorSetEnabled(GetInstancePtr(), false); |
1551 | 1 | } |
1552 | 1 | else |
1553 | 1 | { |
1554 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
1555 | 1 | } |
1556 | 4 | } |
1557 | 141 | #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
1558 | 141 | #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE && \ |
1559 | 141 | (OPENTHREAD_FTD || OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) |
1560 | 141 | else if (aArgs[0] == "manager") |
1561 | 120 | { |
1562 | | /** |
1563 | | * @cli channel manager |
1564 | | * @code |
1565 | | * channel manager |
1566 | | * channel: 11 |
1567 | | * auto: 1 |
1568 | | * delay: 120 |
1569 | | * interval: 10800 |
1570 | | * supported: { 11-26} |
1571 | | * favored: { 11-26} |
1572 | | * Done |
1573 | | * @endcode |
1574 | | * @par |
1575 | | * Get the channel manager state. |
1576 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1577 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE` is required. |
1578 | | * @sa otChannelManagerGetRequestedChannel |
1579 | | */ |
1580 | 120 | if (aArgs[1].IsEmpty()) |
1581 | 2 | { |
1582 | 2 | OutputLine("channel: %u", otChannelManagerGetRequestedChannel(GetInstancePtr())); |
1583 | 2 | #if OPENTHREAD_FTD |
1584 | 2 | OutputLine("auto: %d", otChannelManagerGetAutoChannelSelectionEnabled(GetInstancePtr())); |
1585 | 2 | #endif |
1586 | | #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE |
1587 | | OutputLine("autocsl: %u", otChannelManagerGetAutoCslChannelSelectionEnabled(GetInstancePtr())); |
1588 | | #endif |
1589 | | |
1590 | | #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) |
1591 | | if (otChannelManagerGetAutoChannelSelectionEnabled(GetInstancePtr()) || |
1592 | | otChannelManagerGetAutoCslChannelSelectionEnabled(GetInstancePtr())) |
1593 | | #elif OPENTHREAD_FTD |
1594 | 2 | if (otChannelManagerGetAutoChannelSelectionEnabled(GetInstancePtr())) |
1595 | | #elif OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE |
1596 | | if (otChannelManagerGetAutoCslChannelSelectionEnabled(GetInstancePtr())) |
1597 | | #endif |
1598 | 0 | { |
1599 | 0 | Mac::ChannelMask supportedMask(otChannelManagerGetSupportedChannels(GetInstancePtr())); |
1600 | 0 | Mac::ChannelMask favoredMask(otChannelManagerGetFavoredChannels(GetInstancePtr())); |
1601 | 0 | #if OPENTHREAD_FTD |
1602 | 0 | OutputLine("delay: %u", otChannelManagerGetDelay(GetInstancePtr())); |
1603 | 0 | #endif |
1604 | 0 | OutputLine("interval: %lu", ToUlong(otChannelManagerGetAutoChannelSelectionInterval(GetInstancePtr()))); |
1605 | 0 | OutputLine("cca threshold: 0x%04x", otChannelManagerGetCcaFailureRateThreshold(GetInstancePtr())); |
1606 | 0 | OutputLine("supported: %s", supportedMask.ToString().AsCString()); |
1607 | 0 | OutputLine("favored: %s", favoredMask.ToString().AsCString()); |
1608 | 0 | } |
1609 | 2 | } |
1610 | 118 | #if OPENTHREAD_FTD |
1611 | | /** |
1612 | | * @cli channel manager change |
1613 | | * @code |
1614 | | * channel manager change 11 |
1615 | | * channel manager change 11 |
1616 | | * Done |
1617 | | * @endcode |
1618 | | * @cparam channel manager change @ca{channel-num} |
1619 | | * @par |
1620 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` is required. |
1621 | | * @par api_copy |
1622 | | * #otChannelManagerRequestChannelChange |
1623 | | */ |
1624 | 118 | else if (aArgs[1] == "change") |
1625 | 10 | { |
1626 | 10 | error = ProcessSet(aArgs + 2, otChannelManagerRequestChannelChange); |
1627 | 10 | } |
1628 | 108 | #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
1629 | | /** |
1630 | | * @cli channel manager select |
1631 | | * @code |
1632 | | * channel manager select 1 |
1633 | | * channel manager select 1 |
1634 | | * Done |
1635 | | * @endcode |
1636 | | * @cparam channel manager select @ca{skip-quality-check} |
1637 | | * Use a `1` or `0` for the boolean `skip-quality-check`. |
1638 | | * @par |
1639 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1640 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1641 | | * are required. |
1642 | | * @par api_copy |
1643 | | * #otChannelManagerRequestChannelSelect |
1644 | | */ |
1645 | 108 | else if (aArgs[1] == "select") |
1646 | 2 | { |
1647 | 2 | bool enable; |
1648 | | |
1649 | 2 | SuccessOrExit(error = aArgs[2].ParseAsBool(enable)); |
1650 | 1 | error = otChannelManagerRequestChannelSelect(GetInstancePtr(), enable); |
1651 | 1 | } |
1652 | 106 | #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE |
1653 | | /** |
1654 | | * @cli channel manager auto |
1655 | | * @code |
1656 | | * channel manager auto 1 |
1657 | | * channel manager auto 1 |
1658 | | * Done |
1659 | | * @endcode |
1660 | | * @cparam channel manager auto @ca{enable} |
1661 | | * `1` is a boolean to `enable`. |
1662 | | * @par |
1663 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1664 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1665 | | * are required. |
1666 | | * @par api_copy |
1667 | | * #otChannelManagerSetAutoChannelSelectionEnabled |
1668 | | */ |
1669 | 106 | else if (aArgs[1] == "auto") |
1670 | 3 | { |
1671 | 3 | bool enable; |
1672 | | |
1673 | 3 | SuccessOrExit(error = aArgs[2].ParseAsBool(enable)); |
1674 | 2 | otChannelManagerSetAutoChannelSelectionEnabled(GetInstancePtr(), enable); |
1675 | 2 | } |
1676 | 103 | #endif // OPENTHREAD_FTD |
1677 | | #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE |
1678 | | /** |
1679 | | * @cli channel manager autocsl |
1680 | | * @code |
1681 | | * channel manager autocsl 1 |
1682 | | * Done |
1683 | | * @endcode |
1684 | | * @cparam channel manager autocsl @ca{enable} |
1685 | | * `1` is a boolean to `enable`. |
1686 | | * @par |
1687 | | * Enables or disables the auto channel selection functionality for a CSL channel. |
1688 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1689 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1690 | | * are required. |
1691 | | * @sa otChannelManagerSetAutoCslChannelSelectionEnabled |
1692 | | */ |
1693 | | else if (aArgs[1] == "autocsl") |
1694 | | { |
1695 | | bool enable; |
1696 | | |
1697 | | SuccessOrExit(error = aArgs[2].ParseAsBool(enable)); |
1698 | | otChannelManagerSetAutoCslChannelSelectionEnabled(GetInstancePtr(), enable); |
1699 | | } |
1700 | | #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE |
1701 | 103 | #if OPENTHREAD_FTD |
1702 | | /** |
1703 | | * @cli channel manager delay |
1704 | | * @code |
1705 | | * channel manager delay 120 |
1706 | | * channel manager delay 120 |
1707 | | * Done |
1708 | | * @endcode |
1709 | | * @cparam channel manager delay @ca{delay-seconds} |
1710 | | * @par |
1711 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` are required. |
1712 | | * @par api_copy |
1713 | | * #otChannelManagerSetDelay |
1714 | | */ |
1715 | 103 | else if (aArgs[1] == "delay") |
1716 | 5 | { |
1717 | 5 | error = ProcessGetSet(aArgs + 2, otChannelManagerGetDelay, otChannelManagerSetDelay); |
1718 | 5 | } |
1719 | 98 | #endif |
1720 | | /** |
1721 | | * @cli channel manager interval |
1722 | | * @code |
1723 | | * channel manager interval 10800 |
1724 | | * channel manager interval 10800 |
1725 | | * Done |
1726 | | * @endcode |
1727 | | * @cparam channel manager interval @ca{interval-seconds} |
1728 | | * @par |
1729 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1730 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1731 | | * are required. |
1732 | | * @par api_copy |
1733 | | * #otChannelManagerSetAutoChannelSelectionInterval |
1734 | | */ |
1735 | 98 | else if (aArgs[1] == "interval") |
1736 | 88 | { |
1737 | 88 | error = ProcessSet(aArgs + 2, otChannelManagerSetAutoChannelSelectionInterval); |
1738 | 88 | } |
1739 | | /** |
1740 | | * @cli channel manager supported |
1741 | | * @code |
1742 | | * channel manager supported 0x7fffc00 |
1743 | | * channel manager supported 0x7fffc00 |
1744 | | * Done |
1745 | | * @endcode |
1746 | | * @cparam channel manager supported @ca{mask} |
1747 | | * @par |
1748 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1749 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1750 | | * are required. |
1751 | | * @par api_copy |
1752 | | * #otChannelManagerSetSupportedChannels |
1753 | | */ |
1754 | 10 | else if (aArgs[1] == "supported") |
1755 | 3 | { |
1756 | 3 | error = ProcessSet(aArgs + 2, otChannelManagerSetSupportedChannels); |
1757 | 3 | } |
1758 | | /** |
1759 | | * @cli channel manager favored |
1760 | | * @code |
1761 | | * channel manager favored 0x7fffc00 |
1762 | | * channel manager favored 0x7fffc00 |
1763 | | * Done |
1764 | | * @endcode |
1765 | | * @cparam channel manager favored @ca{mask} |
1766 | | * @par |
1767 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1768 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1769 | | * are required. |
1770 | | * @par api_copy |
1771 | | * #otChannelManagerSetFavoredChannels |
1772 | | */ |
1773 | 7 | else if (aArgs[1] == "favored") |
1774 | 3 | { |
1775 | 3 | error = ProcessSet(aArgs + 2, otChannelManagerSetFavoredChannels); |
1776 | 3 | } |
1777 | | /** |
1778 | | * @cli channel manager threshold |
1779 | | * @code |
1780 | | * channel manager threshold 0xffff |
1781 | | * channel manager threshold 0xffff |
1782 | | * Done |
1783 | | * @endcode |
1784 | | * @cparam channel manager threshold @ca{threshold-percent} |
1785 | | * Use a hex value for `threshold-percent`. `0` maps to 0% and `0xffff` maps to 100%. |
1786 | | * @par |
1787 | | * `OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE` or `OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && |
1788 | | * OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE`, and `OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE` |
1789 | | * are required. |
1790 | | * @par api_copy |
1791 | | * #otChannelManagerSetCcaFailureRateThreshold |
1792 | | */ |
1793 | 4 | else if (aArgs[1] == "threshold") |
1794 | 3 | { |
1795 | 3 | error = ProcessSet(aArgs + 2, otChannelManagerSetCcaFailureRateThreshold); |
1796 | 3 | } |
1797 | 1 | else |
1798 | 1 | { |
1799 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
1800 | 1 | } |
1801 | 120 | } |
1802 | 21 | #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE && OPENTHREAD_FTD |
1803 | 21 | else |
1804 | 21 | { |
1805 | 21 | ExitNow(error = ProcessGetSet(aArgs, otLinkGetChannel, otLinkSetChannel)); |
1806 | 21 | } |
1807 | | |
1808 | 147 | exit: |
1809 | 147 | return error; |
1810 | 147 | } |
1811 | | |
1812 | | #if OPENTHREAD_FTD |
1813 | | template <> otError Interpreter::Process<Cmd("child")>(Arg aArgs[]) |
1814 | 302 | { |
1815 | 302 | otError error = OT_ERROR_NONE; |
1816 | 302 | otChildInfo childInfo; |
1817 | 302 | uint16_t childId; |
1818 | 302 | bool isTable; |
1819 | 302 | otLinkModeConfig linkMode; |
1820 | 302 | char linkModeString[kLinkModeStringSize]; |
1821 | | |
1822 | 302 | isTable = (aArgs[0] == "table"); |
1823 | | |
1824 | 302 | if (isTable || (aArgs[0] == "list")) |
1825 | 19 | { |
1826 | 19 | uint16_t maxChildren; |
1827 | | |
1828 | | /** |
1829 | | * @cli child table |
1830 | | * @code |
1831 | | * child table |
1832 | | * | ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC | |
1833 | | * +-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+ |
1834 | | * | 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 4ecede68435358ac | |
1835 | | * | 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | a672a601d2ce37d8 | |
1836 | | * Done |
1837 | | * @endcode |
1838 | | * @par |
1839 | | * Prints a table of the attached children. |
1840 | | * @sa otThreadGetChildInfoByIndex |
1841 | | */ |
1842 | 19 | if (isTable) |
1843 | 18 | { |
1844 | 18 | static const char *const kChildTableTitles[] = { |
1845 | 18 | "ID", "RLOC16", "Timeout", "Age", "LQ In", "C_VN", "R", |
1846 | 18 | "D", "N", "Ver", "CSL", "QMsgCnt", "Suprvsn", "Extended MAC", |
1847 | 18 | }; |
1848 | | |
1849 | 18 | static const uint8_t kChildTableColumnWidths[] = { |
1850 | 18 | 5, 8, 12, 12, 7, 6, 1, 1, 1, 3, 3, 7, 7, 18, |
1851 | 18 | }; |
1852 | | |
1853 | 18 | OutputTableHeader(kChildTableTitles, kChildTableColumnWidths); |
1854 | 18 | } |
1855 | | |
1856 | 19 | maxChildren = otThreadGetMaxAllowedChildren(GetInstancePtr()); |
1857 | | |
1858 | 209 | for (uint16_t i = 0; i < maxChildren; i++) |
1859 | 190 | { |
1860 | 190 | if ((otThreadGetChildInfoByIndex(GetInstancePtr(), i, &childInfo) != OT_ERROR_NONE) || |
1861 | 190 | childInfo.mIsStateRestoring) |
1862 | 190 | { |
1863 | 190 | continue; |
1864 | 190 | } |
1865 | | |
1866 | 0 | if (isTable) |
1867 | 0 | { |
1868 | 0 | OutputFormat("| %3u ", childInfo.mChildId); |
1869 | 0 | OutputFormat("| 0x%04x ", childInfo.mRloc16); |
1870 | 0 | OutputFormat("| %10lu ", ToUlong(childInfo.mTimeout)); |
1871 | 0 | OutputFormat("| %10lu ", ToUlong(childInfo.mAge)); |
1872 | 0 | OutputFormat("| %5u ", childInfo.mLinkQualityIn); |
1873 | 0 | OutputFormat("| %4u ", childInfo.mNetworkDataVersion); |
1874 | 0 | OutputFormat("|%1d", childInfo.mRxOnWhenIdle); |
1875 | 0 | OutputFormat("|%1d", childInfo.mFullThreadDevice); |
1876 | 0 | OutputFormat("|%1d", childInfo.mFullNetworkData); |
1877 | 0 | OutputFormat("|%3u", childInfo.mVersion); |
1878 | 0 | OutputFormat("| %1d ", childInfo.mIsCslSynced); |
1879 | 0 | OutputFormat("| %5u ", childInfo.mQueuedMessageCnt); |
1880 | 0 | OutputFormat("| %5u ", childInfo.mSupervisionInterval); |
1881 | 0 | OutputFormat("| "); |
1882 | 0 | OutputExtAddress(childInfo.mExtAddress); |
1883 | 0 | OutputLine(" |"); |
1884 | 0 | } |
1885 | | /** |
1886 | | * @cli child list |
1887 | | * @code |
1888 | | * child list |
1889 | | * 1 2 3 6 7 8 |
1890 | | * Done |
1891 | | * @endcode |
1892 | | * @par |
1893 | | * Returns a list of attached Child IDs. |
1894 | | * @sa otThreadGetChildInfoByIndex |
1895 | | */ |
1896 | 0 | else |
1897 | 0 | { |
1898 | 0 | OutputFormat("%u ", childInfo.mChildId); |
1899 | 0 | } |
1900 | 0 | } |
1901 | | |
1902 | 19 | OutputNewLine(); |
1903 | 19 | ExitNow(); |
1904 | 19 | } |
1905 | | |
1906 | 283 | SuccessOrExit(error = aArgs[0].ParseAsUint16(childId)); |
1907 | 59 | SuccessOrExit(error = otThreadGetChildInfoById(GetInstancePtr(), childId, &childInfo)); |
1908 | | |
1909 | | /** |
1910 | | * @cli child (id) |
1911 | | * @code |
1912 | | * child 1 |
1913 | | * Child ID: 1 |
1914 | | * Rloc: 9c01 |
1915 | | * Ext Addr: e2b3540590b0fd87 |
1916 | | * Mode: rn |
1917 | | * CSL Synchronized: 1 |
1918 | | * Net Data: 184 |
1919 | | * Timeout: 100 |
1920 | | * Age: 0 |
1921 | | * Link Quality In: 3 |
1922 | | * RSSI: -20 |
1923 | | * Done |
1924 | | * @endcode |
1925 | | * @cparam child @ca{child-id} |
1926 | | * @par api_copy |
1927 | | * #otThreadGetChildInfoById |
1928 | | */ |
1929 | 0 | OutputLine("Child ID: %u", childInfo.mChildId); |
1930 | 0 | OutputLine("Rloc: %04x", childInfo.mRloc16); |
1931 | 0 | OutputFormat("Ext Addr: "); |
1932 | 0 | OutputExtAddressLine(childInfo.mExtAddress); |
1933 | 0 | linkMode.mRxOnWhenIdle = childInfo.mRxOnWhenIdle; |
1934 | 0 | linkMode.mDeviceType = childInfo.mFullThreadDevice; |
1935 | 0 | linkMode.mNetworkData = childInfo.mFullThreadDevice; |
1936 | 0 | OutputLine("Mode: %s", LinkModeToString(linkMode, linkModeString)); |
1937 | 0 | OutputLine("CSL Synchronized: %d ", childInfo.mIsCslSynced); |
1938 | 0 | OutputLine("Net Data: %u", childInfo.mNetworkDataVersion); |
1939 | 0 | OutputLine("Timeout: %lu", ToUlong(childInfo.mTimeout)); |
1940 | 0 | OutputLine("Age: %lu", ToUlong(childInfo.mAge)); |
1941 | 0 | OutputLine("Link Quality In: %u", childInfo.mLinkQualityIn); |
1942 | 0 | OutputLine("RSSI: %d", childInfo.mAverageRssi); |
1943 | 0 | OutputLine("Supervision Interval: %d", childInfo.mSupervisionInterval); |
1944 | |
|
1945 | 302 | exit: |
1946 | 302 | return error; |
1947 | 0 | } |
1948 | | |
1949 | | template <> otError Interpreter::Process<Cmd("childip")>(Arg aArgs[]) |
1950 | 21 | { |
1951 | 21 | otError error = OT_ERROR_NONE; |
1952 | | |
1953 | | /** |
1954 | | * @cli childip |
1955 | | * @code |
1956 | | * childip |
1957 | | * 3401: fdde:ad00:beef:0:3037:3e03:8c5f:bc0c |
1958 | | * Done |
1959 | | * @endcode |
1960 | | * @par |
1961 | | * Gets a list of IP addresses stored for MTD children. |
1962 | | * @sa otThreadGetChildNextIp6Address |
1963 | | */ |
1964 | 21 | if (aArgs[0].IsEmpty()) |
1965 | 18 | { |
1966 | 18 | uint16_t maxChildren = otThreadGetMaxAllowedChildren(GetInstancePtr()); |
1967 | | |
1968 | 198 | for (uint16_t childIndex = 0; childIndex < maxChildren; childIndex++) |
1969 | 180 | { |
1970 | 180 | otChildIp6AddressIterator iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; |
1971 | 180 | otIp6Address ip6Address; |
1972 | 180 | otChildInfo childInfo; |
1973 | | |
1974 | 180 | if ((otThreadGetChildInfoByIndex(GetInstancePtr(), childIndex, &childInfo) != OT_ERROR_NONE) || |
1975 | 180 | childInfo.mIsStateRestoring) |
1976 | 180 | { |
1977 | 180 | continue; |
1978 | 180 | } |
1979 | | |
1980 | 0 | iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; |
1981 | |
|
1982 | 0 | while (otThreadGetChildNextIp6Address(GetInstancePtr(), childIndex, &iterator, &ip6Address) == |
1983 | 0 | OT_ERROR_NONE) |
1984 | 0 | { |
1985 | 0 | OutputFormat("%04x: ", childInfo.mRloc16); |
1986 | 0 | OutputIp6AddressLine(ip6Address); |
1987 | 0 | } |
1988 | 0 | } |
1989 | 18 | } |
1990 | | /** |
1991 | | * @cli childip max |
1992 | | * @code |
1993 | | * childip max |
1994 | | * 4 |
1995 | | * Done |
1996 | | * @endcode |
1997 | | * @par api_copy |
1998 | | * #otThreadGetMaxChildIpAddresses |
1999 | | */ |
2000 | 3 | else if (aArgs[0] == "max") |
2001 | 2 | { |
2002 | 2 | #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
2003 | 2 | error = ProcessGet(aArgs + 1, otThreadGetMaxChildIpAddresses); |
2004 | | #else |
2005 | | /** |
2006 | | * @cli childip max (set) |
2007 | | * @code |
2008 | | * childip max 2 |
2009 | | * Done |
2010 | | * @endcode |
2011 | | * @cparam childip max @ca{count} |
2012 | | * @par api_copy |
2013 | | * #otThreadSetMaxChildIpAddresses |
2014 | | */ |
2015 | | error = ProcessGetSet(aArgs + 1, otThreadGetMaxChildIpAddresses, otThreadSetMaxChildIpAddresses); |
2016 | | #endif |
2017 | 2 | } |
2018 | 1 | else |
2019 | 1 | { |
2020 | 1 | error = OT_ERROR_INVALID_COMMAND; |
2021 | 1 | } |
2022 | | |
2023 | 21 | return error; |
2024 | 21 | } |
2025 | | |
2026 | | /** |
2027 | | * @cli childmax |
2028 | | * @code |
2029 | | * childmax |
2030 | | * 5 |
2031 | | * Done |
2032 | | * @endcode |
2033 | | * @par api_copy |
2034 | | * #otThreadGetMaxAllowedChildren |
2035 | | */ |
2036 | | template <> otError Interpreter::Process<Cmd("childmax")>(Arg aArgs[]) |
2037 | 27 | { |
2038 | | /** |
2039 | | * @cli childmax (set) |
2040 | | * @code |
2041 | | * childmax 2 |
2042 | | * Done |
2043 | | * @endcode |
2044 | | * @cparam childmax @ca{count} |
2045 | | * @par api_copy |
2046 | | * #otThreadSetMaxAllowedChildren |
2047 | | */ |
2048 | 27 | return ProcessGetSet(aArgs, otThreadGetMaxAllowedChildren, otThreadSetMaxAllowedChildren); |
2049 | 27 | } |
2050 | | #endif // OPENTHREAD_FTD |
2051 | | |
2052 | | template <> otError Interpreter::Process<Cmd("childsupervision")>(Arg aArgs[]) |
2053 | 52 | { |
2054 | 52 | otError error = OT_ERROR_INVALID_ARGS; |
2055 | | |
2056 | | /** |
2057 | | * @cli childsupervision checktimeout |
2058 | | * @code |
2059 | | * childsupervision checktimeout |
2060 | | * 30 |
2061 | | * Done |
2062 | | * @endcode |
2063 | | * @par api_copy |
2064 | | * #otChildSupervisionGetCheckTimeout |
2065 | | */ |
2066 | 52 | if (aArgs[0] == "checktimeout") |
2067 | 28 | { |
2068 | | /** @cli childsupervision checktimeout (set) |
2069 | | * @code |
2070 | | * childsupervision checktimeout 30 |
2071 | | * Done |
2072 | | * @endcode |
2073 | | * @cparam childsupervision checktimeout @ca{timeout-seconds} |
2074 | | * @par api_copy |
2075 | | * #otChildSupervisionSetCheckTimeout |
2076 | | */ |
2077 | 28 | error = ProcessGetSet(aArgs + 1, otChildSupervisionGetCheckTimeout, otChildSupervisionSetCheckTimeout); |
2078 | 28 | } |
2079 | | /** |
2080 | | * @cli childsupervision interval |
2081 | | * @code |
2082 | | * childsupervision interval |
2083 | | * 30 |
2084 | | * Done |
2085 | | * @endcode |
2086 | | * @par api_copy |
2087 | | * #otChildSupervisionGetInterval |
2088 | | */ |
2089 | 24 | else if (aArgs[0] == "interval") |
2090 | 20 | { |
2091 | | /** |
2092 | | * @cli childsupervision interval (set) |
2093 | | * @code |
2094 | | * childsupervision interval 30 |
2095 | | * Done |
2096 | | * @endcode |
2097 | | * @cparam childsupervision interval @ca{interval-seconds} |
2098 | | * @par api_copy |
2099 | | * #otChildSupervisionSetInterval |
2100 | | */ |
2101 | 20 | error = ProcessGetSet(aArgs + 1, otChildSupervisionGetInterval, otChildSupervisionSetInterval); |
2102 | 20 | } |
2103 | 4 | else if (aArgs[0] == "failcounter") |
2104 | 3 | { |
2105 | 3 | if (aArgs[1].IsEmpty()) |
2106 | 1 | { |
2107 | 1 | OutputLine("%u", otChildSupervisionGetCheckFailureCounter(GetInstancePtr())); |
2108 | 1 | error = OT_ERROR_NONE; |
2109 | 1 | } |
2110 | 2 | else if (aArgs[1] == "reset") |
2111 | 1 | { |
2112 | 1 | otChildSupervisionResetCheckFailureCounter(GetInstancePtr()); |
2113 | 1 | error = OT_ERROR_NONE; |
2114 | 1 | } |
2115 | 3 | } |
2116 | | |
2117 | 52 | return error; |
2118 | 52 | } |
2119 | | |
2120 | | /** @cli childtimeout |
2121 | | * @code |
2122 | | * childtimeout |
2123 | | * 300 |
2124 | | * Done |
2125 | | * @endcode |
2126 | | * @par api_copy |
2127 | | * #otThreadGetChildTimeout |
2128 | | */ |
2129 | | template <> otError Interpreter::Process<Cmd("childtimeout")>(Arg aArgs[]) |
2130 | 102 | { |
2131 | | /** @cli childtimeout (set) |
2132 | | * @code |
2133 | | * childtimeout 300 |
2134 | | * Done |
2135 | | * @endcode |
2136 | | * @cparam childtimeout @ca{timeout-seconds} |
2137 | | * @par api_copy |
2138 | | * #otThreadSetChildTimeout |
2139 | | */ |
2140 | 102 | return ProcessGetSet(aArgs, otThreadGetChildTimeout, otThreadSetChildTimeout); |
2141 | 102 | } |
2142 | | |
2143 | | #if OPENTHREAD_CONFIG_COAP_API_ENABLE |
2144 | 199 | template <> otError Interpreter::Process<Cmd("coap")>(Arg aArgs[]) { return mCoap.Process(aArgs); } |
2145 | | #endif |
2146 | | |
2147 | | #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE |
2148 | 110 | template <> otError Interpreter::Process<Cmd("coaps")>(Arg aArgs[]) { return mCoapSecure.Process(aArgs); } |
2149 | | #endif |
2150 | | |
2151 | | #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE |
2152 | | template <> otError Interpreter::Process<Cmd("coex")>(Arg aArgs[]) |
2153 | | { |
2154 | | otError error = OT_ERROR_NONE; |
2155 | | |
2156 | | if (ProcessEnableDisable(aArgs, otPlatRadioIsCoexEnabled, otPlatRadioSetCoexEnabled) == OT_ERROR_NONE) |
2157 | | { |
2158 | | } |
2159 | | else if (aArgs[0] == "metrics") |
2160 | | { |
2161 | | struct RadioCoexMetricName |
2162 | | { |
2163 | | const uint32_t otRadioCoexMetrics::*mValuePtr; |
2164 | | const char *mName; |
2165 | | }; |
2166 | | |
2167 | | static const RadioCoexMetricName kTxMetricNames[] = { |
2168 | | {&otRadioCoexMetrics::mNumTxRequest, "Request"}, |
2169 | | {&otRadioCoexMetrics::mNumTxGrantImmediate, "Grant Immediate"}, |
2170 | | {&otRadioCoexMetrics::mNumTxGrantWait, "Grant Wait"}, |
2171 | | {&otRadioCoexMetrics::mNumTxGrantWaitActivated, "Grant Wait Activated"}, |
2172 | | {&otRadioCoexMetrics::mNumTxGrantWaitTimeout, "Grant Wait Timeout"}, |
2173 | | {&otRadioCoexMetrics::mNumTxGrantDeactivatedDuringRequest, "Grant Deactivated During Request"}, |
2174 | | {&otRadioCoexMetrics::mNumTxDelayedGrant, "Delayed Grant"}, |
2175 | | {&otRadioCoexMetrics::mAvgTxRequestToGrantTime, "Average Request To Grant Time"}, |
2176 | | }; |
2177 | | |
2178 | | static const RadioCoexMetricName kRxMetricNames[] = { |
2179 | | {&otRadioCoexMetrics::mNumRxRequest, "Request"}, |
2180 | | {&otRadioCoexMetrics::mNumRxGrantImmediate, "Grant Immediate"}, |
2181 | | {&otRadioCoexMetrics::mNumRxGrantWait, "Grant Wait"}, |
2182 | | {&otRadioCoexMetrics::mNumRxGrantWaitActivated, "Grant Wait Activated"}, |
2183 | | {&otRadioCoexMetrics::mNumRxGrantWaitTimeout, "Grant Wait Timeout"}, |
2184 | | {&otRadioCoexMetrics::mNumRxGrantDeactivatedDuringRequest, "Grant Deactivated During Request"}, |
2185 | | {&otRadioCoexMetrics::mNumRxDelayedGrant, "Delayed Grant"}, |
2186 | | {&otRadioCoexMetrics::mAvgRxRequestToGrantTime, "Average Request To Grant Time"}, |
2187 | | {&otRadioCoexMetrics::mNumRxGrantNone, "Grant None"}, |
2188 | | }; |
2189 | | |
2190 | | otRadioCoexMetrics metrics; |
2191 | | |
2192 | | SuccessOrExit(error = otPlatRadioGetCoexMetrics(GetInstancePtr(), &metrics)); |
2193 | | |
2194 | | OutputLine("Stopped: %s", metrics.mStopped ? "true" : "false"); |
2195 | | OutputLine("Grant Glitch: %lu", ToUlong(metrics.mNumGrantGlitch)); |
2196 | | OutputLine("Transmit metrics"); |
2197 | | |
2198 | | for (const RadioCoexMetricName &metric : kTxMetricNames) |
2199 | | { |
2200 | | OutputLine(kIndentSize, "%s: %lu", metric.mName, ToUlong(metrics.*metric.mValuePtr)); |
2201 | | } |
2202 | | |
2203 | | OutputLine("Receive metrics"); |
2204 | | |
2205 | | for (const RadioCoexMetricName &metric : kRxMetricNames) |
2206 | | { |
2207 | | OutputLine(kIndentSize, "%s: %lu", metric.mName, ToUlong(metrics.*metric.mValuePtr)); |
2208 | | } |
2209 | | } |
2210 | | else |
2211 | | { |
2212 | | error = OT_ERROR_INVALID_ARGS; |
2213 | | } |
2214 | | |
2215 | | exit: |
2216 | | return error; |
2217 | | } |
2218 | | #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE |
2219 | | |
2220 | | #if OPENTHREAD_FTD |
2221 | | /** |
2222 | | * @cli contextreusedelay (get,set) |
2223 | | * @code |
2224 | | * contextreusedelay |
2225 | | * 11 |
2226 | | * Done |
2227 | | * @endcode |
2228 | | * @code |
2229 | | * contextreusedelay 11 |
2230 | | * Done |
2231 | | * @endcode |
2232 | | * @cparam contextreusedelay @ca{delay} |
2233 | | * Use the optional `delay` argument to set the `CONTEXT_ID_REUSE_DELAY`. |
2234 | | * @par |
2235 | | * Gets or sets the `CONTEXT_ID_REUSE_DELAY` value. |
2236 | | * @sa otThreadGetContextIdReuseDelay |
2237 | | * @sa otThreadSetContextIdReuseDelay |
2238 | | */ |
2239 | | template <> otError Interpreter::Process<Cmd("contextreusedelay")>(Arg aArgs[]) |
2240 | 4 | { |
2241 | 4 | return ProcessGetSet(aArgs, otThreadGetContextIdReuseDelay, otThreadSetContextIdReuseDelay); |
2242 | 4 | } |
2243 | | #endif |
2244 | | |
2245 | | #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE |
2246 | | void Interpreter::OutputBorderRouterCounters(void) |
2247 | 2 | { |
2248 | 2 | struct BrCounterName |
2249 | 2 | { |
2250 | 2 | const otPacketsAndBytes otBorderRoutingCounters::*mPacketsAndBytes; |
2251 | 2 | const char *mName; |
2252 | 2 | }; |
2253 | | |
2254 | 2 | static const BrCounterName kCounterNames[] = { |
2255 | 2 | {&otBorderRoutingCounters::mInboundUnicast, "Inbound Unicast"}, |
2256 | 2 | {&otBorderRoutingCounters::mInboundMulticast, "Inbound Multicast"}, |
2257 | 2 | {&otBorderRoutingCounters::mOutboundUnicast, "Outbound Unicast"}, |
2258 | 2 | {&otBorderRoutingCounters::mOutboundMulticast, "Outbound Multicast"}, |
2259 | 2 | }; |
2260 | | |
2261 | 2 | const otBorderRoutingCounters *brCounters = otIp6GetBorderRoutingCounters(GetInstancePtr()); |
2262 | 2 | Uint64StringBuffer uint64StringBuffer; |
2263 | | |
2264 | 2 | for (const BrCounterName &counter : kCounterNames) |
2265 | 8 | { |
2266 | 8 | OutputFormat("%s:", counter.mName); |
2267 | 8 | OutputFormat(" Packets %s", |
2268 | 8 | Uint64ToString((brCounters->*counter.mPacketsAndBytes).mPackets, uint64StringBuffer)); |
2269 | 8 | OutputLine(" Bytes %s", Uint64ToString((brCounters->*counter.mPacketsAndBytes).mBytes, uint64StringBuffer)); |
2270 | 8 | } |
2271 | | |
2272 | 2 | OutputLine("RA Rx: %lu", ToUlong(brCounters->mRaRx)); |
2273 | 2 | OutputLine("RA TxSuccess: %lu", ToUlong(brCounters->mRaTxSuccess)); |
2274 | 2 | OutputLine("RA TxFailed: %lu", ToUlong(brCounters->mRaTxFailure)); |
2275 | 2 | OutputLine("RS Rx: %lu", ToUlong(brCounters->mRsRx)); |
2276 | 2 | OutputLine("RS TxSuccess: %lu", ToUlong(brCounters->mRsTxSuccess)); |
2277 | 2 | OutputLine("RS TxFailed: %lu", ToUlong(brCounters->mRsTxFailure)); |
2278 | 2 | } |
2279 | | #endif // OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE |
2280 | | |
2281 | | template <> otError Interpreter::Process<Cmd("counters")>(Arg aArgs[]) |
2282 | 18 | { |
2283 | 18 | otError error = OT_ERROR_NONE; |
2284 | | |
2285 | | /** |
2286 | | * @cli counters |
2287 | | * @code |
2288 | | * counters |
2289 | | * ip |
2290 | | * mac |
2291 | | * mle |
2292 | | * Done |
2293 | | * @endcode |
2294 | | * @par |
2295 | | * Gets the supported counter names. |
2296 | | */ |
2297 | 18 | if (aArgs[0].IsEmpty()) |
2298 | 1 | { |
2299 | 1 | #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE |
2300 | 1 | OutputLine("br"); |
2301 | 1 | #endif |
2302 | 1 | OutputLine("ip"); |
2303 | 1 | OutputLine("mac"); |
2304 | 1 | OutputLine("mle"); |
2305 | 1 | } |
2306 | 17 | #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE |
2307 | | /** |
2308 | | * @cli counters br |
2309 | | * @code |
2310 | | * counters br |
2311 | | * Inbound Unicast: Packets 4 Bytes 320 |
2312 | | * Inbound Multicast: Packets 0 Bytes 0 |
2313 | | * Outbound Unicast: Packets 2 Bytes 160 |
2314 | | * Outbound Multicast: Packets 0 Bytes 0 |
2315 | | * RA Rx: 4 |
2316 | | * RA TxSuccess: 2 |
2317 | | * RA TxFailed: 0 |
2318 | | * RS Rx: 0 |
2319 | | * RS TxSuccess: 2 |
2320 | | * RS TxFailed: 0 |
2321 | | * Done |
2322 | | * @endcode |
2323 | | * @par api_copy |
2324 | | * #otIp6GetBorderRoutingCounters |
2325 | | */ |
2326 | 17 | else if (aArgs[0] == "br") |
2327 | 4 | { |
2328 | 4 | if (aArgs[1].IsEmpty()) |
2329 | 1 | { |
2330 | 1 | OutputBorderRouterCounters(); |
2331 | 1 | } |
2332 | | /** |
2333 | | * @cli counters br reset |
2334 | | * @code |
2335 | | * counters br reset |
2336 | | * Done |
2337 | | * @endcode |
2338 | | * @par api_copy |
2339 | | * #otIp6ResetBorderRoutingCounters |
2340 | | */ |
2341 | 3 | else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) |
2342 | 1 | { |
2343 | 1 | otIp6ResetBorderRoutingCounters(GetInstancePtr()); |
2344 | 1 | } |
2345 | 2 | else |
2346 | 2 | { |
2347 | 2 | error = OT_ERROR_INVALID_ARGS; |
2348 | 2 | } |
2349 | 4 | } |
2350 | 13 | #endif |
2351 | | /** |
2352 | | * @cli counters (mac) |
2353 | | * @code |
2354 | | * counters mac |
2355 | | * TxTotal: 10 |
2356 | | * TxUnicast: 3 |
2357 | | * TxBroadcast: 7 |
2358 | | * TxAckRequested: 3 |
2359 | | * TxAcked: 3 |
2360 | | * TxNoAckRequested: 7 |
2361 | | * TxData: 10 |
2362 | | * TxDataPoll: 0 |
2363 | | * TxBeacon: 0 |
2364 | | * TxBeaconRequest: 0 |
2365 | | * TxOther: 0 |
2366 | | * TxRetry: 0 |
2367 | | * TxErrCca: 0 |
2368 | | * TxErrBusyChannel: 0 |
2369 | | * RxTotal: 2 |
2370 | | * RxUnicast: 1 |
2371 | | * RxBroadcast: 1 |
2372 | | * RxData: 2 |
2373 | | * RxDataPoll: 0 |
2374 | | * RxBeacon: 0 |
2375 | | * RxBeaconRequest: 0 |
2376 | | * RxOther: 0 |
2377 | | * RxAddressFiltered: 0 |
2378 | | * RxDestAddrFiltered: 0 |
2379 | | * RxDuplicated: 0 |
2380 | | * RxErrNoFrame: 0 |
2381 | | * RxErrNoUnknownNeighbor: 0 |
2382 | | * RxErrInvalidSrcAddr: 0 |
2383 | | * RxErrSec: 0 |
2384 | | * RxErrFcs: 0 |
2385 | | * RxErrOther: 0 |
2386 | | * Done |
2387 | | * @endcode |
2388 | | * @cparam counters @ca{mac} |
2389 | | * @par api_copy |
2390 | | * #otLinkGetCounters |
2391 | | */ |
2392 | 13 | else if (aArgs[0] == "mac") |
2393 | 4 | { |
2394 | 4 | if (aArgs[1].IsEmpty()) |
2395 | 1 | { |
2396 | 1 | struct MacCounterName |
2397 | 1 | { |
2398 | 1 | const uint32_t otMacCounters::*mValuePtr; |
2399 | 1 | const char *mName; |
2400 | 1 | }; |
2401 | | |
2402 | 1 | static const MacCounterName kTxCounterNames[] = { |
2403 | 1 | {&otMacCounters::mTxUnicast, "TxUnicast"}, |
2404 | 1 | {&otMacCounters::mTxBroadcast, "TxBroadcast"}, |
2405 | 1 | {&otMacCounters::mTxAckRequested, "TxAckRequested"}, |
2406 | 1 | {&otMacCounters::mTxAcked, "TxAcked"}, |
2407 | 1 | {&otMacCounters::mTxNoAckRequested, "TxNoAckRequested"}, |
2408 | 1 | {&otMacCounters::mTxData, "TxData"}, |
2409 | 1 | {&otMacCounters::mTxDataPoll, "TxDataPoll"}, |
2410 | 1 | {&otMacCounters::mTxBeacon, "TxBeacon"}, |
2411 | 1 | {&otMacCounters::mTxBeaconRequest, "TxBeaconRequest"}, |
2412 | 1 | {&otMacCounters::mTxOther, "TxOther"}, |
2413 | 1 | {&otMacCounters::mTxRetry, "TxRetry"}, |
2414 | 1 | {&otMacCounters::mTxErrCca, "TxErrCca"}, |
2415 | 1 | {&otMacCounters::mTxErrBusyChannel, "TxErrBusyChannel"}, |
2416 | 1 | {&otMacCounters::mTxErrAbort, "TxErrAbort"}, |
2417 | 1 | {&otMacCounters::mTxDirectMaxRetryExpiry, "TxDirectMaxRetryExpiry"}, |
2418 | 1 | {&otMacCounters::mTxIndirectMaxRetryExpiry, "TxIndirectMaxRetryExpiry"}, |
2419 | 1 | }; |
2420 | | |
2421 | 1 | static const MacCounterName kRxCounterNames[] = { |
2422 | 1 | {&otMacCounters::mRxUnicast, "RxUnicast"}, |
2423 | 1 | {&otMacCounters::mRxBroadcast, "RxBroadcast"}, |
2424 | 1 | {&otMacCounters::mRxData, "RxData"}, |
2425 | 1 | {&otMacCounters::mRxDataPoll, "RxDataPoll"}, |
2426 | 1 | {&otMacCounters::mRxBeacon, "RxBeacon"}, |
2427 | 1 | {&otMacCounters::mRxBeaconRequest, "RxBeaconRequest"}, |
2428 | 1 | {&otMacCounters::mRxOther, "RxOther"}, |
2429 | 1 | {&otMacCounters::mRxAddressFiltered, "RxAddressFiltered"}, |
2430 | 1 | {&otMacCounters::mRxDestAddrFiltered, "RxDestAddrFiltered"}, |
2431 | 1 | {&otMacCounters::mRxDuplicated, "RxDuplicated"}, |
2432 | 1 | {&otMacCounters::mRxErrNoFrame, "RxErrNoFrame"}, |
2433 | 1 | {&otMacCounters::mRxErrUnknownNeighbor, "RxErrNoUnknownNeighbor"}, |
2434 | 1 | {&otMacCounters::mRxErrInvalidSrcAddr, "RxErrInvalidSrcAddr"}, |
2435 | 1 | {&otMacCounters::mRxErrSec, "RxErrSec"}, |
2436 | 1 | {&otMacCounters::mRxErrFcs, "RxErrFcs"}, |
2437 | 1 | {&otMacCounters::mRxErrOther, "RxErrOther"}, |
2438 | 1 | }; |
2439 | | |
2440 | 1 | const otMacCounters *macCounters = otLinkGetCounters(GetInstancePtr()); |
2441 | | |
2442 | 1 | OutputLine("TxTotal: %lu", ToUlong(macCounters->mTxTotal)); |
2443 | | |
2444 | 1 | for (const MacCounterName &counter : kTxCounterNames) |
2445 | 16 | { |
2446 | 16 | OutputLine(kIndentSize, "%s: %lu", counter.mName, ToUlong(macCounters->*counter.mValuePtr)); |
2447 | 16 | } |
2448 | | |
2449 | 1 | OutputLine("RxTotal: %lu", ToUlong(macCounters->mRxTotal)); |
2450 | | |
2451 | 1 | for (const MacCounterName &counter : kRxCounterNames) |
2452 | 16 | { |
2453 | 16 | OutputLine(kIndentSize, "%s: %lu", counter.mName, ToUlong(macCounters->*counter.mValuePtr)); |
2454 | 16 | } |
2455 | 1 | } |
2456 | | /** |
2457 | | * @cli counters mac reset |
2458 | | * @code |
2459 | | * counters mac reset |
2460 | | * Done |
2461 | | * @endcode |
2462 | | * @cparam counters @ca{mac} reset |
2463 | | * @par api_copy |
2464 | | * #otLinkResetCounters |
2465 | | */ |
2466 | 3 | else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) |
2467 | 1 | { |
2468 | 1 | otLinkResetCounters(GetInstancePtr()); |
2469 | 1 | } |
2470 | 2 | else |
2471 | 2 | { |
2472 | 2 | error = OT_ERROR_INVALID_ARGS; |
2473 | 2 | } |
2474 | 4 | } |
2475 | | /** |
2476 | | * @cli counters (mle) |
2477 | | * @code |
2478 | | * counters mle |
2479 | | * Role Disabled: 0 |
2480 | | * Role Detached: 1 |
2481 | | * Role Child: 0 |
2482 | | * Role Router: 0 |
2483 | | * Role Leader: 1 |
2484 | | * Attach Attempts: 1 |
2485 | | * Partition Id Changes: 1 |
2486 | | * Better Partition Attach Attempts: 0 |
2487 | | * Better Parent Attach Attempts: 0 |
2488 | | * Parent Changes: 0 |
2489 | | * Done |
2490 | | * @endcode |
2491 | | * @cparam counters @ca{mle} |
2492 | | * @par api_copy |
2493 | | * #otThreadGetMleCounters |
2494 | | */ |
2495 | 9 | else if (aArgs[0] == "mle") |
2496 | 4 | { |
2497 | 4 | if (aArgs[1].IsEmpty()) |
2498 | 1 | { |
2499 | 1 | struct MleCounterName |
2500 | 1 | { |
2501 | 1 | const uint16_t otMleCounters::*mValuePtr; |
2502 | 1 | const char *mName; |
2503 | 1 | }; |
2504 | | |
2505 | 1 | struct MleTimeCounterName |
2506 | 1 | { |
2507 | 1 | const uint64_t otMleCounters::*mValuePtr; |
2508 | 1 | const char *mName; |
2509 | 1 | }; |
2510 | | |
2511 | 1 | static const MleCounterName kCounterNames[] = { |
2512 | 1 | {&otMleCounters::mDisabledRole, "Role Disabled"}, |
2513 | 1 | {&otMleCounters::mDetachedRole, "Role Detached"}, |
2514 | 1 | {&otMleCounters::mChildRole, "Role Child"}, |
2515 | 1 | {&otMleCounters::mRouterRole, "Role Router"}, |
2516 | 1 | {&otMleCounters::mLeaderRole, "Role Leader"}, |
2517 | 1 | {&otMleCounters::mAttachAttempts, "Attach Attempts"}, |
2518 | 1 | {&otMleCounters::mPartitionIdChanges, "Partition Id Changes"}, |
2519 | 1 | {&otMleCounters::mBetterPartitionAttachAttempts, "Better Partition Attach Attempts"}, |
2520 | 1 | {&otMleCounters::mBetterParentAttachAttempts, "Better Parent Attach Attempts"}, |
2521 | 1 | {&otMleCounters::mParentChanges, "Parent Changes"}, |
2522 | 1 | }; |
2523 | | |
2524 | 1 | static const MleTimeCounterName kTimeCounterNames[] = { |
2525 | 1 | {&otMleCounters::mDisabledTime, "Disabled"}, {&otMleCounters::mDetachedTime, "Detached"}, |
2526 | 1 | {&otMleCounters::mChildTime, "Child"}, {&otMleCounters::mRouterTime, "Router"}, |
2527 | 1 | {&otMleCounters::mLeaderTime, "Leader"}, |
2528 | 1 | }; |
2529 | | |
2530 | 1 | const otMleCounters *mleCounters = otThreadGetMleCounters(GetInstancePtr()); |
2531 | | |
2532 | 1 | for (const MleCounterName &counter : kCounterNames) |
2533 | 10 | { |
2534 | 10 | OutputLine("%s: %u", counter.mName, mleCounters->*counter.mValuePtr); |
2535 | 10 | } |
2536 | | |
2537 | 1 | for (const MleTimeCounterName &counter : kTimeCounterNames) |
2538 | 5 | { |
2539 | 5 | OutputFormat("Time %s Milli: ", counter.mName); |
2540 | 5 | OutputUint64Line(mleCounters->*counter.mValuePtr); |
2541 | 5 | } |
2542 | | |
2543 | 1 | OutputFormat("Time Tracked Milli: "); |
2544 | 1 | OutputUint64Line(mleCounters->mTrackedTime); |
2545 | 1 | } |
2546 | | /** |
2547 | | * @cli counters mle reset |
2548 | | * @code |
2549 | | * counters mle reset |
2550 | | * Done |
2551 | | * @endcode |
2552 | | * @cparam counters @ca{mle} reset |
2553 | | * @par api_copy |
2554 | | * #otThreadResetMleCounters |
2555 | | */ |
2556 | 3 | else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) |
2557 | 1 | { |
2558 | 1 | otThreadResetMleCounters(GetInstancePtr()); |
2559 | 1 | } |
2560 | 2 | else |
2561 | 2 | { |
2562 | 2 | error = OT_ERROR_INVALID_ARGS; |
2563 | 2 | } |
2564 | 4 | } |
2565 | | /** |
2566 | | * @cli counters ip |
2567 | | * @code |
2568 | | * counters ip |
2569 | | * TxSuccess: 10 |
2570 | | * TxFailed: 0 |
2571 | | * RxSuccess: 5 |
2572 | | * RxFailed: 0 |
2573 | | * Done |
2574 | | * @endcode |
2575 | | * @cparam counters @ca{ip} |
2576 | | * @par api_copy |
2577 | | * #otThreadGetIp6Counters |
2578 | | */ |
2579 | 5 | else if (aArgs[0] == "ip") |
2580 | 4 | { |
2581 | 4 | if (aArgs[1].IsEmpty()) |
2582 | 1 | { |
2583 | 1 | struct IpCounterName |
2584 | 1 | { |
2585 | 1 | const uint32_t otIpCounters::*mValuePtr; |
2586 | 1 | const char *mName; |
2587 | 1 | }; |
2588 | | |
2589 | 1 | static const IpCounterName kCounterNames[] = { |
2590 | 1 | {&otIpCounters::mTxSuccess, "TxSuccess"}, |
2591 | 1 | {&otIpCounters::mTxFailure, "TxFailed"}, |
2592 | 1 | {&otIpCounters::mRxSuccess, "RxSuccess"}, |
2593 | 1 | {&otIpCounters::mRxFailure, "RxFailed"}, |
2594 | 1 | }; |
2595 | | |
2596 | 1 | const otIpCounters *ipCounters = otThreadGetIp6Counters(GetInstancePtr()); |
2597 | | |
2598 | 1 | for (const IpCounterName &counter : kCounterNames) |
2599 | 4 | { |
2600 | 4 | OutputLine("%s: %lu", counter.mName, ToUlong(ipCounters->*counter.mValuePtr)); |
2601 | 4 | } |
2602 | 1 | } |
2603 | | /** |
2604 | | * @cli counters ip reset |
2605 | | * @code |
2606 | | * counters ip reset |
2607 | | * Done |
2608 | | * @endcode |
2609 | | * @cparam counters @ca{ip} reset |
2610 | | * @par api_copy |
2611 | | * #otThreadResetIp6Counters |
2612 | | */ |
2613 | 3 | else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) |
2614 | 1 | { |
2615 | 1 | otThreadResetIp6Counters(GetInstancePtr()); |
2616 | 1 | } |
2617 | 2 | else |
2618 | 2 | { |
2619 | 2 | error = OT_ERROR_INVALID_ARGS; |
2620 | 2 | } |
2621 | 4 | } |
2622 | 1 | else |
2623 | 1 | { |
2624 | 1 | error = OT_ERROR_INVALID_ARGS; |
2625 | 1 | } |
2626 | | |
2627 | 18 | return error; |
2628 | 18 | } |
2629 | | |
2630 | | #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
2631 | | template <> otError Interpreter::Process<Cmd("csl")>(Arg aArgs[]) |
2632 | | { |
2633 | | otError error = OT_ERROR_NONE; |
2634 | | |
2635 | | /** |
2636 | | * @cli csl |
2637 | | * @code |
2638 | | * csl |
2639 | | * Channel: 11 |
2640 | | * Period: 160000us |
2641 | | * Timeout: 1000s |
2642 | | * Done |
2643 | | * @endcode |
2644 | | * @par |
2645 | | * Gets the CSL configuration. |
2646 | | * @sa otLinkGetCslChannel |
2647 | | * @sa otLinkGetCslPeriod |
2648 | | * @sa otLinkGetCslPeriod |
2649 | | * @sa otLinkGetCslTimeout |
2650 | | */ |
2651 | | if (aArgs[0].IsEmpty()) |
2652 | | { |
2653 | | OutputLine("channel: %u", otLinkGetCslChannel(GetInstancePtr())); |
2654 | | OutputLine("period: %luus", ToUlong(otLinkGetCslPeriod(GetInstancePtr()))); |
2655 | | OutputLine("timeout: %lus", ToUlong(otLinkGetCslTimeout(GetInstancePtr()))); |
2656 | | } |
2657 | | /** |
2658 | | * @cli csl channel |
2659 | | * @code |
2660 | | * csl channel 20 |
2661 | | * Done |
2662 | | * @endcode |
2663 | | * @cparam csl channel @ca{channel} |
2664 | | * @par api_copy |
2665 | | * #otLinkSetCslChannel |
2666 | | */ |
2667 | | else if (aArgs[0] == "channel") |
2668 | | { |
2669 | | error = ProcessSet(aArgs + 1, otLinkSetCslChannel); |
2670 | | } |
2671 | | /** |
2672 | | * @cli csl period |
2673 | | * @code |
2674 | | * csl period 3000000 |
2675 | | * Done |
2676 | | * @endcode |
2677 | | * @cparam csl period @ca{period} |
2678 | | * @par api_copy |
2679 | | * #otLinkSetCslPeriod |
2680 | | */ |
2681 | | else if (aArgs[0] == "period") |
2682 | | { |
2683 | | error = ProcessSet(aArgs + 1, otLinkSetCslPeriod); |
2684 | | } |
2685 | | /** |
2686 | | * @cli csl timeout |
2687 | | * @code |
2688 | | * cls timeout 10 |
2689 | | * Done |
2690 | | * @endcode |
2691 | | * @cparam csl timeout @ca{timeout} |
2692 | | * @par api_copy |
2693 | | * #otLinkSetCslTimeout |
2694 | | */ |
2695 | | else if (aArgs[0] == "timeout") |
2696 | | { |
2697 | | error = ProcessSet(aArgs + 1, otLinkSetCslTimeout); |
2698 | | } |
2699 | | else |
2700 | | { |
2701 | | error = OT_ERROR_INVALID_ARGS; |
2702 | | } |
2703 | | |
2704 | | return error; |
2705 | | } |
2706 | | #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
2707 | | |
2708 | | #if OPENTHREAD_FTD |
2709 | | template <> otError Interpreter::Process<Cmd("delaytimermin")>(Arg aArgs[]) |
2710 | 57 | { |
2711 | 57 | otError error = OT_ERROR_NONE; |
2712 | | |
2713 | | /** |
2714 | | * @cli delaytimermin |
2715 | | * @code |
2716 | | * delaytimermin |
2717 | | * 30 |
2718 | | * Done |
2719 | | * @endcode |
2720 | | * @par |
2721 | | * Get the minimal delay timer (in seconds). |
2722 | | * @sa otDatasetGetDelayTimerMinimal |
2723 | | */ |
2724 | 57 | if (aArgs[0].IsEmpty()) |
2725 | 1 | { |
2726 | 1 | OutputLine("%lu", ToUlong((otDatasetGetDelayTimerMinimal(GetInstancePtr()) / 1000))); |
2727 | 1 | } |
2728 | | /** |
2729 | | * @cli delaytimermin (set) |
2730 | | * @code |
2731 | | * delaytimermin 60 |
2732 | | * Done |
2733 | | * @endcode |
2734 | | * @cparam delaytimermin @ca{delaytimermin} |
2735 | | * @par |
2736 | | * Sets the minimal delay timer (in seconds). |
2737 | | * @sa otDatasetSetDelayTimerMinimal |
2738 | | */ |
2739 | 56 | else if (aArgs[1].IsEmpty()) |
2740 | 55 | { |
2741 | 55 | uint32_t delay; |
2742 | 55 | SuccessOrExit(error = aArgs[0].ParseAsUint32(delay)); |
2743 | 54 | SuccessOrExit(error = otDatasetSetDelayTimerMinimal(GetInstancePtr(), static_cast<uint32_t>(delay * 1000))); |
2744 | 54 | } |
2745 | 1 | else |
2746 | 1 | { |
2747 | 1 | error = OT_ERROR_INVALID_ARGS; |
2748 | 1 | } |
2749 | | |
2750 | 57 | exit: |
2751 | 57 | return error; |
2752 | 57 | } |
2753 | | #endif |
2754 | | |
2755 | | /** |
2756 | | * @cli detach |
2757 | | * @code |
2758 | | * detach |
2759 | | * Finished detaching |
2760 | | * Done |
2761 | | * @endcode |
2762 | | * @par |
2763 | | * Start the graceful detach process by first notifying other nodes (sending Address Release if acting as a router, or |
2764 | | * setting Child Timeout value to zero on parent if acting as a child) and then stopping Thread protocol operation. |
2765 | | * @sa otThreadDetachGracefully |
2766 | | */ |
2767 | | template <> otError Interpreter::Process<Cmd("detach")>(Arg aArgs[]) |
2768 | 10 | { |
2769 | 10 | otError error = OT_ERROR_NONE; |
2770 | | |
2771 | | /** |
2772 | | * @cli detach async |
2773 | | * @code |
2774 | | * detach async |
2775 | | * Done |
2776 | | * @endcode |
2777 | | * @par |
2778 | | * Start the graceful detach process similar to the `detach` command without blocking and waiting for the callback |
2779 | | * indicating that detach is finished. |
2780 | | * @csa{detach} |
2781 | | * @sa otThreadDetachGracefully |
2782 | | */ |
2783 | 10 | if (aArgs[0] == "async") |
2784 | 1 | { |
2785 | 1 | SuccessOrExit(error = otThreadDetachGracefully(GetInstancePtr(), nullptr, nullptr)); |
2786 | 1 | } |
2787 | 9 | else |
2788 | 9 | { |
2789 | 9 | SuccessOrExit(error = otThreadDetachGracefully(GetInstancePtr(), HandleDetachGracefullyResult, this)); |
2790 | 9 | error = OT_ERROR_PENDING; |
2791 | 9 | } |
2792 | | |
2793 | 10 | exit: |
2794 | 10 | return error; |
2795 | 10 | } |
2796 | | |
2797 | | void Interpreter::HandleDetachGracefullyResult(void *aContext) |
2798 | 9 | { |
2799 | 9 | static_cast<Interpreter *>(aContext)->HandleDetachGracefullyResult(); |
2800 | 9 | } |
2801 | | |
2802 | | void Interpreter::HandleDetachGracefullyResult(void) |
2803 | 9 | { |
2804 | 9 | OutputLine("Finished detaching"); |
2805 | 9 | OutputResult(OT_ERROR_NONE); |
2806 | 9 | } |
2807 | | |
2808 | | /** |
2809 | | * @cli discover |
2810 | | * @code |
2811 | | * discover |
2812 | | * | J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI | |
2813 | | * +---+------------------+------------------+------+------------------+----+-----+-----+ |
2814 | | * | 0 | OpenThread | dead00beef00cafe | ffff | f1d92a82c8d8fe43 | 11 | -20 | 0 | |
2815 | | * Done |
2816 | | * @endcode |
2817 | | * @cparam discover [@ca{channel}] |
2818 | | * `channel`: The channel to discover on. If no channel is provided, the discovery will cover all |
2819 | | * valid channels. |
2820 | | * @par |
2821 | | * Perform an MLE Discovery operation. |
2822 | | * @sa otThreadDiscover |
2823 | | */ |
2824 | | template <> otError Interpreter::Process<Cmd("discover")>(Arg aArgs[]) |
2825 | 21 | { |
2826 | 21 | otError error = OT_ERROR_NONE; |
2827 | 21 | uint32_t scanChannels = 0; |
2828 | | |
2829 | 21 | #if OPENTHREAD_FTD |
2830 | | /** |
2831 | | * @cli discover reqcallback (enable,disable) |
2832 | | * @code |
2833 | | * discover reqcallback enable |
2834 | | * Done |
2835 | | * @endcode |
2836 | | * @cparam discover reqcallback @ca{enable|disable} |
2837 | | * @par api_copy |
2838 | | * #otThreadSetDiscoveryRequestCallback |
2839 | | */ |
2840 | 21 | if (aArgs[0] == "reqcallback") |
2841 | 3 | { |
2842 | 3 | bool enable; |
2843 | 3 | otThreadDiscoveryRequestCallback callback = nullptr; |
2844 | 3 | void *context = nullptr; |
2845 | | |
2846 | 3 | SuccessOrExit(error = ParseEnableOrDisable(aArgs[1], enable)); |
2847 | | |
2848 | 2 | if (enable) |
2849 | 1 | { |
2850 | 1 | callback = &Interpreter::HandleDiscoveryRequest; |
2851 | 1 | context = this; |
2852 | 1 | } |
2853 | | |
2854 | 2 | otThreadSetDiscoveryRequestCallback(GetInstancePtr(), callback, context); |
2855 | 2 | ExitNow(); |
2856 | 2 | } |
2857 | 18 | #endif // OPENTHREAD_FTD |
2858 | | |
2859 | 18 | if (!aArgs[0].IsEmpty()) |
2860 | 17 | { |
2861 | 17 | uint8_t channel; |
2862 | | |
2863 | 17 | SuccessOrExit(error = aArgs[0].ParseAsUint8(channel)); |
2864 | 16 | VerifyOrExit(channel < BitSizeOf(scanChannels), error = OT_ERROR_INVALID_ARGS); |
2865 | 13 | scanChannels = 1 << channel; |
2866 | 13 | } |
2867 | | |
2868 | 14 | SuccessOrExit(error = otThreadDiscover(GetInstancePtr(), scanChannels, OT_PANID_BROADCAST, false, false, |
2869 | 14 | &Interpreter::HandleActiveScanResult, this)); |
2870 | | |
2871 | 14 | static const char *const kScanTableTitles[] = { |
2872 | 14 | "Network Name", "Extended PAN", "PAN", "MAC Address", "Ch", "dBm", "LQI", |
2873 | 14 | }; |
2874 | | |
2875 | 14 | static const uint8_t kScanTableColumnWidths[] = { |
2876 | 14 | 18, 18, 6, 18, 4, 5, 5, |
2877 | 14 | }; |
2878 | | |
2879 | 14 | OutputTableHeader(kScanTableTitles, kScanTableColumnWidths); |
2880 | | |
2881 | 14 | error = OT_ERROR_PENDING; |
2882 | | |
2883 | 21 | exit: |
2884 | 21 | return error; |
2885 | 14 | } |
2886 | | |
2887 | | #if OPENTHREAD_CLI_DNS_ENABLE |
2888 | 421 | template <> otError Interpreter::Process<Cmd("dns")>(Arg aArgs[]) { return mDns.Process(aArgs); } |
2889 | | #endif |
2890 | | |
2891 | | #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE |
2892 | | template <> otError Interpreter::Process<Cmd("mdns")>(Arg aArgs[]) { return mMdns.Process(aArgs); } |
2893 | | #endif |
2894 | | |
2895 | | #if OPENTHREAD_FTD |
2896 | | void Interpreter::OutputEidCacheEntry(const otCacheEntryInfo &aEntry) |
2897 | 0 | { |
2898 | 0 | static const char *const kStateStrings[] = { |
2899 | 0 | "cache", // (0) OT_CACHE_ENTRY_STATE_CACHED |
2900 | 0 | "snoop", // (1) OT_CACHE_ENTRY_STATE_SNOOPED |
2901 | 0 | "query", // (2) OT_CACHE_ENTRY_STATE_QUERY |
2902 | 0 | "retry", // (3) OT_CACHE_ENTRY_STATE_RETRY_QUERY |
2903 | 0 | }; |
2904 | |
|
2905 | 0 | static_assert(0 == OT_CACHE_ENTRY_STATE_CACHED, "OT_CACHE_ENTRY_STATE_CACHED value is incorrect"); |
2906 | 0 | static_assert(1 == OT_CACHE_ENTRY_STATE_SNOOPED, "OT_CACHE_ENTRY_STATE_SNOOPED value is incorrect"); |
2907 | 0 | static_assert(2 == OT_CACHE_ENTRY_STATE_QUERY, "OT_CACHE_ENTRY_STATE_QUERY value is incorrect"); |
2908 | 0 | static_assert(3 == OT_CACHE_ENTRY_STATE_RETRY_QUERY, "OT_CACHE_ENTRY_STATE_RETRY_QUERY value is incorrect"); |
2909 | |
|
2910 | 0 | OutputIp6Address(aEntry.mTarget); |
2911 | 0 | OutputFormat(" %04x", aEntry.mRloc16); |
2912 | 0 | OutputFormat(" %s", Stringify(aEntry.mState, kStateStrings)); |
2913 | 0 | OutputFormat(" canEvict=%d", aEntry.mCanEvict); |
2914 | |
|
2915 | 0 | if (aEntry.mState == OT_CACHE_ENTRY_STATE_CACHED) |
2916 | 0 | { |
2917 | 0 | if (aEntry.mValidLastTrans) |
2918 | 0 | { |
2919 | 0 | OutputFormat(" transTime=%lu eid=", ToUlong(aEntry.mLastTransTime)); |
2920 | 0 | OutputIp6Address(aEntry.mMeshLocalEid); |
2921 | 0 | } |
2922 | 0 | } |
2923 | 0 | else |
2924 | 0 | { |
2925 | 0 | OutputFormat(" timeout=%u", aEntry.mTimeout); |
2926 | 0 | } |
2927 | |
|
2928 | 0 | if (aEntry.mState == OT_CACHE_ENTRY_STATE_RETRY_QUERY) |
2929 | 0 | { |
2930 | 0 | OutputFormat(" retryDelay=%u rampDown=%d", aEntry.mRetryDelay, aEntry.mRampDown); |
2931 | 0 | } |
2932 | |
|
2933 | 0 | OutputNewLine(); |
2934 | 0 | } |
2935 | | |
2936 | | /** |
2937 | | * @cli eidcache |
2938 | | * @code |
2939 | | * eidcache |
2940 | | * fd49:caf4:a29f:dc0e:97fc:69dd:3c16:df7d 2000 cache canEvict=1 transTime=0 eid=fd49:caf4:a29f:dc0e:97fc:69dd:3c16:df7d |
2941 | | * fd49:caf4:a29f:dc0e:97fc:69dd:3c16:df7f fffe retry canEvict=1 timeout=10 retryDelay=30 |
2942 | | * Done |
2943 | | * @endcode |
2944 | | * @par |
2945 | | * Returns the EID-to-RLOC cache entries. |
2946 | | * @sa otThreadGetNextCacheEntry |
2947 | | */ |
2948 | | template <> otError Interpreter::Process<Cmd("eidcache")>(Arg aArgs[]) |
2949 | 17 | { |
2950 | 17 | OT_UNUSED_VARIABLE(aArgs); |
2951 | | |
2952 | 17 | otCacheEntryIterator iterator; |
2953 | 17 | otCacheEntryInfo entry; |
2954 | | |
2955 | 17 | ClearAllBytes(iterator); |
2956 | | |
2957 | 17 | while (true) |
2958 | 17 | { |
2959 | 17 | SuccessOrExit(otThreadGetNextCacheEntry(GetInstancePtr(), &entry, &iterator)); |
2960 | 0 | OutputEidCacheEntry(entry); |
2961 | 0 | } |
2962 | | |
2963 | 17 | exit: |
2964 | 17 | return OT_ERROR_NONE; |
2965 | 17 | } |
2966 | | #endif |
2967 | | |
2968 | | /** |
2969 | | * @cli eui64 |
2970 | | * @code |
2971 | | * eui64 |
2972 | | * 0615aae900124b00 |
2973 | | * Done |
2974 | | * @endcode |
2975 | | * @par api_copy |
2976 | | * #otPlatRadioGetIeeeEui64 |
2977 | | */ |
2978 | | template <> otError Interpreter::Process<Cmd("eui64")>(Arg aArgs[]) |
2979 | 2 | { |
2980 | 2 | OT_UNUSED_VARIABLE(aArgs); |
2981 | | |
2982 | 2 | otError error = OT_ERROR_NONE; |
2983 | 2 | otExtAddress extAddress; |
2984 | | |
2985 | 2 | VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
2986 | | |
2987 | 1 | otLinkGetFactoryAssignedIeeeEui64(GetInstancePtr(), &extAddress); |
2988 | 1 | OutputExtAddressLine(extAddress); |
2989 | | |
2990 | 2 | exit: |
2991 | 2 | return error; |
2992 | 1 | } |
2993 | | |
2994 | | template <> otError Interpreter::Process<Cmd("extaddr")>(Arg aArgs[]) |
2995 | 32 | { |
2996 | 32 | otError error = OT_ERROR_NONE; |
2997 | | |
2998 | | /** |
2999 | | * @cli extaddr |
3000 | | * @code |
3001 | | * extaddr |
3002 | | * dead00beef00cafe |
3003 | | * Done |
3004 | | * @endcode |
3005 | | * @par api_copy |
3006 | | * #otLinkGetExtendedAddress |
3007 | | */ |
3008 | 32 | if (aArgs[0].IsEmpty()) |
3009 | 17 | { |
3010 | 17 | OutputExtAddressLine(*otLinkGetExtendedAddress(GetInstancePtr())); |
3011 | 17 | } |
3012 | | /** |
3013 | | * @cli extaddr (set) |
3014 | | * @code |
3015 | | * extaddr dead00beef00cafe |
3016 | | * dead00beef00cafe |
3017 | | * Done |
3018 | | * @endcode |
3019 | | * @cparam extaddr @ca{extaddr} |
3020 | | * @par api_copy |
3021 | | * #otLinkSetExtendedAddress |
3022 | | */ |
3023 | 15 | else |
3024 | 15 | { |
3025 | 15 | otExtAddress extAddress; |
3026 | | |
3027 | 15 | SuccessOrExit(error = aArgs[0].ParseAsHexString(extAddress.m8)); |
3028 | 2 | error = otLinkSetExtendedAddress(GetInstancePtr(), &extAddress); |
3029 | 2 | } |
3030 | | |
3031 | 32 | exit: |
3032 | 32 | return error; |
3033 | 32 | } |
3034 | | |
3035 | | template <> otError Interpreter::Process<Cmd("log")>(Arg aArgs[]) |
3036 | 3 | { |
3037 | 3 | otError error = OT_ERROR_NONE; |
3038 | | |
3039 | | /** |
3040 | | * @cli log level |
3041 | | * @code |
3042 | | * log level |
3043 | | * 1 |
3044 | | * Done |
3045 | | * @endcode |
3046 | | * @par |
3047 | | * Get the log level. |
3048 | | * @sa otLoggingGetLevel |
3049 | | */ |
3050 | 3 | if (aArgs[0] == "level") |
3051 | 2 | { |
3052 | 2 | if (aArgs[1].IsEmpty()) |
3053 | 1 | { |
3054 | 1 | OutputLine("%d", otLoggingGetLevel()); |
3055 | 1 | } |
3056 | 1 | else |
3057 | 1 | { |
3058 | | #if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE |
3059 | | uint8_t level; |
3060 | | |
3061 | | /** |
3062 | | * @cli log level (set) |
3063 | | * @code |
3064 | | * log level 4 |
3065 | | * Done |
3066 | | * @endcode |
3067 | | * @par api_copy |
3068 | | * #otLoggingSetLevel |
3069 | | * @cparam log level @ca{level} |
3070 | | */ |
3071 | | VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
3072 | | SuccessOrExit(error = aArgs[1].ParseAsUint8(level)); |
3073 | | error = otLoggingSetLevel(static_cast<otLogLevel>(level)); |
3074 | | #else |
3075 | 1 | error = OT_ERROR_INVALID_ARGS; |
3076 | 1 | #endif |
3077 | 1 | } |
3078 | 2 | } |
3079 | | #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART) && OPENTHREAD_POSIX |
3080 | | /** |
3081 | | * @cli log filename |
3082 | | * @par |
3083 | | * Specifies filename to capture `otPlatLog()` messages, useful when debugging |
3084 | | * automated test scripts on Linux when logging disrupts the automated test scripts. |
3085 | | * @par |
3086 | | * Requires `OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART` |
3087 | | * and `OPENTHREAD_POSIX`. |
3088 | | * @par api_copy |
3089 | | * #otPlatDebugUart_logfile |
3090 | | * @cparam log filename @ca{filename} |
3091 | | */ |
3092 | | else if (aArgs[0] == "filename") |
3093 | | { |
3094 | | VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
3095 | | SuccessOrExit(error = otPlatDebugUart_logfile(aArgs[1].GetCString())); |
3096 | | } |
3097 | | #endif |
3098 | 1 | else |
3099 | 1 | { |
3100 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
3101 | 1 | } |
3102 | | |
3103 | 3 | exit: |
3104 | 3 | return error; |
3105 | 3 | } |
3106 | | |
3107 | | template <> otError Interpreter::Process<Cmd("extpanid")>(Arg aArgs[]) |
3108 | 19 | { |
3109 | 19 | otError error = OT_ERROR_NONE; |
3110 | | |
3111 | | /** |
3112 | | * @cli extpanid |
3113 | | * @code |
3114 | | * extpanid |
3115 | | * dead00beef00cafe |
3116 | | * Done |
3117 | | * @endcode |
3118 | | * @par api_copy |
3119 | | * #otThreadGetExtendedPanId |
3120 | | */ |
3121 | 19 | if (aArgs[0].IsEmpty()) |
3122 | 17 | { |
3123 | 17 | OutputBytesLine(otThreadGetExtendedPanId(GetInstancePtr())->m8); |
3124 | 17 | } |
3125 | | /** |
3126 | | * @cli extpanid (set) |
3127 | | * @code |
3128 | | * extpanid dead00beef00cafe |
3129 | | * Done |
3130 | | * @endcode |
3131 | | * @cparam extpanid @ca{extpanid} |
3132 | | * @par |
3133 | | * @note The current commissioning credential becomes stale after changing this value. |
3134 | | * Use `pskc` to reset. |
3135 | | * @par api_copy |
3136 | | * #otThreadSetExtendedPanId |
3137 | | */ |
3138 | 2 | else |
3139 | 2 | { |
3140 | 2 | otExtendedPanId extPanId; |
3141 | | |
3142 | 2 | SuccessOrExit(error = aArgs[0].ParseAsHexString(extPanId.m8)); |
3143 | 1 | error = otThreadSetExtendedPanId(GetInstancePtr(), &extPanId); |
3144 | 1 | } |
3145 | | |
3146 | 19 | exit: |
3147 | 19 | return error; |
3148 | 19 | } |
3149 | | |
3150 | | /** |
3151 | | * @cli factoryreset |
3152 | | * @code |
3153 | | * factoryreset |
3154 | | * @endcode |
3155 | | * @par api_copy |
3156 | | * #otInstanceFactoryReset |
3157 | | */ |
3158 | | template <> otError Interpreter::Process<Cmd("factoryreset")>(Arg aArgs[]) |
3159 | 1 | { |
3160 | 1 | OT_UNUSED_VARIABLE(aArgs); |
3161 | | |
3162 | 1 | otInstanceFactoryReset(GetInstancePtr()); |
3163 | | |
3164 | 1 | return OT_ERROR_NONE; |
3165 | 1 | } |
3166 | | |
3167 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
3168 | | template <> otError Interpreter::Process<Cmd("fake")>(Arg aArgs[]) |
3169 | | { |
3170 | | otError error = OT_ERROR_INVALID_COMMAND; |
3171 | | |
3172 | | /** |
3173 | | * @cli fake (a,an) |
3174 | | * @code |
3175 | | * fake /a/an fdde:ad00:beef:0:0:ff:fe00:a800 fd00:7d03:7d03:7d03:55f2:bb6a:7a43:a03b 1111222233334444 |
3176 | | * Done |
3177 | | * @endcode |
3178 | | * @cparam fake /a/an @ca{dst-ipaddr} @ca{target} @ca{meshLocalIid} |
3179 | | * @par |
3180 | | * Sends fake Thread messages. |
3181 | | * @par |
3182 | | * Available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled. |
3183 | | * @sa otThreadSendAddressNotification |
3184 | | */ |
3185 | | if (aArgs[0] == "/a/an") |
3186 | | { |
3187 | | otIp6Address destination, target; |
3188 | | otIp6InterfaceIdentifier mlIid; |
3189 | | |
3190 | | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(destination)); |
3191 | | SuccessOrExit(error = aArgs[2].ParseAsIp6Address(target)); |
3192 | | SuccessOrExit(error = aArgs[3].ParseAsHexString(mlIid.mFields.m8)); |
3193 | | otThreadSendAddressNotification(GetInstancePtr(), &destination, &target, &mlIid); |
3194 | | } |
3195 | | #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE |
3196 | | else if (aArgs[0] == "/b/ba") |
3197 | | { |
3198 | | otIp6Address target; |
3199 | | otIp6InterfaceIdentifier mlIid; |
3200 | | uint32_t timeSinceLastTransaction; |
3201 | | |
3202 | | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(target)); |
3203 | | SuccessOrExit(error = aArgs[2].ParseAsHexString(mlIid.mFields.m8)); |
3204 | | SuccessOrExit(error = aArgs[3].ParseAsUint32(timeSinceLastTransaction)); |
3205 | | |
3206 | | error = otThreadSendProactiveBackboneNotification(GetInstancePtr(), &target, &mlIid, timeSinceLastTransaction); |
3207 | | } |
3208 | | #endif |
3209 | | |
3210 | | exit: |
3211 | | return error; |
3212 | | } |
3213 | | #endif |
3214 | | |
3215 | | template <> otError Interpreter::Process<Cmd("fem")>(Arg aArgs[]) |
3216 | 6 | { |
3217 | 6 | otError error = OT_ERROR_NONE; |
3218 | | |
3219 | | /** |
3220 | | * @cli fem |
3221 | | * @code |
3222 | | * fem |
3223 | | * LNA gain 11 dBm |
3224 | | * Done |
3225 | | * @endcode |
3226 | | * @par |
3227 | | * Gets external FEM parameters. |
3228 | | * @sa otPlatRadioGetFemLnaGain |
3229 | | */ |
3230 | 6 | if (aArgs[0].IsEmpty()) |
3231 | 1 | { |
3232 | 1 | int8_t lnaGain; |
3233 | | |
3234 | 1 | SuccessOrExit(error = otPlatRadioGetFemLnaGain(GetInstancePtr(), &lnaGain)); |
3235 | 0 | OutputLine("LNA gain %d dBm", lnaGain); |
3236 | 0 | } |
3237 | | /** |
3238 | | * @cli fem lnagain (get) |
3239 | | * @code |
3240 | | * fem lnagain |
3241 | | * 11 |
3242 | | * Done |
3243 | | * @endcode |
3244 | | * @par api_copy |
3245 | | * #otPlatRadioGetFemLnaGain |
3246 | | */ |
3247 | 5 | else if (aArgs[0] == "lnagain") |
3248 | 3 | { |
3249 | 3 | if (aArgs[1].IsEmpty()) |
3250 | 1 | { |
3251 | 1 | int8_t lnaGain; |
3252 | | |
3253 | 1 | SuccessOrExit(error = otPlatRadioGetFemLnaGain(GetInstancePtr(), &lnaGain)); |
3254 | 0 | OutputLine("%d", lnaGain); |
3255 | 0 | } |
3256 | | /** |
3257 | | * @cli fem lnagain (set) |
3258 | | * @code |
3259 | | * fem lnagain 8 |
3260 | | * Done |
3261 | | * @endcode |
3262 | | * @par api_copy |
3263 | | * #otPlatRadioSetFemLnaGain |
3264 | | */ |
3265 | 2 | else |
3266 | 2 | { |
3267 | 2 | int8_t lnaGain; |
3268 | | |
3269 | 2 | SuccessOrExit(error = aArgs[1].ParseAsInt8(lnaGain)); |
3270 | 1 | SuccessOrExit(error = otPlatRadioSetFemLnaGain(GetInstancePtr(), lnaGain)); |
3271 | 1 | } |
3272 | 3 | } |
3273 | 2 | else |
3274 | 2 | { |
3275 | 2 | error = OT_ERROR_INVALID_ARGS; |
3276 | 2 | } |
3277 | | |
3278 | 6 | exit: |
3279 | 6 | return error; |
3280 | 6 | } |
3281 | | |
3282 | | template <> otError Interpreter::Process<Cmd("ifconfig")>(Arg aArgs[]) |
3283 | 4 | { |
3284 | 4 | otError error = OT_ERROR_NONE; |
3285 | | |
3286 | | /** |
3287 | | * @cli ifconfig |
3288 | | * @code |
3289 | | * ifconfig |
3290 | | * down |
3291 | | * Done |
3292 | | * @endcode |
3293 | | * @code |
3294 | | * ifconfig |
3295 | | * up |
3296 | | * Done |
3297 | | * @endcode |
3298 | | * @par api_copy |
3299 | | * #otIp6IsEnabled |
3300 | | */ |
3301 | 4 | if (aArgs[0].IsEmpty()) |
3302 | 1 | { |
3303 | 1 | if (otIp6IsEnabled(GetInstancePtr())) |
3304 | 1 | { |
3305 | 1 | OutputLine("up"); |
3306 | 1 | } |
3307 | 0 | else |
3308 | 0 | { |
3309 | 0 | OutputLine("down"); |
3310 | 0 | } |
3311 | 1 | } |
3312 | | /** |
3313 | | * @cli ifconfig (up,down) |
3314 | | * @code |
3315 | | * ifconfig up |
3316 | | * Done |
3317 | | * @endcode |
3318 | | * @code |
3319 | | * ifconfig down |
3320 | | * Done |
3321 | | * @endcode |
3322 | | * @cparam ifconfig @ca{up|down} |
3323 | | * @par api_copy |
3324 | | * #otIp6SetEnabled |
3325 | | */ |
3326 | 3 | else if (aArgs[0] == "up") |
3327 | 1 | { |
3328 | 1 | SuccessOrExit(error = otIp6SetEnabled(GetInstancePtr(), true)); |
3329 | 1 | } |
3330 | 2 | else if (aArgs[0] == "down") |
3331 | 1 | { |
3332 | 1 | SuccessOrExit(error = otIp6SetEnabled(GetInstancePtr(), false)); |
3333 | 1 | } |
3334 | 1 | else |
3335 | 1 | { |
3336 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
3337 | 1 | } |
3338 | | |
3339 | 4 | exit: |
3340 | 4 | return error; |
3341 | 4 | } |
3342 | | |
3343 | | template <> otError Interpreter::Process<Cmd("instanceid")>(Arg aArgs[]) |
3344 | 2 | { |
3345 | | /** |
3346 | | * @cli instanceid |
3347 | | * @code |
3348 | | * instanceid |
3349 | | * 468697314 |
3350 | | * Done |
3351 | | * @endcode |
3352 | | * @par api_copy |
3353 | | * #otInstanceGetId |
3354 | | */ |
3355 | 2 | return ProcessGet(aArgs, otInstanceGetId); |
3356 | 2 | } |
3357 | | |
3358 | | template <> otError Interpreter::Process<Cmd("ipaddr")>(Arg aArgs[]) |
3359 | 63 | { |
3360 | 63 | otError error = OT_ERROR_NONE; |
3361 | 63 | bool verbose = false; |
3362 | | |
3363 | 63 | if (aArgs[0] == "-v") |
3364 | 1 | { |
3365 | 1 | aArgs++; |
3366 | 1 | verbose = true; |
3367 | 1 | } |
3368 | | |
3369 | | /** |
3370 | | * @cli ipaddr |
3371 | | * @code |
3372 | | * ipaddr |
3373 | | * fdde:ad00:beef:0:0:ff:fe00:0 |
3374 | | * fdde:ad00:beef:0:558:f56b:d688:799 |
3375 | | * fe80:0:0:0:f3d9:2a82:c8d8:fe43 |
3376 | | * Done |
3377 | | * @endcode |
3378 | | * @code |
3379 | | * ipaddr -v |
3380 | | * fd5e:18fa:f4a5:b8:0:ff:fe00:fc00 origin:thread plen:64 preferred:0 valid:1 |
3381 | | * fd5e:18fa:f4a5:b8:0:ff:fe00:dc00 origin:thread plen:64 preferred:0 valid:1 |
3382 | | * fd5e:18fa:f4a5:b8:f8e:5d95:87a0:e82c origin:thread plen:64 preferred:0 valid:1 |
3383 | | * fe80:0:0:0:4891:b191:e277:8826 origin:thread plen:64 preferred:1 valid:1 |
3384 | | * Done |
3385 | | * @endcode |
3386 | | * @cparam ipaddr [@ca{-v}] |
3387 | | * Use `-v` to get more verbose information about the address: |
3388 | | * - `origin`: can be `thread`, `slaac`, `dhcp6`, `manual` and indicates the origin of the address |
3389 | | * - `plen`: prefix length |
3390 | | * - `preferred`: preferred flag (boolean) |
3391 | | * - `valid`: valid flag (boolean) |
3392 | | * @par api_copy |
3393 | | * #otIp6GetUnicastAddresses |
3394 | | */ |
3395 | 63 | if (aArgs[0].IsEmpty()) |
3396 | 19 | { |
3397 | 19 | const otNetifAddress *unicastAddrs = otIp6GetUnicastAddresses(GetInstancePtr()); |
3398 | | |
3399 | 57 | for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext) |
3400 | 38 | { |
3401 | 38 | OutputIp6Address(addr->mAddress); |
3402 | | |
3403 | 38 | if (verbose) |
3404 | 2 | { |
3405 | 2 | OutputFormat(" origin:%s plen:%u preferred:%u valid:%u", AddressOriginToString(addr->mAddressOrigin), |
3406 | 2 | addr->mPrefixLength, addr->mPreferred, addr->mValid); |
3407 | 2 | } |
3408 | | |
3409 | 38 | OutputNewLine(); |
3410 | 38 | } |
3411 | 19 | } |
3412 | | /** |
3413 | | * @cli ipaddr add |
3414 | | * @code |
3415 | | * ipaddr add 2001::dead:beef:cafe |
3416 | | * Done |
3417 | | * @endcode |
3418 | | * @cparam ipaddr add @ca{aAddress} |
3419 | | * @par api_copy |
3420 | | * #otIp6AddUnicastAddress |
3421 | | */ |
3422 | 44 | else if (aArgs[0] == "add") |
3423 | 25 | { |
3424 | 25 | otNetifAddress address; |
3425 | | |
3426 | 25 | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address.mAddress)); |
3427 | 24 | address.mPrefixLength = 64; |
3428 | 24 | address.mPreferred = true; |
3429 | 24 | address.mValid = true; |
3430 | 24 | address.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL; |
3431 | | |
3432 | 24 | error = otIp6AddUnicastAddress(GetInstancePtr(), &address); |
3433 | 24 | } |
3434 | | /** |
3435 | | * @cli ipaddr del |
3436 | | * @code |
3437 | | * ipaddr del 2001::dead:beef:cafe |
3438 | | * Done |
3439 | | * @endcode |
3440 | | * @cparam ipaddr del @ca{aAddress} |
3441 | | * @par api_copy |
3442 | | * #otIp6RemoveUnicastAddress |
3443 | | */ |
3444 | 19 | else if (aArgs[0] == "del") |
3445 | 15 | { |
3446 | 15 | otIp6Address address; |
3447 | | |
3448 | 15 | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); |
3449 | 13 | error = otIp6RemoveUnicastAddress(GetInstancePtr(), &address); |
3450 | 13 | } |
3451 | | /** |
3452 | | * @cli ipaddr linklocal |
3453 | | * @code |
3454 | | * ipaddr linklocal |
3455 | | * fe80:0:0:0:f3d9:2a82:c8d8:fe43 |
3456 | | * Done |
3457 | | * @endcode |
3458 | | * @par api_copy |
3459 | | * #otThreadGetLinkLocalIp6Address |
3460 | | */ |
3461 | 4 | else if (aArgs[0] == "linklocal") |
3462 | 1 | { |
3463 | 1 | OutputIp6AddressLine(*otThreadGetLinkLocalIp6Address(GetInstancePtr())); |
3464 | 1 | } |
3465 | | /** |
3466 | | * @cli ipaddr rloc |
3467 | | * @code |
3468 | | * ipaddr rloc |
3469 | | * fdde:ad00:beef:0:0:ff:fe00:0 |
3470 | | * Done |
3471 | | * @endcode |
3472 | | * @par api_copy |
3473 | | * #otThreadGetRloc |
3474 | | */ |
3475 | 3 | else if (aArgs[0] == "rloc") |
3476 | 1 | { |
3477 | 1 | OutputIp6AddressLine(*otThreadGetRloc(GetInstancePtr())); |
3478 | 1 | } |
3479 | | /** |
3480 | | * @cli ipaddr mleid |
3481 | | * @code |
3482 | | * ipaddr mleid |
3483 | | * fdde:ad00:beef:0:558:f56b:d688:799 |
3484 | | * Done |
3485 | | * @endcode |
3486 | | * @par api_copy |
3487 | | * #otThreadGetMeshLocalEid |
3488 | | */ |
3489 | 2 | else if (aArgs[0] == "mleid") |
3490 | 1 | { |
3491 | 1 | OutputIp6AddressLine(*otThreadGetMeshLocalEid(GetInstancePtr())); |
3492 | 1 | } |
3493 | 1 | else |
3494 | 1 | { |
3495 | 1 | error = OT_ERROR_INVALID_COMMAND; |
3496 | 1 | } |
3497 | | |
3498 | 63 | exit: |
3499 | 63 | return error; |
3500 | 63 | } |
3501 | | |
3502 | | template <> otError Interpreter::Process<Cmd("ipmaddr")>(Arg aArgs[]) |
3503 | 105 | { |
3504 | 105 | otError error = OT_ERROR_NONE; |
3505 | | |
3506 | | /** |
3507 | | * @cli ipmaddr |
3508 | | * @code |
3509 | | * ipmaddr |
3510 | | * ff05:0:0:0:0:0:0:1 |
3511 | | * ff33:40:fdde:ad00:beef:0:0:1 |
3512 | | * ff32:40:fdde:ad00:beef:0:0:1 |
3513 | | * Done |
3514 | | * @endcode |
3515 | | * @par api_copy |
3516 | | * #otIp6GetMulticastAddresses |
3517 | | */ |
3518 | 105 | if (aArgs[0].IsEmpty()) |
3519 | 17 | { |
3520 | 102 | for (const otNetifMulticastAddress *addr = otIp6GetMulticastAddresses(GetInstancePtr()); addr; |
3521 | 85 | addr = addr->mNext) |
3522 | 85 | { |
3523 | 85 | OutputIp6AddressLine(addr->mAddress); |
3524 | 85 | } |
3525 | 17 | } |
3526 | | /** |
3527 | | * @cli ipmaddr add |
3528 | | * @code |
3529 | | * ipmaddr add ff05::1 |
3530 | | * Done |
3531 | | * @endcode |
3532 | | * @cparam ipmaddr add @ca{aAddress} |
3533 | | * @par api_copy |
3534 | | * #otIp6SubscribeMulticastAddress |
3535 | | */ |
3536 | 88 | else if (aArgs[0] == "add") |
3537 | 39 | { |
3538 | 39 | otIp6Address address; |
3539 | | |
3540 | 39 | aArgs++; |
3541 | | |
3542 | 39 | do |
3543 | 39 | { |
3544 | 39 | SuccessOrExit(error = aArgs->ParseAsIp6Address(address)); |
3545 | 38 | SuccessOrExit(error = otIp6SubscribeMulticastAddress(GetInstancePtr(), &address)); |
3546 | 38 | } |
3547 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
3548 | | while (!(++aArgs)->IsEmpty()); |
3549 | | #else |
3550 | 39 | while (false); |
3551 | 39 | #endif |
3552 | 39 | } |
3553 | | /** |
3554 | | * @cli ipmaddr del |
3555 | | * @code |
3556 | | * ipmaddr del ff05::1 |
3557 | | * Done |
3558 | | * @endcode |
3559 | | * @cparam ipmaddr del @ca{aAddress} |
3560 | | * @par api_copy |
3561 | | * #otIp6UnsubscribeMulticastAddress |
3562 | | */ |
3563 | 49 | else if (aArgs[0] == "del") |
3564 | 46 | { |
3565 | 46 | otIp6Address address; |
3566 | | |
3567 | 46 | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); |
3568 | 44 | error = otIp6UnsubscribeMulticastAddress(GetInstancePtr(), &address); |
3569 | 44 | } |
3570 | | /** |
3571 | | * @cli ipmaddr llatn |
3572 | | * @code |
3573 | | * ipmaddr llatn |
3574 | | * ff32:40:fdde:ad00:beef:0:0:1 |
3575 | | * Done |
3576 | | * @endcode |
3577 | | * @par api_copy |
3578 | | * #otThreadGetLinkLocalAllThreadNodesMulticastAddress |
3579 | | */ |
3580 | 3 | else if (aArgs[0] == "llatn") |
3581 | 1 | { |
3582 | 1 | OutputIp6AddressLine(*otThreadGetLinkLocalAllThreadNodesMulticastAddress(GetInstancePtr())); |
3583 | 1 | } |
3584 | | /** |
3585 | | * @cli ipmaddr rlatn |
3586 | | * @code |
3587 | | * ipmaddr rlatn |
3588 | | * ff33:40:fdde:ad00:beef:0:0:1 |
3589 | | * Done |
3590 | | * @endcode |
3591 | | * @par api_copy |
3592 | | * #otThreadGetRealmLocalAllThreadNodesMulticastAddress |
3593 | | */ |
3594 | 2 | else if (aArgs[0] == "rlatn") |
3595 | 1 | { |
3596 | 1 | OutputIp6AddressLine(*otThreadGetRealmLocalAllThreadNodesMulticastAddress(GetInstancePtr())); |
3597 | 1 | } |
3598 | 1 | else |
3599 | 1 | { |
3600 | 1 | error = OT_ERROR_INVALID_COMMAND; |
3601 | 1 | } |
3602 | | |
3603 | 105 | exit: |
3604 | 105 | return error; |
3605 | 105 | } |
3606 | | |
3607 | | template <> otError Interpreter::Process<Cmd("keysequence")>(Arg aArgs[]) |
3608 | 63 | { |
3609 | 63 | otError error = OT_ERROR_INVALID_ARGS; |
3610 | | |
3611 | | /** |
3612 | | * @cli keysequence counter |
3613 | | * @code |
3614 | | * keysequence counter |
3615 | | * 10 |
3616 | | * Done |
3617 | | * @endcode |
3618 | | * @par api_copy |
3619 | | * #otThreadGetKeySequenceCounter |
3620 | | */ |
3621 | 63 | if (aArgs[0] == "counter") |
3622 | 58 | { |
3623 | | /** |
3624 | | * @cli keysequence counter (set) |
3625 | | * @code |
3626 | | * keysequence counter 10 |
3627 | | * Done |
3628 | | * @endcode |
3629 | | * @cparam keysequence counter @ca{counter} |
3630 | | * @par api_copy |
3631 | | * #otThreadSetKeySequenceCounter |
3632 | | */ |
3633 | 58 | error = ProcessGetSet(aArgs + 1, otThreadGetKeySequenceCounter, otThreadSetKeySequenceCounter); |
3634 | 58 | } |
3635 | | /** |
3636 | | * @cli keysequence guardtime |
3637 | | * @code |
3638 | | * keysequence guardtime |
3639 | | * 0 |
3640 | | * Done |
3641 | | * @endcode |
3642 | | * @par api_copy |
3643 | | * #otThreadGetKeySwitchGuardTime |
3644 | | */ |
3645 | 5 | else if (aArgs[0] == "guardtime") |
3646 | 4 | { |
3647 | | /** |
3648 | | * @cli keysequence guardtime (set) |
3649 | | * @code |
3650 | | * keysequence guardtime 0 |
3651 | | * Done |
3652 | | * @endcode |
3653 | | * @cparam keysequence guardtime @ca{guardtime-hours} |
3654 | | * Use `0` to `Thread Key Switch` immediately if there's a key index match. |
3655 | | * @par api_copy |
3656 | | * #otThreadSetKeySwitchGuardTime |
3657 | | */ |
3658 | 4 | error = ProcessGetSet(aArgs + 1, otThreadGetKeySwitchGuardTime, otThreadSetKeySwitchGuardTime); |
3659 | 4 | } |
3660 | | |
3661 | 63 | return error; |
3662 | 63 | } |
3663 | | |
3664 | | /** |
3665 | | * @cli leaderdata |
3666 | | * @code |
3667 | | * leaderdata |
3668 | | * Partition ID: 1077744240 |
3669 | | * Weighting: 64 |
3670 | | * Data Version: 109 |
3671 | | * Stable Data Version: 211 |
3672 | | * Leader Router ID: 60 |
3673 | | * Done |
3674 | | * @endcode |
3675 | | * @par |
3676 | | * Gets the Thread Leader Data. |
3677 | | * @sa otThreadGetLeaderData |
3678 | | */ |
3679 | | template <> otError Interpreter::Process<Cmd("leaderdata")>(Arg aArgs[]) |
3680 | 17 | { |
3681 | 17 | OT_UNUSED_VARIABLE(aArgs); |
3682 | | |
3683 | 17 | otError error; |
3684 | 17 | otLeaderData leaderData; |
3685 | | |
3686 | 17 | SuccessOrExit(error = otThreadGetLeaderData(GetInstancePtr(), &leaderData)); |
3687 | | |
3688 | 0 | OutputLine("Partition ID: %lu", ToUlong(leaderData.mPartitionId)); |
3689 | 0 | OutputLine("Weighting: %u", leaderData.mWeighting); |
3690 | 0 | OutputLine("Data Version: %u", leaderData.mDataVersion); |
3691 | 0 | OutputLine("Stable Data Version: %u", leaderData.mStableDataVersion); |
3692 | 0 | OutputLine("Leader Router ID: %u", leaderData.mLeaderRouterId); |
3693 | |
|
3694 | 17 | exit: |
3695 | 17 | return error; |
3696 | 0 | } |
3697 | | |
3698 | | #if OPENTHREAD_FTD |
3699 | | template <> otError Interpreter::Process<Cmd("partitionid")>(Arg aArgs[]) |
3700 | 18 | { |
3701 | 18 | otError error = OT_ERROR_INVALID_COMMAND; |
3702 | | |
3703 | | /** |
3704 | | * @cli partitionid |
3705 | | * @code |
3706 | | * partitionid |
3707 | | * 4294967295 |
3708 | | * Done |
3709 | | * @endcode |
3710 | | * @par |
3711 | | * Get the Thread Network Partition ID. |
3712 | | * @sa otThreadGetPartitionId |
3713 | | */ |
3714 | 18 | if (aArgs[0].IsEmpty()) |
3715 | 17 | { |
3716 | 17 | OutputLine("%lu", ToUlong(otThreadGetPartitionId(GetInstancePtr()))); |
3717 | 17 | error = OT_ERROR_NONE; |
3718 | 17 | } |
3719 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
3720 | | /** |
3721 | | * @cli partitionid preferred (get,set) |
3722 | | * @code |
3723 | | * partitionid preferred |
3724 | | * 4294967295 |
3725 | | * Done |
3726 | | * @endcode |
3727 | | * @code |
3728 | | * partitionid preferred 0xffffffff |
3729 | | * Done |
3730 | | * @endcode |
3731 | | * @cparam partitionid preferred @ca{partitionid} |
3732 | | * @sa otThreadGetPreferredLeaderPartitionId |
3733 | | * @sa otThreadSetPreferredLeaderPartitionId |
3734 | | * @par |
3735 | | * `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. |
3736 | | */ |
3737 | | else if (aArgs[0] == "preferred") |
3738 | | { |
3739 | | error = ProcessGetSet(aArgs + 1, otThreadGetPreferredLeaderPartitionId, otThreadSetPreferredLeaderPartitionId); |
3740 | | } |
3741 | | #endif |
3742 | | |
3743 | 18 | return error; |
3744 | 18 | } |
3745 | | |
3746 | | /** |
3747 | | * @cli leaderweight |
3748 | | * @code |
3749 | | * leaderweight |
3750 | | * 128 |
3751 | | * Done |
3752 | | * @endcode |
3753 | | * @par api_copy |
3754 | | * #otThreadGetLocalLeaderWeight |
3755 | | */ |
3756 | | template <> otError Interpreter::Process<Cmd("leaderweight")>(Arg aArgs[]) |
3757 | 4 | { |
3758 | | /** |
3759 | | * @cli leaderweight (set) |
3760 | | * @code |
3761 | | * leaderweight 128 |
3762 | | * Done |
3763 | | * @endcode |
3764 | | * @cparam leaderweight @ca{weight} |
3765 | | * @par api_copy |
3766 | | * #otThreadSetLocalLeaderWeight |
3767 | | */ |
3768 | 4 | return ProcessGetSet(aArgs, otThreadGetLocalLeaderWeight, otThreadSetLocalLeaderWeight); |
3769 | 4 | } |
3770 | | |
3771 | | #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE |
3772 | | template <> otError Interpreter::Process<Cmd("deviceprops")>(Arg aArgs[]) |
3773 | | { |
3774 | | static const char *const kPowerSupplyStrings[4] = { |
3775 | | "battery", // (0) OT_POWER_SUPPLY_BATTERY |
3776 | | "external", // (1) OT_POWER_SUPPLY_EXTERNAL |
3777 | | "external-stable", // (2) OT_POWER_SUPPLY_EXTERNAL_STABLE |
3778 | | "external-unstable", // (3) OT_POWER_SUPPLY_EXTERNAL_UNSTABLE |
3779 | | }; |
3780 | | |
3781 | | static_assert(0 == OT_POWER_SUPPLY_BATTERY, "OT_POWER_SUPPLY_BATTERY value is incorrect"); |
3782 | | static_assert(1 == OT_POWER_SUPPLY_EXTERNAL, "OT_POWER_SUPPLY_EXTERNAL value is incorrect"); |
3783 | | static_assert(2 == OT_POWER_SUPPLY_EXTERNAL_STABLE, "OT_POWER_SUPPLY_EXTERNAL_STABLE value is incorrect"); |
3784 | | static_assert(3 == OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, "OT_POWER_SUPPLY_EXTERNAL_UNSTABLE value is incorrect"); |
3785 | | |
3786 | | otError error = OT_ERROR_NONE; |
3787 | | |
3788 | | /** |
3789 | | * @cli deviceprops |
3790 | | * @code |
3791 | | * deviceprops |
3792 | | * PowerSupply : external |
3793 | | * IsBorderRouter : yes |
3794 | | * SupportsCcm : no |
3795 | | * IsUnstable : no |
3796 | | * WeightAdjustment : 0 |
3797 | | * Done |
3798 | | * @endcode |
3799 | | * @par api_copy |
3800 | | * #otThreadGetDeviceProperties |
3801 | | */ |
3802 | | if (aArgs[0].IsEmpty()) |
3803 | | { |
3804 | | const otDeviceProperties *props = otThreadGetDeviceProperties(GetInstancePtr()); |
3805 | | |
3806 | | OutputLine("PowerSupply : %s", Stringify(props->mPowerSupply, kPowerSupplyStrings)); |
3807 | | OutputLine("IsBorderRouter : %s", props->mIsBorderRouter ? "yes" : "no"); |
3808 | | OutputLine("SupportsCcm : %s", props->mSupportsCcm ? "yes" : "no"); |
3809 | | OutputLine("IsUnstable : %s", props->mIsUnstable ? "yes" : "no"); |
3810 | | OutputLine("WeightAdjustment : %d", props->mLeaderWeightAdjustment); |
3811 | | } |
3812 | | /** |
3813 | | * @cli deviceprops (set) |
3814 | | * @code |
3815 | | * deviceprops battery 0 0 0 -5 |
3816 | | * Done |
3817 | | * @endcode |
3818 | | * @code |
3819 | | * deviceprops |
3820 | | * PowerSupply : battery |
3821 | | * IsBorderRouter : no |
3822 | | * SupportsCcm : no |
3823 | | * IsUnstable : no |
3824 | | * WeightAdjustment : -5 |
3825 | | * Done |
3826 | | * @endcode |
3827 | | * @cparam deviceprops @ca{powerSupply} @ca{isBr} @ca{supportsCcm} @ca{isUnstable} @ca{weightAdjustment} |
3828 | | * `powerSupply`: should be 'battery', 'external', 'external-stable', 'external-unstable'. |
3829 | | * @par |
3830 | | * Sets the device properties. |
3831 | | * @csa{leaderweight} |
3832 | | * @csa{leaderweight (set)} |
3833 | | * @sa #otThreadSetDeviceProperties |
3834 | | */ |
3835 | | else |
3836 | | { |
3837 | | otDeviceProperties props; |
3838 | | bool value; |
3839 | | size_t index; |
3840 | | |
3841 | | for (index = 0; index < OT_ARRAY_LENGTH(kPowerSupplyStrings); index++) |
3842 | | { |
3843 | | if (aArgs[0] == kPowerSupplyStrings[index]) |
3844 | | { |
3845 | | props.mPowerSupply = static_cast<otPowerSupply>(index); |
3846 | | break; |
3847 | | } |
3848 | | } |
3849 | | |
3850 | | VerifyOrExit(index < OT_ARRAY_LENGTH(kPowerSupplyStrings), error = OT_ERROR_INVALID_ARGS); |
3851 | | |
3852 | | SuccessOrExit(error = aArgs[1].ParseAsBool(value)); |
3853 | | props.mIsBorderRouter = value; |
3854 | | |
3855 | | SuccessOrExit(error = aArgs[2].ParseAsBool(value)); |
3856 | | props.mSupportsCcm = value; |
3857 | | |
3858 | | SuccessOrExit(error = aArgs[3].ParseAsBool(value)); |
3859 | | props.mIsUnstable = value; |
3860 | | |
3861 | | SuccessOrExit(error = aArgs[4].ParseAsInt8(props.mLeaderWeightAdjustment)); |
3862 | | |
3863 | | VerifyOrExit(aArgs[5].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
3864 | | otThreadSetDeviceProperties(GetInstancePtr(), &props); |
3865 | | } |
3866 | | |
3867 | | exit: |
3868 | | return error; |
3869 | | } |
3870 | | #endif // OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE |
3871 | | |
3872 | | #endif // OPENTHREAD_FTD |
3873 | | |
3874 | | #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE |
3875 | | |
3876 | | template <> otError Interpreter::Process<Cmd("linkmetrics")>(Arg aArgs[]) { return mLinkMetrics.Process(aArgs); } |
3877 | | |
3878 | | #if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE |
3879 | | template <> otError Interpreter::Process<Cmd("linkmetricsmgr")>(Arg aArgs[]) |
3880 | | { |
3881 | | otError error = OT_ERROR_NONE; |
3882 | | |
3883 | | /** |
3884 | | * @cli linkmetricsmgr (enable,disable) |
3885 | | * @code |
3886 | | * linkmetricmgr enable |
3887 | | * Done |
3888 | | * @endcode |
3889 | | * @code |
3890 | | * linkmetricmgr disable |
3891 | | * Done |
3892 | | * @endcode |
3893 | | * @cparam linkmetricsmgr @ca{enable|disable} |
3894 | | * @par api_copy |
3895 | | * #otLinkMetricsManagerSetEnabled |
3896 | | */ |
3897 | | if (ProcessEnableDisable(aArgs, otLinkMetricsManagerIsEnabled, otLinkMetricsManagerSetEnabled) == OT_ERROR_NONE) |
3898 | | { |
3899 | | } |
3900 | | /** |
3901 | | * @cli linkmetricsmgr show |
3902 | | * @code |
3903 | | * linkmetricsmgr show |
3904 | | * ExtAddr:827aa7f7f63e1234, LinkMargin:80, Rssi:-20 |
3905 | | * Done |
3906 | | * @endcode |
3907 | | * @par api_copy |
3908 | | * #otLinkMetricsManagerGetMetricsValueByExtAddr |
3909 | | */ |
3910 | | else if (aArgs[0] == "show") |
3911 | | { |
3912 | | otNeighborInfoIterator iterator = OT_NEIGHBOR_INFO_ITERATOR_INIT; |
3913 | | otNeighborInfo neighborInfo; |
3914 | | |
3915 | | while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) |
3916 | | { |
3917 | | otLinkMetricsValues linkMetricsValues; |
3918 | | |
3919 | | if (otLinkMetricsManagerGetMetricsValueByExtAddr(GetInstancePtr(), &neighborInfo.mExtAddress, |
3920 | | &linkMetricsValues) != OT_ERROR_NONE) |
3921 | | { |
3922 | | continue; |
3923 | | } |
3924 | | |
3925 | | OutputFormat("ExtAddr:"); |
3926 | | OutputExtAddress(neighborInfo.mExtAddress); |
3927 | | OutputLine(", LinkMargin:%u, Rssi:%d", linkMetricsValues.mLinkMarginValue, linkMetricsValues.mRssiValue); |
3928 | | } |
3929 | | } |
3930 | | else |
3931 | | { |
3932 | | error = OT_ERROR_INVALID_COMMAND; |
3933 | | } |
3934 | | |
3935 | | return error; |
3936 | | } |
3937 | | #endif // OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE |
3938 | | |
3939 | | #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE |
3940 | | |
3941 | | #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE |
3942 | | |
3943 | | template <> otError Interpreter::Process<Cmd("locate")>(Arg aArgs[]) |
3944 | | { |
3945 | | otError error = OT_ERROR_INVALID_ARGS; |
3946 | | otIp6Address anycastAddress; |
3947 | | |
3948 | | /** |
3949 | | * @cli locate |
3950 | | * @code |
3951 | | * locate |
3952 | | * Idle |
3953 | | * Done |
3954 | | * @endcode |
3955 | | * @code |
3956 | | * locate fdde:ad00:beef:0:0:ff:fe00:fc10 |
3957 | | * @endcode |
3958 | | * @code |
3959 | | * locate |
3960 | | * In Progress |
3961 | | * Done |
3962 | | * @endcode |
3963 | | * @par |
3964 | | * Gets the current state (`In Progress` or `Idle`) of anycast locator. |
3965 | | * @par |
3966 | | * Available when `OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE` is enabled. |
3967 | | * @sa otThreadIsAnycastLocateInProgress |
3968 | | */ |
3969 | | if (aArgs[0].IsEmpty()) |
3970 | | { |
3971 | | OutputLine(otThreadIsAnycastLocateInProgress(GetInstancePtr()) ? "In Progress" : "Idle"); |
3972 | | ExitNow(error = OT_ERROR_NONE); |
3973 | | } |
3974 | | |
3975 | | /** |
3976 | | * @cli locate (set) |
3977 | | * @code |
3978 | | * locate fdde:ad00:beef:0:0:ff:fe00:fc00 |
3979 | | * fdde:ad00:beef:0:d9d3:9000:16b:d03b 0xc800 |
3980 | | * Done |
3981 | | * @endcode |
3982 | | * @par |
3983 | | * Locate the closest destination of an anycast address (i.e., find the |
3984 | | * destination's mesh local EID and RLOC16). |
3985 | | * @par |
3986 | | * The closest destination is determined based on the current routing |
3987 | | * table and path costs within the Thread mesh. |
3988 | | * @par |
3989 | | * Available when `OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE` is enabled. |
3990 | | * @sa otThreadLocateAnycastDestination |
3991 | | * @cparam locate @ca{anycastaddr} |
3992 | | */ |
3993 | | SuccessOrExit(error = aArgs[0].ParseAsIp6Address(anycastAddress)); |
3994 | | SuccessOrExit(error = |
3995 | | otThreadLocateAnycastDestination(GetInstancePtr(), &anycastAddress, HandleLocateResult, this)); |
3996 | | SetCommandTimeout(kLocateTimeoutMsecs); |
3997 | | mLocateInProgress = true; |
3998 | | error = OT_ERROR_PENDING; |
3999 | | |
4000 | | exit: |
4001 | | return error; |
4002 | | } |
4003 | | |
4004 | | void Interpreter::HandleLocateResult(void *aContext, |
4005 | | otError aError, |
4006 | | const otIp6Address *aMeshLocalAddress, |
4007 | | uint16_t aRloc16) |
4008 | | { |
4009 | | static_cast<Interpreter *>(aContext)->HandleLocateResult(aError, aMeshLocalAddress, aRloc16); |
4010 | | } |
4011 | | |
4012 | | void Interpreter::HandleLocateResult(otError aError, const otIp6Address *aMeshLocalAddress, uint16_t aRloc16) |
4013 | | { |
4014 | | VerifyOrExit(mLocateInProgress); |
4015 | | |
4016 | | mLocateInProgress = false; |
4017 | | |
4018 | | if (aError == OT_ERROR_NONE) |
4019 | | { |
4020 | | OutputIp6Address(*aMeshLocalAddress); |
4021 | | OutputLine(" 0x%04x", aRloc16); |
4022 | | } |
4023 | | |
4024 | | OutputResult(aError); |
4025 | | |
4026 | | exit: |
4027 | | return; |
4028 | | } |
4029 | | |
4030 | | #endif // OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE |
4031 | | |
4032 | | #if OPENTHREAD_FTD |
4033 | | template <> otError Interpreter::Process<Cmd("pskc")>(Arg aArgs[]) |
4034 | 79 | { |
4035 | 79 | otError error = OT_ERROR_NONE; |
4036 | 79 | otPskc pskc; |
4037 | | |
4038 | | /** |
4039 | | * @cli pskc |
4040 | | * @code |
4041 | | * pskc |
4042 | | * 67c0c203aa0b042bfb5381c47aef4d9e |
4043 | | * Done |
4044 | | * @endcode |
4045 | | * @par api_copy |
4046 | | * #otThreadGetPskc |
4047 | | */ |
4048 | 79 | if (aArgs[0].IsEmpty()) |
4049 | 1 | { |
4050 | 1 | otThreadGetPskc(GetInstancePtr(), &pskc); |
4051 | 1 | OutputBytesLine(pskc.m8); |
4052 | 1 | } |
4053 | 78 | else |
4054 | | /** |
4055 | | * @cli pskc (set) |
4056 | | * @code |
4057 | | * pskc 67c0c203aa0b042bfb5381c47aef4d9e |
4058 | | * Done |
4059 | | * @endcode |
4060 | | * @cparam pskc @ca{key} |
4061 | | * @par |
4062 | | * Sets the pskc in hexadecimal format. |
4063 | | */ |
4064 | 78 | { |
4065 | 78 | if (aArgs[1].IsEmpty()) |
4066 | 7 | { |
4067 | 7 | SuccessOrExit(error = aArgs[0].ParseAsHexString(pskc.m8)); |
4068 | 7 | } |
4069 | | /** |
4070 | | * @cli pskc -p |
4071 | | * @code |
4072 | | * pskc -p 123456 |
4073 | | * Done |
4074 | | * @endcode |
4075 | | * @cparam pskc -p @ca{passphrase} |
4076 | | * @par |
4077 | | * Generates the pskc from the passphrase (UTF-8 encoded), together with the current network name and extended |
4078 | | * PAN ID. |
4079 | | */ |
4080 | 71 | else if (aArgs[0] == "-p") |
4081 | 70 | { |
4082 | 70 | SuccessOrExit(error = otDatasetGeneratePskc( |
4083 | 70 | aArgs[1].GetCString(), |
4084 | 70 | reinterpret_cast<const otNetworkName *>(otThreadGetNetworkName(GetInstancePtr())), |
4085 | 70 | otThreadGetExtendedPanId(GetInstancePtr()), &pskc)); |
4086 | 70 | } |
4087 | 1 | else |
4088 | 1 | { |
4089 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
4090 | 1 | } |
4091 | | |
4092 | 35 | error = otThreadSetPskc(GetInstancePtr(), &pskc); |
4093 | 35 | } |
4094 | | |
4095 | 79 | exit: |
4096 | 79 | return error; |
4097 | 79 | } |
4098 | | |
4099 | | #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE |
4100 | | template <> otError Interpreter::Process<Cmd("pskcref")>(Arg aArgs[]) |
4101 | | { |
4102 | | otError error = OT_ERROR_NONE; |
4103 | | |
4104 | | /** |
4105 | | * @cli pskcref |
4106 | | * @code |
4107 | | * pskcref |
4108 | | * 0x80000000 |
4109 | | * Done |
4110 | | * @endcode |
4111 | | * @par api_copy |
4112 | | * #otThreadGetPskcRef |
4113 | | */ |
4114 | | if (aArgs[0].IsEmpty()) |
4115 | | { |
4116 | | OutputLine("0x%08lx", ToUlong(otThreadGetPskcRef(GetInstancePtr()))); |
4117 | | } |
4118 | | else |
4119 | | { |
4120 | | /** |
4121 | | * @cli pskcref (set) |
4122 | | * @code |
4123 | | * pskc 0x20017 |
4124 | | * Done |
4125 | | * @endcode |
4126 | | * @cparam pskc @ca{keyref} |
4127 | | * @par api_copy |
4128 | | * #otThreadSetPskcRef |
4129 | | */ |
4130 | | error = ProcessSet(aArgs, otThreadSetPskcRef); |
4131 | | } |
4132 | | |
4133 | | return error; |
4134 | | } |
4135 | | #endif |
4136 | | #endif // OPENTHREAD_FTD |
4137 | | |
4138 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
4139 | | /** |
4140 | | * @cli mleadvimax |
4141 | | * @code |
4142 | | * mleadvimax |
4143 | | * 12000 |
4144 | | * Done |
4145 | | * @endcode |
4146 | | * @par api_copy |
4147 | | * #otThreadGetAdvertisementTrickleIntervalMax |
4148 | | */ |
4149 | | template <> otError Interpreter::Process<Cmd("mleadvimax")>(Arg aArgs[]) |
4150 | | { |
4151 | | return ProcessGet(aArgs, otThreadGetAdvertisementTrickleIntervalMax); |
4152 | | } |
4153 | | #endif |
4154 | | |
4155 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
4156 | | /** |
4157 | | * @cli mliid |
4158 | | * @code |
4159 | | * mliid 1122334455667788 |
4160 | | * Done |
4161 | | * @endcode |
4162 | | * @par |
4163 | | * It must be used before Thread stack is enabled. |
4164 | | * @par |
4165 | | * Only for testing/reference device. |
4166 | | * @par api_copy |
4167 | | * #otIp6SetMeshLocalIid |
4168 | | * @cparam mliid @ca{iid} |
4169 | | */ |
4170 | | template <> otError Interpreter::Process<Cmd("mliid")>(Arg aArgs[]) |
4171 | | { |
4172 | | otError error = OT_ERROR_NONE; |
4173 | | otIp6InterfaceIdentifier iid; |
4174 | | |
4175 | | VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
4176 | | |
4177 | | SuccessOrExit(error = aArgs[0].ParseAsHexString(iid.mFields.m8)); |
4178 | | SuccessOrExit(error = otIp6SetMeshLocalIid(GetInstancePtr(), &iid)); |
4179 | | |
4180 | | exit: |
4181 | | return error; |
4182 | | } |
4183 | | #endif |
4184 | | |
4185 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE |
4186 | | /** |
4187 | | * @cli mlr reg |
4188 | | * @code |
4189 | | * mlr reg ff04::1 |
4190 | | * status 0, 0 failed |
4191 | | * Done |
4192 | | * @endcode |
4193 | | * @code |
4194 | | * mlr reg ff04::1 ff04::2 ff02::1 |
4195 | | * status 2, 1 failed |
4196 | | * ff02:0:0:0:0:0:0:1 |
4197 | | * Done |
4198 | | * @endcode |
4199 | | * @code |
4200 | | * mlr reg ff04::1 ff04::2 1000 |
4201 | | * status 0, 0 failed |
4202 | | * Done |
4203 | | * @endcode |
4204 | | * @code |
4205 | | * mlr reg ff04::1 ff04::2 0 |
4206 | | * status 0, 0 failed |
4207 | | * Done |
4208 | | * @endcode |
4209 | | * @par |
4210 | | * Omit timeout to use the default MLR timeout on the Primary Backbone Router. |
4211 | | * @par |
4212 | | * Use timeout = 0 to deregister Multicast Listeners. |
4213 | | * @par api_copy |
4214 | | * #otIp6RegisterMulticastListeners |
4215 | | * @cparam mlr reg @ca{ipaddr} [@ca{timeout}] |
4216 | | */ |
4217 | | template <> otError Interpreter::Process<Cmd("mlr")>(Arg aArgs[]) |
4218 | 88 | { |
4219 | 88 | otError error = OT_ERROR_INVALID_COMMAND; |
4220 | | |
4221 | 88 | if (aArgs[0] == "reg") |
4222 | 85 | { |
4223 | 85 | otIp6Address addresses[OT_IP6_MAX_MLR_ADDRESSES]; |
4224 | 85 | uint32_t timeout; |
4225 | 85 | bool hasTimeout = false; |
4226 | 85 | uint8_t numAddresses = 0; |
4227 | | |
4228 | 85 | aArgs++; |
4229 | | |
4230 | 335 | while (aArgs->ParseAsIp6Address(addresses[numAddresses]) == OT_ERROR_NONE) |
4231 | 252 | { |
4232 | 252 | aArgs++; |
4233 | 252 | numAddresses++; |
4234 | | |
4235 | 252 | if (numAddresses == OT_ARRAY_LENGTH(addresses)) |
4236 | 2 | { |
4237 | 2 | break; |
4238 | 2 | } |
4239 | 252 | } |
4240 | | |
4241 | 85 | if (aArgs->ParseAsUint32(timeout) == OT_ERROR_NONE) |
4242 | 22 | { |
4243 | 22 | aArgs++; |
4244 | 22 | hasTimeout = true; |
4245 | 22 | } |
4246 | | |
4247 | 85 | VerifyOrExit(aArgs->IsEmpty() && (numAddresses > 0), error = OT_ERROR_INVALID_ARGS); |
4248 | | |
4249 | 27 | SuccessOrExit(error = otIp6RegisterMulticastListeners(GetInstancePtr(), addresses, numAddresses, |
4250 | 27 | hasTimeout ? &timeout : nullptr, |
4251 | 27 | Interpreter::HandleMlrRegResult, this)); |
4252 | | |
4253 | 0 | error = OT_ERROR_PENDING; |
4254 | 0 | } |
4255 | | |
4256 | 88 | exit: |
4257 | 88 | return error; |
4258 | 88 | } |
4259 | | |
4260 | | void Interpreter::HandleMlrRegResult(void *aContext, |
4261 | | otError aError, |
4262 | | uint8_t aMlrStatus, |
4263 | | const otIp6Address *aFailedAddresses, |
4264 | | uint8_t aFailedAddressNum) |
4265 | 0 | { |
4266 | 0 | static_cast<Interpreter *>(aContext)->HandleMlrRegResult(aError, aMlrStatus, aFailedAddresses, aFailedAddressNum); |
4267 | 0 | } |
4268 | | |
4269 | | void Interpreter::HandleMlrRegResult(otError aError, |
4270 | | uint8_t aMlrStatus, |
4271 | | const otIp6Address *aFailedAddresses, |
4272 | | uint8_t aFailedAddressNum) |
4273 | 0 | { |
4274 | 0 | if (aError == OT_ERROR_NONE) |
4275 | 0 | { |
4276 | 0 | OutputLine("status %d, %d failed", aMlrStatus, aFailedAddressNum); |
4277 | |
|
4278 | 0 | for (uint8_t i = 0; i < aFailedAddressNum; i++) |
4279 | 0 | { |
4280 | 0 | OutputIp6AddressLine(aFailedAddresses[i]); |
4281 | 0 | } |
4282 | 0 | } |
4283 | |
|
4284 | 0 | OutputResult(aError); |
4285 | 0 | } |
4286 | | |
4287 | | #endif // (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE |
4288 | | |
4289 | | template <> otError Interpreter::Process<Cmd("mode")>(Arg aArgs[]) |
4290 | 32 | { |
4291 | 32 | otError error = OT_ERROR_NONE; |
4292 | 32 | otLinkModeConfig linkMode; |
4293 | | |
4294 | 32 | ClearAllBytes(linkMode); |
4295 | | |
4296 | 32 | if (aArgs[0].IsEmpty()) |
4297 | 1 | { |
4298 | 1 | char linkModeString[kLinkModeStringSize]; |
4299 | | |
4300 | 1 | OutputLine("%s", LinkModeToString(otThreadGetLinkMode(GetInstancePtr()), linkModeString)); |
4301 | 1 | ExitNow(); |
4302 | 1 | } |
4303 | | |
4304 | | /** |
4305 | | * @cli mode (get,set) |
4306 | | * @code |
4307 | | * mode rdn |
4308 | | * Done |
4309 | | * @endcode |
4310 | | * @code |
4311 | | * mode - |
4312 | | * Done |
4313 | | * @endcode |
4314 | | * @par api_copy |
4315 | | * #otThreadSetLinkMode |
4316 | | * @cparam mode [@ca{rdn}] |
4317 | | * - `-`: no flags set (rx-off-when-idle, minimal Thread device, stable network data) |
4318 | | * - `r`: rx-on-when-idle |
4319 | | * - `d`: Full Thread Device |
4320 | | * - `n`: Full Network Data |
4321 | | */ |
4322 | 31 | if (aArgs[0] != "-") |
4323 | 30 | { |
4324 | 625 | for (const char *arg = aArgs[0].GetCString(); *arg != '\0'; arg++) |
4325 | 596 | { |
4326 | 596 | switch (*arg) |
4327 | 596 | { |
4328 | 196 | case 'r': |
4329 | 196 | linkMode.mRxOnWhenIdle = true; |
4330 | 196 | break; |
4331 | | |
4332 | 196 | case 'd': |
4333 | 196 | linkMode.mDeviceType = true; |
4334 | 196 | break; |
4335 | | |
4336 | 203 | case 'n': |
4337 | 203 | linkMode.mNetworkData = true; |
4338 | 203 | break; |
4339 | | |
4340 | 1 | default: |
4341 | 1 | ExitNow(error = OT_ERROR_INVALID_ARGS); |
4342 | 596 | } |
4343 | 596 | } |
4344 | 30 | } |
4345 | | |
4346 | 30 | error = otThreadSetLinkMode(GetInstancePtr(), linkMode); |
4347 | | |
4348 | 32 | exit: |
4349 | 32 | return error; |
4350 | 30 | } |
4351 | | |
4352 | | /** |
4353 | | * @cli multiradio |
4354 | | * @code |
4355 | | * multiradio |
4356 | | * [15.4, TREL] |
4357 | | * Done |
4358 | | * @endcode |
4359 | | * @par |
4360 | | * Get the list of supported radio links by the device. |
4361 | | * @par |
4362 | | * This command is always available, even when only a single radio is supported by the device. |
4363 | | */ |
4364 | | template <> otError Interpreter::Process<Cmd("multiradio")>(Arg aArgs[]) |
4365 | 2 | { |
4366 | 2 | otError error = OT_ERROR_NONE; |
4367 | | |
4368 | 2 | OT_UNUSED_VARIABLE(aArgs); |
4369 | | |
4370 | 2 | if (aArgs[0].IsEmpty()) |
4371 | 1 | { |
4372 | 1 | bool isFirst = true; |
4373 | | |
4374 | 1 | OutputFormat("["); |
4375 | 1 | #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE |
4376 | 1 | OutputFormat("15.4"); |
4377 | 1 | isFirst = false; |
4378 | 1 | #endif |
4379 | | #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE |
4380 | | OutputFormat("%sTREL", isFirst ? "" : ", "); |
4381 | | #endif |
4382 | 1 | OutputLine("]"); |
4383 | | |
4384 | 1 | OT_UNUSED_VARIABLE(isFirst); |
4385 | 1 | } |
4386 | | #if OPENTHREAD_CONFIG_MULTI_RADIO |
4387 | | else if (aArgs[0] == "neighbor") |
4388 | | { |
4389 | | otMultiRadioNeighborInfo multiRadioInfo; |
4390 | | |
4391 | | /** |
4392 | | * @cli multiradio neighbor list |
4393 | | * @code |
4394 | | * multiradio neighbor list |
4395 | | * ExtAddr:3a65bc38dbe4a5be, RLOC16:0xcc00, Radios:[15.4(255), TREL(255)] |
4396 | | * ExtAddr:17df23452ee4a4be, RLOC16:0x1300, Radios:[15.4(255)] |
4397 | | * Done |
4398 | | * @endcode |
4399 | | * @par api_copy |
4400 | | * #otMultiRadioGetNeighborInfo |
4401 | | */ |
4402 | | if (aArgs[1] == "list") |
4403 | | { |
4404 | | otNeighborInfoIterator iterator = OT_NEIGHBOR_INFO_ITERATOR_INIT; |
4405 | | otNeighborInfo neighInfo; |
4406 | | |
4407 | | while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighInfo) == OT_ERROR_NONE) |
4408 | | { |
4409 | | if (otMultiRadioGetNeighborInfo(GetInstancePtr(), &neighInfo.mExtAddress, &multiRadioInfo) != |
4410 | | OT_ERROR_NONE) |
4411 | | { |
4412 | | continue; |
4413 | | } |
4414 | | |
4415 | | OutputFormat("ExtAddr:"); |
4416 | | OutputExtAddress(neighInfo.mExtAddress); |
4417 | | OutputFormat(", RLOC16:0x%04x, Radios:", neighInfo.mRloc16); |
4418 | | OutputMultiRadioInfo(multiRadioInfo); |
4419 | | } |
4420 | | } |
4421 | | else |
4422 | | { |
4423 | | /** |
4424 | | * @cli multiradio neighbor |
4425 | | * @code |
4426 | | * multiradio neighbor 3a65bc38dbe4a5be |
4427 | | * [15.4(255), TREL(255)] |
4428 | | * Done |
4429 | | * @endcode |
4430 | | * @par api_copy |
4431 | | * #otMultiRadioGetNeighborInfo |
4432 | | * @cparam multiradio neighbor @ca{ext-address} |
4433 | | */ |
4434 | | otExtAddress extAddress; |
4435 | | |
4436 | | SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddress.m8)); |
4437 | | SuccessOrExit(error = otMultiRadioGetNeighborInfo(GetInstancePtr(), &extAddress, &multiRadioInfo)); |
4438 | | OutputMultiRadioInfo(multiRadioInfo); |
4439 | | } |
4440 | | } |
4441 | | #endif // OPENTHREAD_CONFIG_MULTI_RADIO |
4442 | 1 | else |
4443 | 1 | { |
4444 | 1 | ExitNow(error = OT_ERROR_INVALID_COMMAND); |
4445 | 1 | } |
4446 | | |
4447 | 2 | exit: |
4448 | 2 | return error; |
4449 | 2 | } |
4450 | | |
4451 | | #if OPENTHREAD_CONFIG_MULTI_RADIO |
4452 | | void Interpreter::OutputMultiRadioInfo(const otMultiRadioNeighborInfo &aMultiRadioInfo) |
4453 | | { |
4454 | | bool isFirst = true; |
4455 | | |
4456 | | OutputFormat("["); |
4457 | | |
4458 | | if (aMultiRadioInfo.mSupportsIeee802154) |
4459 | | { |
4460 | | OutputFormat("15.4(%u)", aMultiRadioInfo.mIeee802154Info.mPreference); |
4461 | | isFirst = false; |
4462 | | } |
4463 | | |
4464 | | if (aMultiRadioInfo.mSupportsTrelUdp6) |
4465 | | { |
4466 | | OutputFormat("%sTREL(%u)", isFirst ? "" : ", ", aMultiRadioInfo.mTrelUdp6Info.mPreference); |
4467 | | } |
4468 | | |
4469 | | OutputLine("]"); |
4470 | | } |
4471 | | #endif // OPENTHREAD_CONFIG_MULTI_RADIO |
4472 | | |
4473 | | #if OPENTHREAD_FTD |
4474 | | template <> otError Interpreter::Process<Cmd("neighbor")>(Arg aArgs[]) |
4475 | 23 | { |
4476 | 23 | otError error = OT_ERROR_NONE; |
4477 | 23 | otNeighborInfo neighborInfo; |
4478 | 23 | bool isTable; |
4479 | 23 | otNeighborInfoIterator iterator = OT_NEIGHBOR_INFO_ITERATOR_INIT; |
4480 | | |
4481 | 23 | isTable = (aArgs[0] == "table"); |
4482 | | |
4483 | 23 | if (isTable || (aArgs[0] == "list")) |
4484 | 19 | { |
4485 | 19 | if (isTable) |
4486 | 18 | { |
4487 | 18 | static const char *const kNeighborTableTitles[] = { |
4488 | 18 | "Role", "RLOC16", "Age", "Avg RSSI", "Last RSSI", "R", "D", "N", "Extended MAC", "Version", |
4489 | 18 | }; |
4490 | | |
4491 | 18 | static const uint8_t kNeighborTableColumnWidths[] = { |
4492 | 18 | 6, 8, 5, 10, 11, 1, 1, 1, 18, 9, |
4493 | 18 | }; |
4494 | | |
4495 | 18 | OutputTableHeader(kNeighborTableTitles, kNeighborTableColumnWidths); |
4496 | 18 | } |
4497 | | |
4498 | 19 | while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) |
4499 | 0 | { |
4500 | | /** |
4501 | | * @cli neighbor table |
4502 | | * @code |
4503 | | * neighbor table |
4504 | | * | Role | RLOC16 | Age | Avg RSSI | Last RSSI |R|D|N| Extended MAC | |
4505 | | * +------+--------+-----+----------+-----------+-+-+-+------------------+ |
4506 | | * | C | 0xcc01 | 96 | -46 | -46 |1|1|1| 1eb9ba8a6522636b | |
4507 | | * | R | 0xc800 | 2 | -29 | -29 |1|1|1| 9a91556102c39ddb | |
4508 | | * | R | 0xf000 | 3 | -28 | -28 |1|1|1| 0ad7ed6beaa6016d | |
4509 | | * Done |
4510 | | * @endcode |
4511 | | * @par |
4512 | | * Prints information in table format about all neighbors. |
4513 | | * @par |
4514 | | * For `Role`, the only possible values for this table are `C` (Child) or `R` (Router). |
4515 | | * @par |
4516 | | * The following columns provide information about the device mode of neighbors. |
4517 | | * Each column has a value of `0` (off) or `1` (on). |
4518 | | * - `R`: RX on when idle |
4519 | | * - `D`: Full Thread device |
4520 | | * - `N`: Full network data |
4521 | | * @sa otThreadGetNextNeighborInfo |
4522 | | */ |
4523 | 0 | if (isTable) |
4524 | 0 | { |
4525 | 0 | OutputFormat("| %3c ", neighborInfo.mIsChild ? 'C' : 'R'); |
4526 | 0 | OutputFormat("| 0x%04x ", neighborInfo.mRloc16); |
4527 | 0 | OutputFormat("| %3lu ", ToUlong(neighborInfo.mAge)); |
4528 | 0 | OutputFormat("| %8d ", neighborInfo.mAverageRssi); |
4529 | 0 | OutputFormat("| %9d ", neighborInfo.mLastRssi); |
4530 | 0 | OutputFormat("|%1d", neighborInfo.mRxOnWhenIdle); |
4531 | 0 | OutputFormat("|%1d", neighborInfo.mFullThreadDevice); |
4532 | 0 | OutputFormat("|%1d", neighborInfo.mFullNetworkData); |
4533 | 0 | OutputFormat("| "); |
4534 | 0 | OutputExtAddress(neighborInfo.mExtAddress); |
4535 | 0 | OutputLine(" | %7d |", neighborInfo.mVersion); |
4536 | 0 | } |
4537 | | /** |
4538 | | * @cli neighbor list |
4539 | | * @code |
4540 | | * neighbor list |
4541 | | * 0xcc01 0xc800 0xf000 |
4542 | | * Done |
4543 | | * @endcode |
4544 | | * @par |
4545 | | * Lists the RLOC16 of each neighbor. |
4546 | | */ |
4547 | 0 | else |
4548 | 0 | { |
4549 | 0 | OutputFormat("0x%04x ", neighborInfo.mRloc16); |
4550 | 0 | } |
4551 | 0 | } |
4552 | | |
4553 | 19 | OutputNewLine(); |
4554 | 19 | } |
4555 | | /** |
4556 | | * @cli neighbor linkquality |
4557 | | * @code |
4558 | | * neighbor linkquality |
4559 | | * | RLOC16 | Extended MAC | Frame Error | Msg Error | Avg RSS | Last RSS | Age | |
4560 | | * +--------+------------------+-------------+-----------+---------+----------+-------+ |
4561 | | * | 0xe800 | 9e2fa4e1b84f92db | 0.00 % | 0.00 % | -46 | -48 | 1 | |
4562 | | * | 0xc001 | 0ad7ed6beaa6016d | 4.67 % | 0.08 % | -68 | -72 | 10 | |
4563 | | * Done |
4564 | | * @endcode |
4565 | | * @par |
4566 | | * Prints link quality information about all neighbors. |
4567 | | */ |
4568 | 4 | else if (aArgs[0] == "linkquality") |
4569 | 1 | { |
4570 | 1 | static const char *const kLinkQualityTableTitles[] = { |
4571 | 1 | "RLOC16", "Extended MAC", "Frame Error", "Msg Error", "Avg RSS", "Last RSS", "Age", |
4572 | 1 | }; |
4573 | | |
4574 | 1 | static const uint8_t kLinkQualityTableColumnWidths[] = { |
4575 | 1 | 8, 18, 13, 11, 9, 10, 7, |
4576 | 1 | }; |
4577 | | |
4578 | 1 | OutputTableHeader(kLinkQualityTableTitles, kLinkQualityTableColumnWidths); |
4579 | | |
4580 | 1 | while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) |
4581 | 0 | { |
4582 | 0 | PercentageStringBuffer stringBuffer; |
4583 | |
|
4584 | 0 | OutputFormat("| 0x%04x | ", neighborInfo.mRloc16); |
4585 | 0 | OutputExtAddress(neighborInfo.mExtAddress); |
4586 | 0 | OutputFormat(" | %9s %% ", PercentageToString(neighborInfo.mFrameErrorRate, stringBuffer)); |
4587 | 0 | OutputFormat("| %7s %% ", PercentageToString(neighborInfo.mMessageErrorRate, stringBuffer)); |
4588 | 0 | OutputFormat("| %7d ", neighborInfo.mAverageRssi); |
4589 | 0 | OutputFormat("| %8d ", neighborInfo.mLastRssi); |
4590 | 0 | OutputLine("| %5lu |", ToUlong(neighborInfo.mAge)); |
4591 | 0 | } |
4592 | 1 | } |
4593 | | /** |
4594 | | * @cli neighbor conntime |
4595 | | * @code |
4596 | | * neighbor conntime |
4597 | | * | RLOC16 | Extended MAC | Last Heard (Age) | Connection Time | |
4598 | | * +--------+------------------+------------------+------------------+ |
4599 | | * | 0x8401 | 1a28be396a14a318 | 00:00:13 | 00:07:59 | |
4600 | | * | 0x5c00 | 723ebf0d9eba3264 | 00:00:03 | 00:11:27 | |
4601 | | * | 0xe800 | ce53628a1e3f5b3c | 00:00:02 | 00:00:15 | |
4602 | | * Done |
4603 | | * @endcode |
4604 | | * @par |
4605 | | * Prints the connection time and age of neighbors. Information per neighbor: |
4606 | | * - RLOC16 |
4607 | | * - Extended MAC |
4608 | | * - Last Heard (Age): Number of seconds since last heard from neighbor. |
4609 | | * - Connection Time: Number of seconds since link establishment with neighbor. |
4610 | | * Duration intervals are formatted as `{hh}:{mm}:{ss}` for hours, minutes, and seconds if the duration is less |
4611 | | * than one day. If the duration is longer than one day, the format is `{dd}d.{hh}:{mm}:{ss}`. |
4612 | | * @csa{neighbor conntime list} |
4613 | | */ |
4614 | 3 | else if (aArgs[0] == "conntime") |
4615 | 2 | { |
4616 | | /** |
4617 | | * @cli neighbor conntime list |
4618 | | * @code |
4619 | | * neighbor conntime list |
4620 | | * 0x8401 1a28be396a14a318 age:63 conn-time:644 |
4621 | | * 0x5c00 723ebf0d9eba3264 age:23 conn-time:852 |
4622 | | * 0xe800 ce53628a1e3f5b3c age:23 conn-time:180 |
4623 | | * Done |
4624 | | * @endcode |
4625 | | * @par |
4626 | | * Prints the connection time and age of neighbors. |
4627 | | * This command is similar to `neighbor conntime`, but it displays the information in a list format. The age |
4628 | | * and connection time are both displayed in seconds. |
4629 | | * @csa{neighbor conntime} |
4630 | | */ |
4631 | 2 | if (aArgs[1] == "list") |
4632 | 1 | { |
4633 | 1 | isTable = false; |
4634 | 1 | } |
4635 | 1 | else |
4636 | 1 | { |
4637 | 1 | static const char *const kConnTimeTableTitles[] = { |
4638 | 1 | "RLOC16", |
4639 | 1 | "Extended MAC", |
4640 | 1 | "Last Heard (Age)", |
4641 | 1 | "Connection Time", |
4642 | 1 | }; |
4643 | | |
4644 | 1 | static const uint8_t kConnTimeTableColumnWidths[] = {8, 18, 18, 18}; |
4645 | | |
4646 | 1 | isTable = true; |
4647 | 1 | OutputTableHeader(kConnTimeTableTitles, kConnTimeTableColumnWidths); |
4648 | 1 | } |
4649 | | |
4650 | 2 | while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) |
4651 | 0 | { |
4652 | 0 | if (isTable) |
4653 | 0 | { |
4654 | 0 | char string[OT_DURATION_STRING_SIZE]; |
4655 | |
|
4656 | 0 | OutputFormat("| 0x%04x | ", neighborInfo.mRloc16); |
4657 | 0 | OutputExtAddress(neighborInfo.mExtAddress); |
4658 | 0 | otConvertDurationInSecondsToString(neighborInfo.mAge, string, sizeof(string)); |
4659 | 0 | OutputFormat(" | %16s", string); |
4660 | 0 | otConvertDurationInSecondsToString(neighborInfo.mConnectionTime, string, sizeof(string)); |
4661 | 0 | OutputLine(" | %16s |", string); |
4662 | 0 | } |
4663 | 0 | else |
4664 | 0 | { |
4665 | 0 | OutputFormat("0x%04x ", neighborInfo.mRloc16); |
4666 | 0 | OutputExtAddress(neighborInfo.mExtAddress); |
4667 | 0 | OutputLine(" age:%lu conn-time:%lu", ToUlong(neighborInfo.mAge), ToUlong(neighborInfo.mConnectionTime)); |
4668 | 0 | } |
4669 | 0 | } |
4670 | 2 | } |
4671 | 1 | else |
4672 | 1 | { |
4673 | 1 | error = OT_ERROR_INVALID_ARGS; |
4674 | 1 | } |
4675 | | |
4676 | 23 | return error; |
4677 | 23 | } |
4678 | | #endif // OPENTHREAD_FTD |
4679 | | |
4680 | | /** |
4681 | | * @cli netstat |
4682 | | * @code |
4683 | | * netstat |
4684 | | * | Local Address | Peer Address | |
4685 | | * +-------------------------------------------------+-------------------------------------------------+ |
4686 | | * | [0:0:0:0:0:0:0:0]:49153 | [0:0:0:0:0:0:0:0]:0 | |
4687 | | * | [0:0:0:0:0:0:0:0]:49152 | [0:0:0:0:0:0:0:0]:0 | |
4688 | | * | [0:0:0:0:0:0:0:0]:61631 | [0:0:0:0:0:0:0:0]:0 | |
4689 | | * | [0:0:0:0:0:0:0:0]:19788 | [0:0:0:0:0:0:0:0]:0 | |
4690 | | * Done |
4691 | | * @endcode |
4692 | | * @par api_copy |
4693 | | * #otUdpGetSockets |
4694 | | */ |
4695 | | template <> otError Interpreter::Process<Cmd("netstat")>(Arg aArgs[]) |
4696 | 1 | { |
4697 | 1 | OT_UNUSED_VARIABLE(aArgs); |
4698 | | |
4699 | 1 | static const char *const kNetstatTableTitles[] = {"Local Address", "Peer Address"}; |
4700 | 1 | static const uint8_t kNetstatTableColumnWidths[] = {49, 49}; |
4701 | | |
4702 | 1 | char string[OT_IP6_SOCK_ADDR_STRING_SIZE]; |
4703 | | |
4704 | 1 | OutputTableHeader(kNetstatTableTitles, kNetstatTableColumnWidths); |
4705 | | |
4706 | 6 | for (const otUdpSocket *socket = otUdpGetSockets(GetInstancePtr()); socket != nullptr; socket = socket->mNext) |
4707 | 5 | { |
4708 | 5 | otIp6SockAddrToString(&socket->mSockName, string, sizeof(string)); |
4709 | 5 | OutputFormat("| %-47s ", string); |
4710 | 5 | otIp6SockAddrToString(&socket->mPeerName, string, sizeof(string)); |
4711 | 5 | OutputLine("| %-47s |", string); |
4712 | 5 | } |
4713 | | |
4714 | 1 | return OT_ERROR_NONE; |
4715 | 1 | } |
4716 | | |
4717 | | #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
4718 | | template <> otError Interpreter::Process<Cmd("service")>(Arg aArgs[]) |
4719 | 72 | { |
4720 | 72 | otError error = OT_ERROR_INVALID_COMMAND; |
4721 | 72 | otServiceConfig cfg; |
4722 | | |
4723 | 72 | if (aArgs[0].IsEmpty()) |
4724 | 1 | { |
4725 | 1 | otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
4726 | 1 | otServiceConfig config; |
4727 | | |
4728 | 1 | while (otServerGetNextService(GetInstancePtr(), &iterator, &config) == OT_ERROR_NONE) |
4729 | 0 | { |
4730 | 0 | mNetworkData.OutputService(config); |
4731 | 0 | } |
4732 | | |
4733 | 1 | error = OT_ERROR_NONE; |
4734 | 1 | } |
4735 | 71 | else |
4736 | 71 | { |
4737 | 71 | uint16_t length; |
4738 | | |
4739 | 71 | SuccessOrExit(error = aArgs[1].ParseAsUint32(cfg.mEnterpriseNumber)); |
4740 | | |
4741 | 70 | length = sizeof(cfg.mServiceData); |
4742 | 70 | SuccessOrExit(error = aArgs[2].ParseAsHexString(length, cfg.mServiceData)); |
4743 | 66 | VerifyOrExit(length > 0, error = OT_ERROR_INVALID_ARGS); |
4744 | 66 | cfg.mServiceDataLength = static_cast<uint8_t>(length); |
4745 | | |
4746 | | /** |
4747 | | * @cli service add |
4748 | | * @code |
4749 | | * service add 44970 112233 aabbcc |
4750 | | * Done |
4751 | | * @endcode |
4752 | | * @code |
4753 | | * netdata register |
4754 | | * Done |
4755 | | * @endcode |
4756 | | * @cparam service add @ca{enterpriseNumber} @ca{serviceData} [@ca{serverData}] |
4757 | | * @par |
4758 | | * Adds service to the network data. |
4759 | | * @par |
4760 | | * - enterpriseNumber: IANA enterprise number |
4761 | | * - serviceData: Hex-encoded binary service data |
4762 | | * - serverData: Hex-encoded binary server data (empty if not provided) |
4763 | | * @par |
4764 | | * Note: For each change in service registration to take effect, run |
4765 | | * the `netdata register` command after running the `service add` command to notify the leader. |
4766 | | * @sa otServerAddService |
4767 | | * @csa{netdata register} |
4768 | | */ |
4769 | 66 | if (aArgs[0] == "add") |
4770 | 59 | { |
4771 | 59 | if (!aArgs[3].IsEmpty()) |
4772 | 4 | { |
4773 | 4 | length = sizeof(cfg.mServerConfig.mServerData); |
4774 | 4 | SuccessOrExit(error = aArgs[3].ParseAsHexString(length, cfg.mServerConfig.mServerData)); |
4775 | 3 | VerifyOrExit(length > 0, error = OT_ERROR_INVALID_ARGS); |
4776 | 3 | cfg.mServerConfig.mServerDataLength = static_cast<uint8_t>(length); |
4777 | 3 | } |
4778 | 55 | else |
4779 | 55 | { |
4780 | 55 | cfg.mServerConfig.mServerDataLength = 0; |
4781 | 55 | } |
4782 | | |
4783 | 58 | cfg.mServerConfig.mStable = true; |
4784 | | |
4785 | 58 | error = otServerAddService(GetInstancePtr(), &cfg); |
4786 | 58 | } |
4787 | | /** |
4788 | | * @cli service remove |
4789 | | * @code |
4790 | | * service remove 44970 112233 |
4791 | | * Done |
4792 | | * @endcode |
4793 | | * @code |
4794 | | * netdata register |
4795 | | * Done |
4796 | | * @endcode |
4797 | | * @cparam service remove @ca{enterpriseNumber} @ca{serviceData} |
4798 | | * @par |
4799 | | * Removes service from the network data. |
4800 | | * @par |
4801 | | * - enterpriseNumber: IANA enterprise number |
4802 | | * - serviceData: Hex-encoded binary service data |
4803 | | * @par |
4804 | | * Note: For each change in service registration to take effect, run |
4805 | | * the `netdata register` command after running the `service remove` command to notify the leader. |
4806 | | * @sa otServerRemoveService |
4807 | | * @csa{netdata register} |
4808 | | */ |
4809 | 7 | else if (aArgs[0] == "remove") |
4810 | 1 | { |
4811 | 1 | error = otServerRemoveService(GetInstancePtr(), cfg.mEnterpriseNumber, cfg.mServiceData, |
4812 | 1 | cfg.mServiceDataLength); |
4813 | 1 | } |
4814 | 66 | } |
4815 | | |
4816 | 72 | exit: |
4817 | 72 | return error; |
4818 | 72 | } |
4819 | | #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
4820 | | |
4821 | 170 | template <> otError Interpreter::Process<Cmd("netdata")>(Arg aArgs[]) { return mNetworkData.Process(aArgs); } |
4822 | | |
4823 | | #if OPENTHREAD_FTD |
4824 | | /** |
4825 | | * @cli networkidtimeout (get,set) |
4826 | | * @code |
4827 | | * networkidtimeout 120 |
4828 | | * Done |
4829 | | * @endcode |
4830 | | * @code |
4831 | | * networkidtimeout |
4832 | | * 120 |
4833 | | * Done |
4834 | | * @endcode |
4835 | | * @cparam networkidtimeout [@ca{timeout}] |
4836 | | * Use the optional `timeout` argument to set the value of the `NETWORK_ID_TIMEOUT` parameter. |
4837 | | * @par |
4838 | | * Gets or sets the `NETWORK_ID_TIMEOUT` parameter. |
4839 | | * @note This command is reserved for testing and demo purposes only. |
4840 | | * Changing settings with this API will render a production application |
4841 | | * non-compliant with the Thread Specification. |
4842 | | * @sa otThreadGetNetworkIdTimeout |
4843 | | * @sa otThreadSetNetworkIdTimeout |
4844 | | */ |
4845 | | template <> otError Interpreter::Process<Cmd("networkidtimeout")>(Arg aArgs[]) |
4846 | 4 | { |
4847 | 4 | return ProcessGetSet(aArgs, otThreadGetNetworkIdTimeout, otThreadSetNetworkIdTimeout); |
4848 | 4 | } |
4849 | | #endif |
4850 | | |
4851 | | template <> otError Interpreter::Process<Cmd("networkkey")>(Arg aArgs[]) |
4852 | 3 | { |
4853 | 3 | otError error = OT_ERROR_NONE; |
4854 | | |
4855 | | /** |
4856 | | * @cli networkkey |
4857 | | * @code |
4858 | | * networkkey |
4859 | | * 00112233445566778899aabbccddeeff |
4860 | | * Done |
4861 | | * @endcode |
4862 | | * @par api_copy |
4863 | | * #otThreadGetNetworkKey |
4864 | | */ |
4865 | 3 | if (aArgs[0].IsEmpty()) |
4866 | 1 | { |
4867 | 1 | otNetworkKey networkKey; |
4868 | | |
4869 | 1 | otThreadGetNetworkKey(GetInstancePtr(), &networkKey); |
4870 | 1 | OutputBytesLine(networkKey.m8); |
4871 | 1 | } |
4872 | | /** |
4873 | | * @cli networkkey (key) |
4874 | | * @code |
4875 | | * networkkey 00112233445566778899aabbccddeeff |
4876 | | * Done |
4877 | | * @endcode |
4878 | | * @par api_copy |
4879 | | * #otThreadSetNetworkKey |
4880 | | * @cparam networkkey @ca{key} |
4881 | | */ |
4882 | 2 | else |
4883 | 2 | { |
4884 | 2 | otNetworkKey key; |
4885 | | |
4886 | 2 | SuccessOrExit(error = aArgs[0].ParseAsHexString(key.m8)); |
4887 | 1 | SuccessOrExit(error = otThreadSetNetworkKey(GetInstancePtr(), &key)); |
4888 | 1 | } |
4889 | | |
4890 | 3 | exit: |
4891 | 3 | return error; |
4892 | 3 | } |
4893 | | |
4894 | | #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE |
4895 | | template <> otError Interpreter::Process<Cmd("networkkeyref")>(Arg aArgs[]) |
4896 | | { |
4897 | | otError error = OT_ERROR_NONE; |
4898 | | |
4899 | | if (aArgs[0].IsEmpty()) |
4900 | | { |
4901 | | OutputLine("0x%08lx", ToUlong(otThreadGetNetworkKeyRef(GetInstancePtr()))); |
4902 | | } |
4903 | | else |
4904 | | { |
4905 | | error = ProcessSet(aArgs, otThreadSetNetworkKeyRef); |
4906 | | } |
4907 | | |
4908 | | return error; |
4909 | | } |
4910 | | #endif |
4911 | | |
4912 | | /** |
4913 | | * @cli networkname |
4914 | | * @code |
4915 | | * networkname |
4916 | | * OpenThread |
4917 | | * Done |
4918 | | * @endcode |
4919 | | * @par api_copy |
4920 | | * #otThreadGetNetworkName |
4921 | | */ |
4922 | | template <> otError Interpreter::Process<Cmd("networkname")>(Arg aArgs[]) |
4923 | 3 | { |
4924 | | /** |
4925 | | * @cli networkname (name) |
4926 | | * @code |
4927 | | * networkname OpenThread |
4928 | | * Done |
4929 | | * @endcode |
4930 | | * @par api_copy |
4931 | | * #otThreadSetNetworkName |
4932 | | * @cparam networkname @ca{name} |
4933 | | * @par |
4934 | | * Note: The current commissioning credential becomes stale after changing this value. Use `pskc` to reset. |
4935 | | */ |
4936 | 3 | return ProcessGetSet(aArgs, otThreadGetNetworkName, otThreadSetNetworkName); |
4937 | 3 | } |
4938 | | |
4939 | | #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE |
4940 | | template <> otError Interpreter::Process<Cmd("networktime")>(Arg aArgs[]) |
4941 | | { |
4942 | | otError error = OT_ERROR_NONE; |
4943 | | |
4944 | | /** |
4945 | | * @cli networktime |
4946 | | * @code |
4947 | | * networktime |
4948 | | * Network Time: 21084154us (synchronized) |
4949 | | * Time Sync Period: 100s |
4950 | | * XTAL Threshold: 300ppm |
4951 | | * Done |
4952 | | * @endcode |
4953 | | * @par |
4954 | | * Gets the Thread network time and the time sync parameters. |
4955 | | * @sa otNetworkTimeGet |
4956 | | * @sa otNetworkTimeGetSyncPeriod |
4957 | | * @sa otNetworkTimeGetXtalThreshold |
4958 | | */ |
4959 | | if (aArgs[0].IsEmpty()) |
4960 | | { |
4961 | | uint64_t time; |
4962 | | otNetworkTimeStatus networkTimeStatus; |
4963 | | |
4964 | | networkTimeStatus = otNetworkTimeGet(GetInstancePtr(), &time); |
4965 | | |
4966 | | OutputFormat("Network Time: "); |
4967 | | OutputUint64(time); |
4968 | | OutputFormat("us"); |
4969 | | |
4970 | | switch (networkTimeStatus) |
4971 | | { |
4972 | | case OT_NETWORK_TIME_UNSYNCHRONIZED: |
4973 | | OutputLine(" (unsynchronized)"); |
4974 | | break; |
4975 | | |
4976 | | case OT_NETWORK_TIME_RESYNC_NEEDED: |
4977 | | OutputLine(" (resync needed)"); |
4978 | | break; |
4979 | | |
4980 | | case OT_NETWORK_TIME_SYNCHRONIZED: |
4981 | | OutputLine(" (synchronized)"); |
4982 | | break; |
4983 | | |
4984 | | default: |
4985 | | break; |
4986 | | } |
4987 | | |
4988 | | OutputLine("Time Sync Period: %us", otNetworkTimeGetSyncPeriod(GetInstancePtr())); |
4989 | | OutputLine("XTAL Threshold: %uppm", otNetworkTimeGetXtalThreshold(GetInstancePtr())); |
4990 | | } |
4991 | | /** |
4992 | | * @cli networktime (set) |
4993 | | * @code |
4994 | | * networktime 100 300 |
4995 | | * Done |
4996 | | * @endcode |
4997 | | * @cparam networktime @ca{timesyncperiod} @ca{xtalthreshold} |
4998 | | * @par |
4999 | | * Sets the time sync parameters. |
5000 | | * * `timesyncperiod`: The time synchronization period, in seconds. |
5001 | | * * `xtalthreshold`: The XTAL accuracy threshold for a device to become Router-Capable device, in PPM. |
5002 | | * @sa otNetworkTimeSetSyncPeriod |
5003 | | * @sa otNetworkTimeSetXtalThreshold |
5004 | | */ |
5005 | | else |
5006 | | { |
5007 | | uint16_t period; |
5008 | | uint16_t xtalThreshold; |
5009 | | |
5010 | | SuccessOrExit(error = aArgs[0].ParseAsUint16(period)); |
5011 | | SuccessOrExit(error = aArgs[1].ParseAsUint16(xtalThreshold)); |
5012 | | SuccessOrExit(error = otNetworkTimeSetSyncPeriod(GetInstancePtr(), period)); |
5013 | | SuccessOrExit(error = otNetworkTimeSetXtalThreshold(GetInstancePtr(), xtalThreshold)); |
5014 | | } |
5015 | | |
5016 | | exit: |
5017 | | return error; |
5018 | | } |
5019 | | #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE |
5020 | | |
5021 | | #if OPENTHREAD_FTD |
5022 | | template <> otError Interpreter::Process<Cmd("nexthop")>(Arg aArgs[]) |
5023 | 24 | { |
5024 | 24 | constexpr uint8_t kRouterIdOffset = 10; // Bit offset of Router ID in RLOC16 |
5025 | 24 | constexpr uint16_t kInvalidRloc16 = 0xfffe; |
5026 | | |
5027 | 24 | otError error = OT_ERROR_NONE; |
5028 | 24 | uint16_t destRloc16; |
5029 | 24 | uint16_t nextHopRloc16; |
5030 | 24 | uint8_t pathCost; |
5031 | | |
5032 | | /** |
5033 | | * @cli nexthop |
5034 | | * @code |
5035 | | * nexthop |
5036 | | * | ID |NxtHop| Cost | |
5037 | | * +------+------+------+ |
5038 | | * | 9 | 9 | 1 | |
5039 | | * | 25 | 25 | 0 | |
5040 | | * | 30 | 30 | 1 | |
5041 | | * | 46 | - | - | |
5042 | | * | 50 | 30 | 3 | |
5043 | | * | 60 | 30 | 2 | |
5044 | | * Done |
5045 | | * @endcode |
5046 | | * @par |
5047 | | * Output table of allocated Router IDs and current next hop and path |
5048 | | * cost for each router. |
5049 | | * @sa otThreadGetNextHopAndPathCost |
5050 | | * @sa otThreadIsRouterIdAllocated |
5051 | | */ |
5052 | 24 | if (aArgs[0].IsEmpty()) |
5053 | 18 | { |
5054 | 18 | static const char *const kNextHopTableTitles[] = { |
5055 | 18 | "ID", |
5056 | 18 | "NxtHop", |
5057 | 18 | "Cost", |
5058 | 18 | }; |
5059 | | |
5060 | 18 | static const uint8_t kNextHopTableColumnWidths[] = { |
5061 | 18 | 6, |
5062 | 18 | 6, |
5063 | 18 | 6, |
5064 | 18 | }; |
5065 | | |
5066 | 18 | OutputTableHeader(kNextHopTableTitles, kNextHopTableColumnWidths); |
5067 | | |
5068 | 1.15k | for (uint8_t routerId = 0; routerId <= OT_NETWORK_MAX_ROUTER_ID; routerId++) |
5069 | 1.13k | { |
5070 | 1.13k | if (!otThreadIsRouterIdAllocated(GetInstancePtr(), routerId)) |
5071 | 1.13k | { |
5072 | 1.13k | continue; |
5073 | 1.13k | } |
5074 | | |
5075 | 0 | destRloc16 = routerId; |
5076 | 0 | destRloc16 <<= kRouterIdOffset; |
5077 | |
|
5078 | 0 | otThreadGetNextHopAndPathCost(GetInstancePtr(), destRloc16, &nextHopRloc16, &pathCost); |
5079 | |
|
5080 | 0 | OutputFormat("| %4u | ", routerId); |
5081 | |
|
5082 | 0 | if (nextHopRloc16 != kInvalidRloc16) |
5083 | 0 | { |
5084 | 0 | OutputLine("%4u | %4u |", nextHopRloc16 >> kRouterIdOffset, pathCost); |
5085 | 0 | } |
5086 | 0 | else |
5087 | 0 | { |
5088 | 0 | OutputLine("%4s | %4s |", "-", "-"); |
5089 | 0 | } |
5090 | 0 | } |
5091 | 18 | } |
5092 | | /** |
5093 | | * @cli nexthop (get) |
5094 | | * @code |
5095 | | * nexthop 0xc000 |
5096 | | * 0xc000 cost:0 |
5097 | | * Done |
5098 | | * @endcode |
5099 | | * @code |
5100 | | * nexthop 0x8001 |
5101 | | * 0x2000 cost:3 |
5102 | | * Done |
5103 | | * @endcode |
5104 | | * @cparam nexthop @ca{rloc16} |
5105 | | * @par api_copy |
5106 | | * #otThreadGetNextHopAndPathCost |
5107 | | */ |
5108 | 6 | else |
5109 | 6 | { |
5110 | 6 | SuccessOrExit(error = aArgs[0].ParseAsUint16(destRloc16)); |
5111 | 1 | otThreadGetNextHopAndPathCost(GetInstancePtr(), destRloc16, &nextHopRloc16, &pathCost); |
5112 | 1 | OutputLine("0x%04x cost:%u", nextHopRloc16, pathCost); |
5113 | 1 | } |
5114 | | |
5115 | 24 | exit: |
5116 | 24 | return error; |
5117 | 24 | } |
5118 | | |
5119 | | #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE |
5120 | | |
5121 | 34 | template <> otError Interpreter::Process<Cmd("meshdiag")>(Arg aArgs[]) { return mMeshDiag.Process(aArgs); } |
5122 | | |
5123 | | #endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE |
5124 | | |
5125 | | #endif // OPENTHREAD_FTD |
5126 | | |
5127 | | template <> otError Interpreter::Process<Cmd("panid")>(Arg aArgs[]) |
5128 | 31 | { |
5129 | 31 | otError error = OT_ERROR_NONE; |
5130 | | /** |
5131 | | * @cli panid |
5132 | | * @code |
5133 | | * panid |
5134 | | * 0xdead |
5135 | | * Done |
5136 | | * @endcode |
5137 | | * @par api_copy |
5138 | | * #otLinkGetPanId |
5139 | | */ |
5140 | 31 | if (aArgs[0].IsEmpty()) |
5141 | 17 | { |
5142 | 17 | OutputLine("0x%04x", otLinkGetPanId(GetInstancePtr())); |
5143 | 17 | } |
5144 | | /** |
5145 | | * @cli panid (panid) |
5146 | | * @code |
5147 | | * panid 0xdead |
5148 | | * Done |
5149 | | * @endcode |
5150 | | * @par api_copy |
5151 | | * #otLinkSetPanId |
5152 | | * @cparam panid @ca{panid} |
5153 | | */ |
5154 | 14 | else |
5155 | 14 | { |
5156 | 14 | error = ProcessSet(aArgs, otLinkSetPanId); |
5157 | 14 | } |
5158 | | |
5159 | 31 | return error; |
5160 | 31 | } |
5161 | | |
5162 | | template <> otError Interpreter::Process<Cmd("parent")>(Arg aArgs[]) |
5163 | 3 | { |
5164 | 3 | otError error = OT_ERROR_NONE; |
5165 | | /** |
5166 | | * @cli parent |
5167 | | * @code |
5168 | | * parent |
5169 | | * Ext Addr: be1857c6c21dce55 |
5170 | | * Rloc: 5c00 |
5171 | | * Link Quality In: 3 |
5172 | | * Link Quality Out: 3 |
5173 | | * Age: 20 |
5174 | | * Version: 4 |
5175 | | * Done |
5176 | | * @endcode |
5177 | | * @sa otThreadGetParentInfo |
5178 | | * @par |
5179 | | * Get the diagnostic information for a Thread Router as parent. |
5180 | | * @par |
5181 | | * When operating as a Thread Router when OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE is enabled, this command |
5182 | | * will return the cached information from when the device was previously attached as a Thread Child. Returning |
5183 | | * cached information is necessary to support the Thread Test Harness - Test Scenario 8.2.x requests the former |
5184 | | * parent (i.e. %Joiner Router's) MAC address even if the device has already promoted to a router. |
5185 | | * @par |
5186 | | * Note: When OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE is enabled, this command will return two extra lines with |
5187 | | * information relevant for CSL Receiver operation. |
5188 | | */ |
5189 | 3 | if (aArgs[0].IsEmpty()) |
5190 | 1 | { |
5191 | 1 | otRouterInfo parentInfo; |
5192 | | |
5193 | 1 | SuccessOrExit(error = otThreadGetParentInfo(GetInstancePtr(), &parentInfo)); |
5194 | 0 | OutputFormat("Ext Addr: "); |
5195 | 0 | OutputExtAddressLine(parentInfo.mExtAddress); |
5196 | 0 | OutputLine("Rloc: %x", parentInfo.mRloc16); |
5197 | 0 | OutputLine("Link Quality In: %u", parentInfo.mLinkQualityIn); |
5198 | 0 | OutputLine("Link Quality Out: %u", parentInfo.mLinkQualityOut); |
5199 | 0 | OutputLine("Age: %lu", ToUlong(parentInfo.mAge)); |
5200 | 0 | OutputLine("Version: %u", parentInfo.mVersion); |
5201 | | #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
5202 | | OutputLine("CSL clock accuracy: %u", parentInfo.mCslClockAccuracy); |
5203 | | OutputLine("CSL uncertainty: %u", parentInfo.mCslUncertainty); |
5204 | | #endif |
5205 | 0 | } |
5206 | | /** |
5207 | | * @cli parent search |
5208 | | * @code |
5209 | | * parent search |
5210 | | * Done |
5211 | | * @endcode |
5212 | | * @par api_copy |
5213 | | * #otThreadSearchForBetterParent |
5214 | | */ |
5215 | 2 | else if (aArgs[0] == "search") |
5216 | 1 | { |
5217 | 1 | error = otThreadSearchForBetterParent(GetInstancePtr()); |
5218 | 1 | } |
5219 | 1 | else |
5220 | 1 | { |
5221 | 1 | error = OT_ERROR_INVALID_ARGS; |
5222 | 1 | } |
5223 | | |
5224 | 3 | exit: |
5225 | 3 | return error; |
5226 | 3 | } |
5227 | | |
5228 | | #if OPENTHREAD_FTD |
5229 | | /** |
5230 | | * @cli parentpriority (get,set) |
5231 | | * @code |
5232 | | * parentpriority |
5233 | | * 1 |
5234 | | * Done |
5235 | | * @endcode |
5236 | | * @code |
5237 | | * parentpriority 1 |
5238 | | * Done |
5239 | | * @endcode |
5240 | | * @cparam parentpriority [@ca{parentpriority}] |
5241 | | * @par |
5242 | | * Gets or sets the assigned parent priority value: 1, 0, -1 or -2. -2 means not assigned. |
5243 | | * @sa otThreadGetParentPriority |
5244 | | * @sa otThreadSetParentPriority |
5245 | | */ |
5246 | | template <> otError Interpreter::Process<Cmd("parentpriority")>(Arg aArgs[]) |
5247 | 15 | { |
5248 | 15 | return ProcessGetSet(aArgs, otThreadGetParentPriority, otThreadSetParentPriority); |
5249 | 15 | } |
5250 | | #endif |
5251 | | |
5252 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
5253 | | template <> otError Interpreter::Process<Cmd("routeridrange")>(Arg *aArgs) |
5254 | | { |
5255 | | uint8_t minRouterId; |
5256 | | uint8_t maxRouterId; |
5257 | | otError error = OT_ERROR_NONE; |
5258 | | |
5259 | | if (aArgs[0].IsEmpty()) |
5260 | | { |
5261 | | otThreadGetRouterIdRange(GetInstancePtr(), &minRouterId, &maxRouterId); |
5262 | | OutputLine("%u %u", minRouterId, maxRouterId); |
5263 | | } |
5264 | | else |
5265 | | { |
5266 | | SuccessOrExit(error = aArgs[0].ParseAsUint8(minRouterId)); |
5267 | | SuccessOrExit(error = aArgs[1].ParseAsUint8(maxRouterId)); |
5268 | | VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
5269 | | error = otThreadSetRouterIdRange(GetInstancePtr(), minRouterId, maxRouterId); |
5270 | | } |
5271 | | |
5272 | | exit: |
5273 | | return error; |
5274 | | } |
5275 | | #endif |
5276 | | |
5277 | | #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE |
5278 | | /** |
5279 | | * @cli ping |
5280 | | * @code |
5281 | | * ping fd00:db8:0:0:76b:6a05:3ae9:a61a |
5282 | | * 16 bytes from fd00:db8:0:0:76b:6a05:3ae9:a61a: icmp_seq=5 hlim=64 time=0ms |
5283 | | * 1 packets transmitted, 1 packets received. Packet loss = 0.0%. Round-trip min/avg/max = 0/0.0/0 ms. |
5284 | | * Done |
5285 | | * @endcode |
5286 | | * @code |
5287 | | * ping -I fd00:db8:0:0:76b:6a05:3ae9:a61a ff02::1 100 1 1 1 |
5288 | | * 108 bytes from fd00:db8:0:0:f605:fb4b:d429:d59a: icmp_seq=4 hlim=64 time=7ms |
5289 | | * 1 packets transmitted, 1 packets received. Round-trip min/avg/max = 7/7.0/7 ms. |
5290 | | * Done |
5291 | | * @endcode |
5292 | | * @code |
5293 | | * ping 172.17.0.1 |
5294 | | * Pinging synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1 |
5295 | | * 16 bytes from fdde:ad00:beef:2:0:0:ac11:1: icmp_seq=5 hlim=64 time=0ms |
5296 | | * 1 packets transmitted, 1 packets received. Packet loss = 0.0%. Round-trip min/avg/max = 0/0.0/0 ms. |
5297 | | * Done |
5298 | | * @endcode |
5299 | | * @cparam ping [@ca{async}] [@ca{-I source}] [@ca{-m}] @ca{ipaddrc} [@ca{size}] [@ca{count}] <!-- |
5300 | | * --> [@ca{interval}] [@ca{hoplimit}] [@ca{timeout}] |
5301 | | * @par |
5302 | | * Send an ICMPv6 Echo Request. |
5303 | | * @par |
5304 | | * The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix |
5305 | | * from the network data. |
5306 | | * @par |
5307 | | * The optional `-m` flag sets the multicast loop flag, which allows looping back pings to multicast addresses that the |
5308 | | * device itself is subscribed to. |
5309 | | * @par |
5310 | | * Note: The command will return InvalidState when the preferred NAT64 prefix is unavailable. |
5311 | | * @sa otPingSenderPing |
5312 | | */ |
5313 | 814 | template <> otError Interpreter::Process<Cmd("ping")>(Arg aArgs[]) { return mPing.Process(aArgs); } |
5314 | | #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE |
5315 | | |
5316 | | /** |
5317 | | * @cli platform |
5318 | | * @code |
5319 | | * platform |
5320 | | * NRF52840 |
5321 | | * Done |
5322 | | * @endcode |
5323 | | * @par |
5324 | | * Print the current platform |
5325 | | */ |
5326 | | template <> otError Interpreter::Process<Cmd("platform")>(Arg aArgs[]) |
5327 | 1 | { |
5328 | 1 | OT_UNUSED_VARIABLE(aArgs); |
5329 | 1 | OutputLine("%s", OPENTHREAD_CONFIG_PLATFORM_INFO); |
5330 | 1 | return OT_ERROR_NONE; |
5331 | 1 | } |
5332 | | |
5333 | | /** |
5334 | | * @cli pollperiod (get,set) |
5335 | | * @code |
5336 | | * pollperiod |
5337 | | * 0 |
5338 | | * Done |
5339 | | * @endcode |
5340 | | * @code |
5341 | | * pollperiod 10 |
5342 | | * Done |
5343 | | * @endcode |
5344 | | * @sa otLinkGetPollPeriod |
5345 | | * @sa otLinkSetPollPeriod |
5346 | | * @par |
5347 | | * Get or set the customized data poll period of sleepy end device (milliseconds). Only for certification test. |
5348 | | */ |
5349 | | template <> otError Interpreter::Process<Cmd("pollperiod")>(Arg aArgs[]) |
5350 | 97 | { |
5351 | 97 | return ProcessGetSet(aArgs, otLinkGetPollPeriod, otLinkSetPollPeriod); |
5352 | 97 | } |
5353 | | |
5354 | | template <> otError Interpreter::Process<Cmd("promiscuous")>(Arg aArgs[]) |
5355 | 4 | { |
5356 | 4 | otError error = OT_ERROR_NONE; |
5357 | | |
5358 | | /** |
5359 | | * @cli promiscuous |
5360 | | * @code |
5361 | | * promiscuous |
5362 | | * Disabled |
5363 | | * Done |
5364 | | * @endcode |
5365 | | * @par api_copy |
5366 | | * #otLinkIsPromiscuous |
5367 | | * @sa otPlatRadioGetPromiscuous |
5368 | | */ |
5369 | 4 | if (aArgs[0].IsEmpty()) |
5370 | 1 | { |
5371 | 1 | OutputEnabledDisabledStatus(otLinkIsPromiscuous(GetInstancePtr()) && |
5372 | 1 | otPlatRadioGetPromiscuous(GetInstancePtr())); |
5373 | 1 | } |
5374 | 3 | else |
5375 | 3 | { |
5376 | 3 | bool enable; |
5377 | | |
5378 | 3 | SuccessOrExit(error = ParseEnableOrDisable(aArgs[0], enable)); |
5379 | | |
5380 | | /** |
5381 | | * @cli promiscuous (enable,disable) |
5382 | | * @code |
5383 | | * promiscuous enable |
5384 | | * Done |
5385 | | * @endcode |
5386 | | * @code |
5387 | | * promiscuous disable |
5388 | | * Done |
5389 | | * @endcode |
5390 | | * @cparam promiscuous @ca{enable|disable} |
5391 | | * @par api_copy |
5392 | | * #otLinkSetPromiscuous |
5393 | | */ |
5394 | 2 | if (!enable) |
5395 | 1 | { |
5396 | 1 | otLinkSetPcapCallback(GetInstancePtr(), nullptr, nullptr); |
5397 | 1 | } |
5398 | | |
5399 | 2 | SuccessOrExit(error = otLinkSetPromiscuous(GetInstancePtr(), enable)); |
5400 | | |
5401 | 0 | if (enable) |
5402 | 0 | { |
5403 | 0 | otLinkSetPcapCallback(GetInstancePtr(), &HandleLinkPcapReceive, this); |
5404 | 0 | } |
5405 | 0 | } |
5406 | | |
5407 | 4 | exit: |
5408 | 4 | return error; |
5409 | 4 | } |
5410 | | |
5411 | | void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx, void *aContext) |
5412 | 0 | { |
5413 | 0 | static_cast<Interpreter *>(aContext)->HandleLinkPcapReceive(aFrame, aIsTx); |
5414 | 0 | } |
5415 | | |
5416 | | void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx) |
5417 | 0 | { |
5418 | 0 | otLogHexDumpInfo info; |
5419 | |
|
5420 | 0 | info.mDataBytes = aFrame->mPsdu; |
5421 | 0 | info.mDataLength = aFrame->mLength; |
5422 | 0 | info.mTitle = (aIsTx) ? "TX" : "RX"; |
5423 | 0 | info.mIterator = 0; |
5424 | |
|
5425 | 0 | OutputNewLine(); |
5426 | |
|
5427 | 0 | while (otLogGenerateNextHexDumpLine(&info) == OT_ERROR_NONE) |
5428 | 0 | { |
5429 | 0 | OutputLine("%s", info.mLine); |
5430 | 0 | } |
5431 | 0 | } |
5432 | | |
5433 | | #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
5434 | | template <> otError Interpreter::Process<Cmd("prefix")>(Arg aArgs[]) |
5435 | 138 | { |
5436 | 138 | otError error = OT_ERROR_NONE; |
5437 | | |
5438 | | /** |
5439 | | * @cli prefix |
5440 | | * @code |
5441 | | * prefix |
5442 | | * 2001:dead:beef:cafe::/64 paros med |
5443 | | * - fd00:7d03:7d03:7d03::/64 prosD med |
5444 | | * Done |
5445 | | * @endcode |
5446 | | * @par |
5447 | | * Get the prefix list in the local Network Data. |
5448 | | * @note For the Thread 1.2 border router with backbone capability, the local Domain Prefix |
5449 | | * is listed as well and includes the `D` flag. If backbone functionality is disabled, a dash |
5450 | | * `-` is printed before the local Domain Prefix. |
5451 | | * @par |
5452 | | * For more information about #otBorderRouterConfig flags, refer to @overview. |
5453 | | * @sa otBorderRouterGetNextOnMeshPrefix |
5454 | | */ |
5455 | 138 | if (aArgs[0].IsEmpty()) |
5456 | 1 | { |
5457 | 1 | otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
5458 | 1 | otBorderRouterConfig config; |
5459 | | |
5460 | 1 | while (otBorderRouterGetNextOnMeshPrefix(GetInstancePtr(), &iterator, &config) == OT_ERROR_NONE) |
5461 | 0 | { |
5462 | 0 | mNetworkData.OutputPrefix(config); |
5463 | 0 | } |
5464 | | |
5465 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE |
5466 | | if (otBackboneRouterGetState(GetInstancePtr()) == OT_BACKBONE_ROUTER_STATE_DISABLED) |
5467 | | { |
5468 | | SuccessOrExit(otBackboneRouterGetDomainPrefix(GetInstancePtr(), &config)); |
5469 | | OutputFormat("- "); |
5470 | | mNetworkData.OutputPrefix(config); |
5471 | | } |
5472 | | #endif |
5473 | 1 | } |
5474 | | /** |
5475 | | * @cli prefix add |
5476 | | * @code |
5477 | | * prefix add 2001:dead:beef:cafe::/64 paros med |
5478 | | * Done |
5479 | | * @endcode |
5480 | | * @code |
5481 | | * prefix add fd00:7d03:7d03:7d03::/64 prosD low |
5482 | | * Done |
5483 | | * @endcode |
5484 | | * @cparam prefix add @ca{prefix} [@ca{padcrosnD}] [@ca{high}|@ca{med}|@ca{low}] |
5485 | | * OT CLI uses mapped arguments to configure #otBorderRouterConfig values. @moreinfo{the @overview}. |
5486 | | * @par |
5487 | | * Adds a valid prefix to the Network Data. |
5488 | | * @sa otBorderRouterAddOnMeshPrefix |
5489 | | */ |
5490 | 137 | else if (aArgs[0] == "add") |
5491 | 129 | { |
5492 | 129 | otBorderRouterConfig config; |
5493 | | |
5494 | 129 | SuccessOrExit(error = ParsePrefix(aArgs + 1, config)); |
5495 | 118 | error = otBorderRouterAddOnMeshPrefix(GetInstancePtr(), &config); |
5496 | 118 | } |
5497 | | /** |
5498 | | * @cli prefix remove |
5499 | | * @code |
5500 | | * prefix remove 2001:dead:beef:cafe::/64 |
5501 | | * Done |
5502 | | * @endcode |
5503 | | * @par api_copy |
5504 | | * #otBorderRouterRemoveOnMeshPrefix |
5505 | | */ |
5506 | 8 | else if (aArgs[0] == "remove") |
5507 | 2 | { |
5508 | 2 | otIp6Prefix prefix; |
5509 | | |
5510 | 2 | SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix)); |
5511 | 1 | error = otBorderRouterRemoveOnMeshPrefix(GetInstancePtr(), &prefix); |
5512 | 1 | } |
5513 | | /** |
5514 | | * @cli prefix meshlocal |
5515 | | * @code |
5516 | | * prefix meshlocal |
5517 | | * fdde:ad00:beef:0::/64 |
5518 | | * Done |
5519 | | * @endcode |
5520 | | * @par |
5521 | | * Get the mesh local prefix. |
5522 | | */ |
5523 | 6 | else if (aArgs[0] == "meshlocal") |
5524 | 5 | { |
5525 | 5 | if (aArgs[1].IsEmpty()) |
5526 | 1 | { |
5527 | 1 | OutputIp6PrefixLine(*otThreadGetMeshLocalPrefix(GetInstancePtr())); |
5528 | 1 | } |
5529 | 4 | else |
5530 | 4 | { |
5531 | 4 | otIp6Prefix prefix; |
5532 | | |
5533 | 4 | SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix)); |
5534 | 3 | VerifyOrExit(prefix.mLength == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS); |
5535 | 1 | error = |
5536 | 1 | otThreadSetMeshLocalPrefix(GetInstancePtr(), reinterpret_cast<otMeshLocalPrefix *>(&prefix.mPrefix)); |
5537 | 1 | } |
5538 | 5 | } |
5539 | 1 | else |
5540 | 1 | { |
5541 | 1 | error = OT_ERROR_INVALID_COMMAND; |
5542 | 1 | } |
5543 | | |
5544 | 138 | exit: |
5545 | 138 | return error; |
5546 | 138 | } |
5547 | | #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
5548 | | |
5549 | | /** |
5550 | | * @cli preferrouterid |
5551 | | * @code |
5552 | | * preferrouterid 16 |
5553 | | * Done |
5554 | | * @endcode |
5555 | | * @cparam preferrouterid @ca{routerid} |
5556 | | * @par |
5557 | | * Specifies the preferred router ID that the leader should provide when solicited. |
5558 | | * @sa otThreadSetPreferredRouterId |
5559 | | */ |
5560 | | #if OPENTHREAD_FTD |
5561 | | template <> otError Interpreter::Process<Cmd("preferrouterid")>(Arg aArgs[]) |
5562 | 3 | { |
5563 | 3 | return ProcessSet(aArgs, otThreadSetPreferredRouterId); |
5564 | 3 | } |
5565 | | #endif |
5566 | | |
5567 | | #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE |
5568 | | template <> otError Interpreter::Process<Cmd("radiofilter")>(Arg aArgs[]) |
5569 | 4 | { |
5570 | 4 | return ProcessEnableDisable(aArgs, otLinkIsRadioFilterEnabled, otLinkSetRadioFilterEnabled); |
5571 | 4 | } |
5572 | | #endif |
5573 | | |
5574 | | #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE |
5575 | | inline unsigned long UsToSInt(uint64_t aUs) { return ToUlong(static_cast<uint32_t>(aUs / 1000000)); } |
5576 | | inline unsigned long UsToSDec(uint64_t aUs) { return ToUlong(static_cast<uint32_t>(aUs % 1000000)); } |
5577 | | |
5578 | | void Interpreter::OutputRadioStatsTime(const char *aTimeName, uint64_t aTimeUs, uint64_t aTotalTimeUs) |
5579 | | { |
5580 | | uint32_t timePercentInt = static_cast<uint32_t>(aTimeUs * 100 / aTotalTimeUs); |
5581 | | uint32_t timePercentDec = static_cast<uint32_t>((aTimeUs * 100 % aTotalTimeUs) * 100 / aTotalTimeUs); |
5582 | | |
5583 | | OutputLine("%s Time: %lu.%06lus (%lu.%02lu%%)", aTimeName, UsToSInt(aTimeUs), UsToSDec(aTimeUs), |
5584 | | ToUlong(timePercentInt), ToUlong(timePercentDec)); |
5585 | | } |
5586 | | #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE |
5587 | | |
5588 | | template <> otError Interpreter::Process<Cmd("radio")>(Arg aArgs[]) |
5589 | 0 | { |
5590 | 0 | otError error = OT_ERROR_NONE; |
5591 | | |
5592 | | /** |
5593 | | * @cli radio (enable,disable) |
5594 | | * @code |
5595 | | * radio enable |
5596 | | * Done |
5597 | | * @endcode |
5598 | | * @code |
5599 | | * radio disable |
5600 | | * Done |
5601 | | * @endcode |
5602 | | * @cparam radio @ca{enable|disable} |
5603 | | * @sa otLinkSetEnabled |
5604 | | * @par |
5605 | | * Enables or disables the radio. |
5606 | | */ |
5607 | 0 | if (ProcessEnableDisable(aArgs, otLinkSetEnabled) == OT_ERROR_NONE) |
5608 | 0 | { |
5609 | 0 | } |
5610 | | #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE |
5611 | | /** |
5612 | | * @cli radio stats |
5613 | | * @code |
5614 | | * radio stats |
5615 | | * Radio Statistics: |
5616 | | * Total Time: 67.756s |
5617 | | * Tx Time: 0.022944s (0.03%) |
5618 | | * Rx Time: 1.482353s (2.18%) |
5619 | | * Sleep Time: 66.251128s (97.77%) |
5620 | | * Disabled Time: 0.000080s (0.00%) |
5621 | | * Done |
5622 | | * @endcode |
5623 | | * @par api_copy |
5624 | | * #otRadioTimeStatsGet |
5625 | | */ |
5626 | | else if (aArgs[0] == "stats") |
5627 | | { |
5628 | | if (aArgs[1].IsEmpty()) |
5629 | | { |
5630 | | const otRadioTimeStats *radioStats = nullptr; |
5631 | | uint64_t totalTimeUs; |
5632 | | |
5633 | | radioStats = otRadioTimeStatsGet(GetInstancePtr()); |
5634 | | |
5635 | | totalTimeUs = |
5636 | | radioStats->mSleepTime + radioStats->mTxTime + radioStats->mRxTime + radioStats->mDisabledTime; |
5637 | | if (totalTimeUs == 0) |
5638 | | { |
5639 | | OutputLine("Total Time is 0!"); |
5640 | | } |
5641 | | else |
5642 | | { |
5643 | | OutputLine("Radio Statistics:"); |
5644 | | OutputLine("Total Time: %lu.%03lus", ToUlong(static_cast<uint32_t>(totalTimeUs / 1000000)), |
5645 | | ToUlong((totalTimeUs % 1000000) / 1000)); |
5646 | | OutputRadioStatsTime("Tx", radioStats->mTxTime, totalTimeUs); |
5647 | | OutputRadioStatsTime("Rx", radioStats->mRxTime, totalTimeUs); |
5648 | | OutputRadioStatsTime("Sleep", radioStats->mSleepTime, totalTimeUs); |
5649 | | OutputRadioStatsTime("Disabled", radioStats->mDisabledTime, totalTimeUs); |
5650 | | } |
5651 | | } |
5652 | | /** |
5653 | | * @cli radio stats clear |
5654 | | * @code |
5655 | | * radio stats clear |
5656 | | * Done |
5657 | | * @endcode |
5658 | | * @par api_copy |
5659 | | * #otRadioTimeStatsReset |
5660 | | */ |
5661 | | else if (aArgs[1] == "clear") |
5662 | | { |
5663 | | otRadioTimeStatsReset(GetInstancePtr()); |
5664 | | } |
5665 | | } |
5666 | | #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE |
5667 | 0 | else |
5668 | 0 | { |
5669 | 0 | error = OT_ERROR_INVALID_COMMAND; |
5670 | 0 | } |
5671 | |
|
5672 | 0 | return error; |
5673 | 0 | } |
5674 | | |
5675 | | template <> otError Interpreter::Process<Cmd("rcp")>(Arg aArgs[]) |
5676 | 1 | { |
5677 | 1 | otError error = OT_ERROR_NONE; |
5678 | 1 | const char *version = otPlatRadioGetVersionString(GetInstancePtr()); |
5679 | | |
5680 | 1 | VerifyOrExit(version != otGetVersionString(), error = OT_ERROR_NOT_IMPLEMENTED); |
5681 | | /** |
5682 | | * @cli rcp version |
5683 | | * @code |
5684 | | * rcp version |
5685 | | * OPENTHREAD/20191113-00825-g82053cc9d-dirty; SIMULATION; Jun 4 2020 17:53:16 |
5686 | | * Done |
5687 | | * @endcode |
5688 | | * @par api_copy |
5689 | | * #otPlatRadioGetVersionString |
5690 | | */ |
5691 | 0 | if (aArgs[0] == "version") |
5692 | 0 | { |
5693 | 0 | OutputLine("%s", version); |
5694 | 0 | } |
5695 | | |
5696 | 0 | else |
5697 | 0 | { |
5698 | 0 | error = OT_ERROR_INVALID_ARGS; |
5699 | 0 | } |
5700 | |
|
5701 | 1 | exit: |
5702 | 1 | return error; |
5703 | 0 | } |
5704 | | /** |
5705 | | * @cli region |
5706 | | * @code |
5707 | | * region |
5708 | | * US |
5709 | | * Done |
5710 | | * @endcode |
5711 | | * @par api_copy |
5712 | | * #otLinkGetRegion |
5713 | | */ |
5714 | | template <> otError Interpreter::Process<Cmd("region")>(Arg aArgs[]) |
5715 | 3 | { |
5716 | 3 | otError error = OT_ERROR_NONE; |
5717 | 3 | uint16_t regionCode; |
5718 | | |
5719 | 3 | if (aArgs[0].IsEmpty()) |
5720 | 1 | { |
5721 | 1 | SuccessOrExit(error = otLinkGetRegion(GetInstancePtr(), ®ionCode)); |
5722 | 0 | OutputLine("%c%c", regionCode >> 8, regionCode & 0xff); |
5723 | 0 | } |
5724 | | /** |
5725 | | * @cli region (set) |
5726 | | * @code |
5727 | | * region US |
5728 | | * Done |
5729 | | * @endcode |
5730 | | * @par api_copy |
5731 | | * #otLinkSetRegion |
5732 | | * @par |
5733 | | * Changing this can affect the transmit power limit. |
5734 | | */ |
5735 | 2 | else |
5736 | | |
5737 | 2 | { |
5738 | 2 | VerifyOrExit(aArgs[0].GetLength() == 2, error = OT_ERROR_INVALID_ARGS); |
5739 | | |
5740 | 1 | regionCode = static_cast<uint16_t>(static_cast<uint16_t>(aArgs[0].GetCString()[0]) << 8) + |
5741 | 1 | static_cast<uint16_t>(aArgs[0].GetCString()[1]); |
5742 | 1 | error = otLinkSetRegion(GetInstancePtr(), regionCode); |
5743 | 1 | } |
5744 | | |
5745 | 3 | exit: |
5746 | 3 | return error; |
5747 | 3 | } |
5748 | | |
5749 | | #if OPENTHREAD_FTD |
5750 | | /** |
5751 | | * @cli releaserouterid (routerid) |
5752 | | * @code |
5753 | | * releaserouterid 16 |
5754 | | * Done |
5755 | | * @endcode |
5756 | | * @cparam releaserouterid [@ca{routerid}] |
5757 | | * @par api_copy |
5758 | | * #otThreadReleaseRouterId |
5759 | | */ |
5760 | | template <> otError Interpreter::Process<Cmd("releaserouterid")>(Arg aArgs[]) |
5761 | | |
5762 | 11 | { |
5763 | 11 | return ProcessSet(aArgs, otThreadReleaseRouterId); |
5764 | 11 | } |
5765 | | #endif |
5766 | | /** |
5767 | | * @cli rloc16 |
5768 | | * @code |
5769 | | * rloc16 |
5770 | | * 0xdead |
5771 | | * Done |
5772 | | * @endcode |
5773 | | * @par api_copy |
5774 | | * #otThreadGetRloc16 |
5775 | | */ |
5776 | | template <> otError Interpreter::Process<Cmd("rloc16")>(Arg aArgs[]) |
5777 | | |
5778 | 17 | { |
5779 | 17 | OT_UNUSED_VARIABLE(aArgs); |
5780 | | |
5781 | 17 | OutputLine("%04x", otThreadGetRloc16(GetInstancePtr())); |
5782 | | |
5783 | 17 | return OT_ERROR_NONE; |
5784 | 17 | } |
5785 | | |
5786 | | #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
5787 | | template <> otError Interpreter::Process<Cmd("route")>(Arg aArgs[]) |
5788 | 148 | { |
5789 | 148 | otError error = OT_ERROR_NONE; |
5790 | | /** |
5791 | | * @cli route |
5792 | | * @code |
5793 | | * route |
5794 | | * 2001:dead:beef:cafe::/64 s med |
5795 | | * Done |
5796 | | * @endcode |
5797 | | * @sa otBorderRouterGetNextRoute |
5798 | | * @par |
5799 | | * Get the external route list in the local Network Data. |
5800 | | */ |
5801 | 148 | if (aArgs[0].IsEmpty()) |
5802 | 1 | { |
5803 | 1 | otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; |
5804 | 1 | otExternalRouteConfig config; |
5805 | | |
5806 | 1 | while (otBorderRouterGetNextRoute(GetInstancePtr(), &iterator, &config) == OT_ERROR_NONE) |
5807 | 0 | { |
5808 | 0 | mNetworkData.OutputRoute(config); |
5809 | 0 | } |
5810 | 1 | } |
5811 | | /** |
5812 | | * @cli route add |
5813 | | * @code |
5814 | | * route add 2001:dead:beef:cafe::/64 s med |
5815 | | * Done |
5816 | | * @endcode |
5817 | | * @par |
5818 | | * For parameters, use: |
5819 | | * * s: Stable flag |
5820 | | * * n: NAT64 flag |
5821 | | * * prf: Default Router Preference, [high, med, low]. |
5822 | | * @cparam route add @ca{prefix} [@ca{sn}] [@ca{high}|@ca{med}|@ca{low}] |
5823 | | * @par api_copy |
5824 | | * #otExternalRouteConfig |
5825 | | * @par |
5826 | | * Add a valid external route to the Network Data. |
5827 | | */ |
5828 | 147 | else if (aArgs[0] == "add") |
5829 | 144 | { |
5830 | 144 | otExternalRouteConfig config; |
5831 | | |
5832 | 144 | SuccessOrExit(error = ParseRoute(aArgs + 1, config)); |
5833 | 115 | error = otBorderRouterAddRoute(GetInstancePtr(), &config); |
5834 | 115 | } |
5835 | | /** |
5836 | | * @cli route remove |
5837 | | * @code |
5838 | | * route remove 2001:dead:beef:cafe::/64 |
5839 | | * Done |
5840 | | * @endcode |
5841 | | * @cparam route remove [@ca{prefix}] |
5842 | | * @par api_copy |
5843 | | * #otBorderRouterRemoveRoute |
5844 | | */ |
5845 | 3 | else if (aArgs[0] == "remove") |
5846 | 2 | { |
5847 | 2 | otIp6Prefix prefix; |
5848 | | |
5849 | 2 | SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix)); |
5850 | 1 | error = otBorderRouterRemoveRoute(GetInstancePtr(), &prefix); |
5851 | 1 | } |
5852 | 1 | else |
5853 | 1 | { |
5854 | 1 | error = OT_ERROR_INVALID_COMMAND; |
5855 | 1 | } |
5856 | | |
5857 | 148 | exit: |
5858 | 148 | return error; |
5859 | 148 | } |
5860 | | #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
5861 | | |
5862 | | #if OPENTHREAD_FTD |
5863 | | template <> otError Interpreter::Process<Cmd("router")>(Arg aArgs[]) |
5864 | 39 | { |
5865 | 39 | otError error = OT_ERROR_NONE; |
5866 | 39 | otRouterInfo routerInfo; |
5867 | 39 | uint16_t routerId; |
5868 | 39 | bool isTable; |
5869 | | /** |
5870 | | * @cli router table |
5871 | | * @code |
5872 | | * router table |
5873 | | * | ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC | Link | |
5874 | | * +----+--------+----------+-----------+-------+--------+-----+------------------+------+ |
5875 | | * | 22 | 0x5800 | 63 | 0 | 0 | 0 | 0 | 0aeb8196c9f61658 | 0 | |
5876 | | * | 49 | 0xc400 | 63 | 0 | 3 | 3 | 0 | faa1c03908e2dbf2 | 1 | |
5877 | | * Done |
5878 | | * @endcode |
5879 | | * @sa otThreadGetRouterInfo |
5880 | | * @par |
5881 | | * Prints a list of routers in a table format. |
5882 | | */ |
5883 | 39 | isTable = (aArgs[0] == "table"); |
5884 | | /** |
5885 | | * @cli router list |
5886 | | * @code |
5887 | | * router list |
5888 | | * 8 24 50 |
5889 | | * Done |
5890 | | * @endcode |
5891 | | * @sa otThreadGetRouterInfo |
5892 | | * @par |
5893 | | * List allocated Router IDs. |
5894 | | */ |
5895 | 39 | if (isTable || (aArgs[0] == "list")) |
5896 | 18 | { |
5897 | 18 | uint8_t maxRouterId; |
5898 | | |
5899 | 18 | if (isTable) |
5900 | 17 | { |
5901 | 17 | static const char *const kRouterTableTitles[] = { |
5902 | 17 | "ID", "RLOC16", "Next Hop", "Path Cost", "LQ In", "LQ Out", "Age", "Extended MAC", "Link", |
5903 | 17 | }; |
5904 | | |
5905 | 17 | static const uint8_t kRouterTableColumnWidths[] = { |
5906 | 17 | 4, 8, 10, 11, 7, 8, 5, 18, 6, |
5907 | 17 | }; |
5908 | | |
5909 | 17 | OutputTableHeader(kRouterTableTitles, kRouterTableColumnWidths); |
5910 | 17 | } |
5911 | | |
5912 | 18 | maxRouterId = otThreadGetMaxRouterId(GetInstancePtr()); |
5913 | | |
5914 | 1.15k | for (uint8_t i = 0; i <= maxRouterId; i++) |
5915 | 1.13k | { |
5916 | 1.13k | if (otThreadGetRouterInfo(GetInstancePtr(), i, &routerInfo) != OT_ERROR_NONE) |
5917 | 1.13k | { |
5918 | 1.13k | continue; |
5919 | 1.13k | } |
5920 | | |
5921 | 0 | if (isTable) |
5922 | 0 | { |
5923 | 0 | OutputFormat("| %2u ", routerInfo.mRouterId); |
5924 | 0 | OutputFormat("| 0x%04x ", routerInfo.mRloc16); |
5925 | 0 | OutputFormat("| %8u ", routerInfo.mNextHop); |
5926 | 0 | OutputFormat("| %9u ", routerInfo.mPathCost); |
5927 | 0 | OutputFormat("| %5u ", routerInfo.mLinkQualityIn); |
5928 | 0 | OutputFormat("| %6u ", routerInfo.mLinkQualityOut); |
5929 | 0 | OutputFormat("| %3u ", routerInfo.mAge); |
5930 | 0 | OutputFormat("| "); |
5931 | 0 | OutputExtAddress(routerInfo.mExtAddress); |
5932 | 0 | OutputLine(" | %4d |", routerInfo.mLinkEstablished); |
5933 | 0 | } |
5934 | 0 | else |
5935 | 0 | { |
5936 | 0 | OutputFormat("%u ", i); |
5937 | 0 | } |
5938 | 0 | } |
5939 | | |
5940 | 18 | OutputNewLine(); |
5941 | 18 | ExitNow(); |
5942 | 18 | } |
5943 | | /** |
5944 | | * @cli router (id) |
5945 | | * @code |
5946 | | * router 50 |
5947 | | * Alloc: 1 |
5948 | | * Router ID: 50 |
5949 | | * Rloc: c800 |
5950 | | * Next Hop: c800 |
5951 | | * Link: 1 |
5952 | | * Ext Addr: e2b3540590b0fd87 |
5953 | | * Cost: 0 |
5954 | | * Link Quality In: 3 |
5955 | | * Link Quality Out: 3 |
5956 | | * Age: 3 |
5957 | | * Done |
5958 | | * @endcode |
5959 | | * @code |
5960 | | * router 0xc800 |
5961 | | * Alloc: 1 |
5962 | | * Router ID: 50 |
5963 | | * Rloc: c800 |
5964 | | * Next Hop: c800 |
5965 | | * Link: 1 |
5966 | | * Ext Addr: e2b3540590b0fd87 |
5967 | | * Cost: 0 |
5968 | | * Link Quality In: 3 |
5969 | | * Link Quality Out: 3 |
5970 | | * Age: 7 |
5971 | | * Done |
5972 | | * @endcode |
5973 | | * @cparam router [@ca{id}] |
5974 | | * @par api_copy |
5975 | | * #otThreadGetRouterInfo |
5976 | | * @par |
5977 | | * Print diagnostic information for a Thread Router. The id may be a Router ID or |
5978 | | * an RLOC16. |
5979 | | */ |
5980 | 21 | SuccessOrExit(error = aArgs[0].ParseAsUint16(routerId)); |
5981 | 16 | SuccessOrExit(error = otThreadGetRouterInfo(GetInstancePtr(), routerId, &routerInfo)); |
5982 | | |
5983 | 0 | OutputLine("Alloc: %d", routerInfo.mAllocated); |
5984 | |
|
5985 | 0 | if (routerInfo.mAllocated) |
5986 | 0 | { |
5987 | 0 | OutputLine("Router ID: %u", routerInfo.mRouterId); |
5988 | 0 | OutputLine("Rloc: %04x", routerInfo.mRloc16); |
5989 | 0 | OutputLine("Next Hop: %04x", static_cast<uint16_t>(routerInfo.mNextHop) << 10); |
5990 | 0 | OutputLine("Link: %d", routerInfo.mLinkEstablished); |
5991 | |
|
5992 | 0 | if (routerInfo.mLinkEstablished) |
5993 | 0 | { |
5994 | 0 | OutputFormat("Ext Addr: "); |
5995 | 0 | OutputExtAddressLine(routerInfo.mExtAddress); |
5996 | 0 | OutputLine("Cost: %u", routerInfo.mPathCost); |
5997 | 0 | OutputLine("Link Quality In: %u", routerInfo.mLinkQualityIn); |
5998 | 0 | OutputLine("Link Quality Out: %u", routerInfo.mLinkQualityOut); |
5999 | 0 | OutputLine("Age: %u", routerInfo.mAge); |
6000 | 0 | } |
6001 | 0 | } |
6002 | |
|
6003 | 39 | exit: |
6004 | 39 | return error; |
6005 | 0 | } |
6006 | | /** |
6007 | | * @cli routerdowngradethreshold (get,set) |
6008 | | * @code routerdowngradethreshold |
6009 | | * 23 |
6010 | | * Done |
6011 | | * @endcode |
6012 | | * @code routerdowngradethreshold 23 |
6013 | | * Done |
6014 | | * @endcode |
6015 | | * @cparam routerdowngradethreshold [@ca{threshold}] |
6016 | | * @par |
6017 | | * Gets or sets the ROUTER_DOWNGRADE_THRESHOLD value. |
6018 | | * @sa otThreadGetRouterDowngradeThreshold |
6019 | | * @sa otThreadSetRouterDowngradeThreshold |
6020 | | */ |
6021 | | template <> otError Interpreter::Process<Cmd("routerdowngradethreshold")>(Arg aArgs[]) |
6022 | 4 | { |
6023 | 4 | return ProcessGetSet(aArgs, otThreadGetRouterDowngradeThreshold, otThreadSetRouterDowngradeThreshold); |
6024 | 4 | } |
6025 | | |
6026 | | /** |
6027 | | * @cli routereligible |
6028 | | * @code |
6029 | | * routereligible |
6030 | | * Enabled |
6031 | | * Done |
6032 | | * @endcode |
6033 | | * @sa otThreadIsRouterEligible |
6034 | | * @par |
6035 | | * Indicates whether the router role is enabled or disabled. |
6036 | | */ |
6037 | | template <> otError Interpreter::Process<Cmd("routereligible")>(Arg aArgs[]) |
6038 | 4 | { |
6039 | | /** |
6040 | | * @cli routereligible (enable,disable) |
6041 | | * @code |
6042 | | * routereligible enable |
6043 | | * Done |
6044 | | * @endcode |
6045 | | * @code |
6046 | | * routereligible disable |
6047 | | * Done |
6048 | | * @endcode |
6049 | | * @cparam routereligible [@ca{enable|disable}] |
6050 | | * @sa otThreadSetRouterEligible |
6051 | | * @par |
6052 | | * Enables or disables the router role. |
6053 | | */ |
6054 | 4 | return ProcessEnableDisable(aArgs, otThreadIsRouterEligible, otThreadSetRouterEligible); |
6055 | 4 | } |
6056 | | |
6057 | | /** |
6058 | | * @cli routerselectionjitter |
6059 | | * @code |
6060 | | * routerselectionjitter |
6061 | | * 120 |
6062 | | * Done |
6063 | | * @endcode |
6064 | | * @code |
6065 | | * routerselectionjitter 120 |
6066 | | * Done |
6067 | | * @endcode |
6068 | | * @cparam routerselectionjitter [@ca{jitter}] |
6069 | | * @par |
6070 | | * Gets or sets the ROUTER_SELECTION_JITTER value. |
6071 | | * @sa otThreadGetRouterSelectionJitter |
6072 | | * @sa otThreadSetRouterSelectionJitter |
6073 | | */ |
6074 | | template <> otError Interpreter::Process<Cmd("routerselectionjitter")>(Arg aArgs[]) |
6075 | 4 | { |
6076 | 4 | return ProcessGetSet(aArgs, otThreadGetRouterSelectionJitter, otThreadSetRouterSelectionJitter); |
6077 | 4 | } |
6078 | | /** |
6079 | | * @cli routerupgradethreshold (get,set) |
6080 | | * @code |
6081 | | * routerupgradethreshold |
6082 | | * 16 |
6083 | | * Done |
6084 | | * @endcode |
6085 | | * @code |
6086 | | * routerupgradethreshold 16 |
6087 | | * Done |
6088 | | * @endcode |
6089 | | * @cparam routerupgradethreshold [@ca{threshold}] |
6090 | | * @par |
6091 | | * Gets or sets the ROUTER_UPGRADE_THRESHOLD value. |
6092 | | * @sa otThreadGetRouterUpgradeThreshold |
6093 | | * @sa otThreadSetRouterUpgradeThreshold |
6094 | | */ |
6095 | | template <> otError Interpreter::Process<Cmd("routerupgradethreshold")>(Arg aArgs[]) |
6096 | 4 | { |
6097 | 4 | return ProcessGetSet(aArgs, otThreadGetRouterUpgradeThreshold, otThreadSetRouterUpgradeThreshold); |
6098 | 4 | } |
6099 | | /** |
6100 | | * @cli childrouterlinks (get,set) |
6101 | | * @code |
6102 | | * childrouterlinks |
6103 | | * 16 |
6104 | | * Done |
6105 | | * @endcode |
6106 | | * @code |
6107 | | * childrouterlinks 16 |
6108 | | * Done |
6109 | | * @endcode |
6110 | | * @cparam childrouterlinks [@ca{links}] |
6111 | | * @par |
6112 | | * Gets or sets the MLE_CHILD_ROUTER_LINKS value. |
6113 | | * @sa otThreadGetChildRouterLinks |
6114 | | * @sa otThreadSetChildRouterLinks |
6115 | | */ |
6116 | | template <> otError Interpreter::Process<Cmd("childrouterlinks")>(Arg aArgs[]) |
6117 | 4 | { |
6118 | 4 | return ProcessGetSet(aArgs, otThreadGetChildRouterLinks, otThreadSetChildRouterLinks); |
6119 | 4 | } |
6120 | | #endif // OPENTHREAD_FTD |
6121 | | |
6122 | | template <> otError Interpreter::Process<Cmd("scan")>(Arg aArgs[]) |
6123 | 314 | { |
6124 | 314 | otError error = OT_ERROR_NONE; |
6125 | 314 | uint32_t scanChannels = 0; |
6126 | 314 | uint16_t scanDuration = 0; |
6127 | 314 | bool energyScan = false; |
6128 | | |
6129 | 314 | if (aArgs[0] == "energy") |
6130 | 3 | { |
6131 | 3 | energyScan = true; |
6132 | 3 | aArgs++; |
6133 | | |
6134 | 3 | if (!aArgs->IsEmpty()) |
6135 | 2 | { |
6136 | 2 | SuccessOrExit(error = aArgs->ParseAsUint16(scanDuration)); |
6137 | 1 | aArgs++; |
6138 | 1 | } |
6139 | 3 | } |
6140 | | |
6141 | 313 | if (!aArgs->IsEmpty()) |
6142 | 309 | { |
6143 | 309 | uint8_t channel; |
6144 | | |
6145 | 309 | SuccessOrExit(error = aArgs->ParseAsUint8(channel)); |
6146 | 33 | VerifyOrExit(channel < BitSizeOf(scanChannels), error = OT_ERROR_INVALID_ARGS); |
6147 | 15 | scanChannels = 1 << channel; |
6148 | 15 | } |
6149 | | |
6150 | | /** |
6151 | | * @cli scan energy |
6152 | | * @code |
6153 | | * scan energy 10 |
6154 | | * | Ch | RSSI | |
6155 | | * +----+------+ |
6156 | | * | 11 | -59 | |
6157 | | * | 12 | -62 | |
6158 | | * | 13 | -67 | |
6159 | | * | 14 | -61 | |
6160 | | * | 15 | -87 | |
6161 | | * | 16 | -86 | |
6162 | | * | 17 | -86 | |
6163 | | * | 18 | -52 | |
6164 | | * | 19 | -58 | |
6165 | | * | 20 | -82 | |
6166 | | * | 21 | -76 | |
6167 | | * | 22 | -82 | |
6168 | | * | 23 | -74 | |
6169 | | * | 24 | -81 | |
6170 | | * | 25 | -88 | |
6171 | | * | 26 | -71 | |
6172 | | * Done |
6173 | | * @endcode |
6174 | | * @code |
6175 | | * scan energy 10 20 |
6176 | | * | Ch | RSSI | |
6177 | | * +----+------+ |
6178 | | * | 20 | -82 | |
6179 | | * Done |
6180 | | * @endcode |
6181 | | * @cparam scan energy [@ca{duration}] [@ca{channel}] |
6182 | | * @par |
6183 | | * Performs an IEEE 802.15.4 energy scan, and displays the time in milliseconds |
6184 | | * to use for scanning each channel. All channels are shown unless you specify a certain channel |
6185 | | * by using the channel option. |
6186 | | * @sa otLinkEnergyScan |
6187 | | */ |
6188 | 19 | if (energyScan) |
6189 | 2 | { |
6190 | 2 | static const char *const kEnergyScanTableTitles[] = {"Ch", "RSSI"}; |
6191 | 2 | static const uint8_t kEnergyScanTableColumnWidths[] = {4, 6}; |
6192 | | |
6193 | 2 | OutputTableHeader(kEnergyScanTableTitles, kEnergyScanTableColumnWidths); |
6194 | 2 | SuccessOrExit(error = otLinkEnergyScan(GetInstancePtr(), scanChannels, scanDuration, |
6195 | 2 | &Interpreter::HandleEnergyScanResult, this)); |
6196 | 2 | } |
6197 | | /** |
6198 | | * @cli scan |
6199 | | * @code |
6200 | | * scan |
6201 | | * | PAN | MAC Address | Ch | dBm | LQI | |
6202 | | * +------+------------------+----+-----+-----+ |
6203 | | * | ffff | f1d92a82c8d8fe43 | 11 | -20 | 0 | |
6204 | | * Done |
6205 | | * @endcode |
6206 | | * @cparam scan [@ca{channel}] |
6207 | | * @par |
6208 | | * Performs an active IEEE 802.15.4 scan. The scan covers all channels if no channel is specified; otherwise the |
6209 | | * span covers only the channel specified. |
6210 | | * @sa otLinkActiveScan |
6211 | | */ |
6212 | 17 | else |
6213 | 17 | { |
6214 | 17 | static const char *const kScanTableTitles[] = {"PAN", "MAC Address", "Ch", "dBm", "LQI"}; |
6215 | 17 | static const uint8_t kScanTableColumnWidths[] = {6, 18, 4, 5, 5}; |
6216 | | |
6217 | 17 | OutputTableHeader(kScanTableTitles, kScanTableColumnWidths); |
6218 | | |
6219 | 17 | SuccessOrExit(error = otLinkActiveScan(GetInstancePtr(), scanChannels, scanDuration, |
6220 | 17 | &Interpreter::HandleActiveScanResult, this)); |
6221 | 17 | } |
6222 | | |
6223 | 4 | error = OT_ERROR_PENDING; |
6224 | | |
6225 | 314 | exit: |
6226 | 314 | return error; |
6227 | 4 | } |
6228 | | |
6229 | | void Interpreter::HandleActiveScanResult(otActiveScanResult *aResult, void *aContext) |
6230 | 0 | { |
6231 | 0 | static_cast<Interpreter *>(aContext)->HandleActiveScanResult(aResult); |
6232 | 0 | } |
6233 | | |
6234 | | void Interpreter::HandleActiveScanResult(otActiveScanResult *aResult) |
6235 | 0 | { |
6236 | 0 | if (aResult == nullptr) |
6237 | 0 | { |
6238 | 0 | OutputResult(OT_ERROR_NONE); |
6239 | 0 | ExitNow(); |
6240 | 0 | } |
6241 | | |
6242 | 0 | if (aResult->mDiscover) |
6243 | 0 | { |
6244 | 0 | OutputFormat("| %-16s ", aResult->mNetworkName.m8); |
6245 | |
|
6246 | 0 | OutputFormat("| "); |
6247 | 0 | OutputBytes(aResult->mExtendedPanId.m8); |
6248 | 0 | OutputFormat(" "); |
6249 | 0 | } |
6250 | |
|
6251 | 0 | OutputFormat("| %04x | ", aResult->mPanId); |
6252 | 0 | OutputExtAddress(aResult->mExtAddress); |
6253 | 0 | OutputFormat(" | %2u ", aResult->mChannel); |
6254 | 0 | OutputFormat("| %3d ", aResult->mRssi); |
6255 | 0 | OutputLine("| %3u |", aResult->mLqi); |
6256 | |
|
6257 | 0 | exit: |
6258 | 0 | return; |
6259 | 0 | } |
6260 | | |
6261 | | void Interpreter::HandleEnergyScanResult(otEnergyScanResult *aResult, void *aContext) |
6262 | 0 | { |
6263 | 0 | static_cast<Interpreter *>(aContext)->HandleEnergyScanResult(aResult); |
6264 | 0 | } |
6265 | | |
6266 | | void Interpreter::HandleEnergyScanResult(otEnergyScanResult *aResult) |
6267 | 0 | { |
6268 | 0 | if (aResult == nullptr) |
6269 | 0 | { |
6270 | 0 | OutputResult(OT_ERROR_NONE); |
6271 | 0 | ExitNow(); |
6272 | 0 | } |
6273 | | |
6274 | 0 | OutputLine("| %2u | %4d |", aResult->mChannel, aResult->mMaxRssi); |
6275 | |
|
6276 | 0 | exit: |
6277 | 0 | return; |
6278 | 0 | } |
6279 | | |
6280 | | /** |
6281 | | * @cli singleton |
6282 | | * @code |
6283 | | * singleton |
6284 | | * true |
6285 | | * Done |
6286 | | * @endcode |
6287 | | * @par |
6288 | | * Indicates whether a node is the only router on the network. |
6289 | | * Returns either `true` or `false`. |
6290 | | * @sa otThreadIsSingleton |
6291 | | */ |
6292 | | template <> otError Interpreter::Process<Cmd("singleton")>(Arg aArgs[]) |
6293 | 1 | { |
6294 | 1 | OT_UNUSED_VARIABLE(aArgs); |
6295 | | |
6296 | 1 | OutputLine(otThreadIsSingleton(GetInstancePtr()) ? "true" : "false"); |
6297 | | |
6298 | 1 | return OT_ERROR_NONE; |
6299 | 1 | } |
6300 | | |
6301 | | #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
6302 | | template <> otError Interpreter::Process<Cmd("sntp")>(Arg aArgs[]) |
6303 | 144 | { |
6304 | 144 | otError error = OT_ERROR_NONE; |
6305 | 144 | uint16_t port = OT_SNTP_DEFAULT_SERVER_PORT; |
6306 | 144 | Ip6::MessageInfo messageInfo; |
6307 | 144 | otSntpQuery query; |
6308 | | |
6309 | | /** |
6310 | | * @cli sntp query |
6311 | | * @code |
6312 | | * sntp query |
6313 | | * SNTP response - Unix time: 1540894725 (era: 0) |
6314 | | * Done |
6315 | | * @endcode |
6316 | | * @code |
6317 | | * sntp query 64:ff9b::d8ef:2308 |
6318 | | * SNTP response - Unix time: 1540898611 (era: 0) |
6319 | | * Done |
6320 | | * @endcode |
6321 | | * @cparam sntp query [@ca{SNTP server IP}] [@ca{SNTP server port}] |
6322 | | * @par |
6323 | | * Sends an SNTP query to obtain the current unix epoch time (from January 1, 1970). |
6324 | | * - SNTP server default IP address: `2001:4860:4806:8::` (Google IPv6 NTP Server) |
6325 | | * - SNTP server default port: `123` |
6326 | | * @note This command is available only if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE is enabled. |
6327 | | * @sa #otSntpClientQuery |
6328 | | */ |
6329 | 144 | if (aArgs[0] == "query") |
6330 | 143 | { |
6331 | 143 | VerifyOrExit(!mSntpQueryingInProgress, error = OT_ERROR_BUSY); |
6332 | | |
6333 | 143 | if (!aArgs[1].IsEmpty()) |
6334 | 142 | { |
6335 | 142 | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(messageInfo.GetPeerAddr())); |
6336 | 142 | } |
6337 | 1 | else |
6338 | 1 | { |
6339 | | // Use IPv6 address of default SNTP server. |
6340 | 1 | SuccessOrExit(error = messageInfo.GetPeerAddr().FromString(OT_SNTP_DEFAULT_SERVER_IP)); |
6341 | 1 | } |
6342 | | |
6343 | 142 | if (!aArgs[2].IsEmpty()) |
6344 | 19 | { |
6345 | 19 | SuccessOrExit(error = aArgs[2].ParseAsUint16(port)); |
6346 | 19 | } |
6347 | | |
6348 | 141 | messageInfo.SetPeerPort(port); |
6349 | | |
6350 | 141 | query.mMessageInfo = static_cast<const otMessageInfo *>(&messageInfo); |
6351 | | |
6352 | 141 | SuccessOrExit(error = otSntpClientQuery(GetInstancePtr(), &query, &Interpreter::HandleSntpResponse, this)); |
6353 | | |
6354 | 138 | mSntpQueryingInProgress = true; |
6355 | 138 | error = OT_ERROR_PENDING; |
6356 | 138 | } |
6357 | 1 | else |
6358 | 1 | { |
6359 | 1 | error = OT_ERROR_INVALID_COMMAND; |
6360 | 1 | } |
6361 | | |
6362 | 144 | exit: |
6363 | 144 | return error; |
6364 | 144 | } |
6365 | | |
6366 | | void Interpreter::HandleSntpResponse(void *aContext, uint64_t aTime, otError aResult) |
6367 | 138 | { |
6368 | 138 | static_cast<Interpreter *>(aContext)->HandleSntpResponse(aTime, aResult); |
6369 | 138 | } |
6370 | | |
6371 | | void Interpreter::HandleSntpResponse(uint64_t aTime, otError aResult) |
6372 | 138 | { |
6373 | 138 | if (aResult == OT_ERROR_NONE) |
6374 | 0 | { |
6375 | | // Some Embedded C libraries do not support printing of 64-bit unsigned integers. |
6376 | | // To simplify, unix epoch time and era number are printed separately. |
6377 | 0 | OutputLine("SNTP response - Unix time: %lu (era: %lu)", ToUlong(static_cast<uint32_t>(aTime)), |
6378 | 0 | ToUlong(static_cast<uint32_t>(aTime >> 32))); |
6379 | 0 | } |
6380 | 138 | else |
6381 | 138 | { |
6382 | 138 | OutputLine("SNTP error - %s", otThreadErrorToString(aResult)); |
6383 | 138 | } |
6384 | | |
6385 | 138 | mSntpQueryingInProgress = false; |
6386 | | |
6387 | 138 | OutputResult(OT_ERROR_NONE); |
6388 | 138 | } |
6389 | | #endif // OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
6390 | | |
6391 | | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE || OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
6392 | | template <> otError Interpreter::Process<Cmd("srp")>(Arg aArgs[]) |
6393 | 786 | { |
6394 | 786 | otError error = OT_ERROR_NONE; |
6395 | | |
6396 | 786 | if (aArgs[0].IsEmpty()) |
6397 | 1 | { |
6398 | 1 | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE |
6399 | 1 | OutputLine("client"); |
6400 | 1 | #endif |
6401 | 1 | #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
6402 | 1 | OutputLine("server"); |
6403 | 1 | #endif |
6404 | 1 | ExitNow(); |
6405 | 1 | } |
6406 | | |
6407 | 785 | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE |
6408 | 785 | if (aArgs[0] == "client") |
6409 | 357 | { |
6410 | 357 | ExitNow(error = mSrpClient.Process(aArgs + 1)); |
6411 | 357 | } |
6412 | 428 | #endif |
6413 | 428 | #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
6414 | 428 | if (aArgs[0] == "server") |
6415 | 426 | { |
6416 | 426 | ExitNow(error = mSrpServer.Process(aArgs + 1)); |
6417 | 426 | } |
6418 | 2 | #endif |
6419 | | |
6420 | 2 | error = OT_ERROR_INVALID_COMMAND; |
6421 | | |
6422 | 786 | exit: |
6423 | 786 | return error; |
6424 | 2 | } |
6425 | | #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE || OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
6426 | | |
6427 | | template <> otError Interpreter::Process<Cmd("state")>(Arg aArgs[]) |
6428 | 22 | { |
6429 | 22 | otError error = OT_ERROR_NONE; |
6430 | | |
6431 | | /** |
6432 | | * @cli state |
6433 | | * @code |
6434 | | * state |
6435 | | * child |
6436 | | * Done |
6437 | | * @endcode |
6438 | | * @code |
6439 | | * state leader |
6440 | | * Done |
6441 | | * @endcode |
6442 | | * @cparam state [@ca{child}|@ca{router}|@ca{leader}|@ca{detached}] |
6443 | | * @par |
6444 | | * Returns the current role of the Thread device, or changes the role as specified with one of the options. |
6445 | | * Possible values returned when inquiring about the device role: |
6446 | | * - `child`: The device is currently operating as a Thread child. |
6447 | | * - `router`: The device is currently operating as a Thread router. |
6448 | | * - `leader`: The device is currently operating as a Thread leader. |
6449 | | * - `detached`: The device is not currently participating in a Thread network/partition. |
6450 | | * - `disabled`: The Thread stack is currently disabled. |
6451 | | * @par |
6452 | | * Using one of the options allows you to change the current role of a device, with the exclusion of |
6453 | | * changing to or from a `disabled` state. |
6454 | | * @sa otThreadGetDeviceRole |
6455 | | * @sa otThreadBecomeChild |
6456 | | * @sa otThreadBecomeRouter |
6457 | | * @sa otThreadBecomeLeader |
6458 | | * @sa otThreadBecomeDetached |
6459 | | */ |
6460 | 22 | if (aArgs[0].IsEmpty()) |
6461 | 17 | { |
6462 | 17 | OutputLine("%s", otThreadDeviceRoleToString(otThreadGetDeviceRole(GetInstancePtr()))); |
6463 | 17 | } |
6464 | 5 | else if (aArgs[0] == "detached") |
6465 | 1 | { |
6466 | 1 | error = otThreadBecomeDetached(GetInstancePtr()); |
6467 | 1 | } |
6468 | 4 | else if (aArgs[0] == "child") |
6469 | 1 | { |
6470 | 1 | error = otThreadBecomeChild(GetInstancePtr()); |
6471 | 1 | } |
6472 | 3 | #if OPENTHREAD_FTD |
6473 | 3 | else if (aArgs[0] == "router") |
6474 | 1 | { |
6475 | 1 | error = otThreadBecomeRouter(GetInstancePtr()); |
6476 | 1 | } |
6477 | 2 | else if (aArgs[0] == "leader") |
6478 | 1 | { |
6479 | 1 | error = otThreadBecomeLeader(GetInstancePtr()); |
6480 | 1 | } |
6481 | 1 | #endif |
6482 | 1 | else |
6483 | 1 | { |
6484 | 1 | error = OT_ERROR_INVALID_ARGS; |
6485 | 1 | } |
6486 | | |
6487 | 22 | return error; |
6488 | 22 | } |
6489 | | |
6490 | | template <> otError Interpreter::Process<Cmd("thread")>(Arg aArgs[]) |
6491 | 4 | { |
6492 | 4 | otError error = OT_ERROR_NONE; |
6493 | | |
6494 | | /** |
6495 | | * @cli thread start |
6496 | | * @code |
6497 | | * thread start |
6498 | | * Done |
6499 | | * @endcode |
6500 | | * @par |
6501 | | * Starts the Thread protocol operation. |
6502 | | * @note The interface must be up when running this command. |
6503 | | * @sa otThreadSetEnabled |
6504 | | */ |
6505 | 4 | if (aArgs[0] == "start") |
6506 | 1 | { |
6507 | 1 | error = otThreadSetEnabled(GetInstancePtr(), true); |
6508 | 1 | } |
6509 | | /** |
6510 | | * @cli thread stop |
6511 | | * @code |
6512 | | * thread stop |
6513 | | * Done |
6514 | | * @endcode |
6515 | | * @par |
6516 | | * Stops the Thread protocol operation. |
6517 | | */ |
6518 | 3 | else if (aArgs[0] == "stop") |
6519 | 1 | { |
6520 | 1 | error = otThreadSetEnabled(GetInstancePtr(), false); |
6521 | 1 | } |
6522 | | /** |
6523 | | * @cli thread version |
6524 | | * @code thread version |
6525 | | * 2 |
6526 | | * Done |
6527 | | * @endcode |
6528 | | * @par api_copy |
6529 | | * #otThreadGetVersion |
6530 | | */ |
6531 | 2 | else if (aArgs[0] == "version") |
6532 | 1 | { |
6533 | 1 | OutputLine("%u", otThreadGetVersion()); |
6534 | 1 | } |
6535 | 1 | else |
6536 | 1 | { |
6537 | 1 | error = OT_ERROR_INVALID_COMMAND; |
6538 | 1 | } |
6539 | | |
6540 | 4 | return error; |
6541 | 4 | } |
6542 | | |
6543 | | #if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE |
6544 | | template <> otError Interpreter::Process<Cmd("timeinqueue")>(Arg aArgs[]) |
6545 | 5 | { |
6546 | 5 | otError error = OT_ERROR_NONE; |
6547 | | |
6548 | | /** |
6549 | | * @cli timeinqueue |
6550 | | * @code |
6551 | | * timeinqueue |
6552 | | * | Min | Max |Msg Count| |
6553 | | * +------+------+---------+ |
6554 | | * | 0 | 9 | 1537 | |
6555 | | * | 10 | 19 | 156 | |
6556 | | * | 20 | 29 | 57 | |
6557 | | * | 30 | 39 | 108 | |
6558 | | * | 40 | 49 | 60 | |
6559 | | * | 50 | 59 | 76 | |
6560 | | * | 60 | 69 | 88 | |
6561 | | * | 70 | 79 | 51 | |
6562 | | * | 80 | 89 | 86 | |
6563 | | * | 90 | 99 | 45 | |
6564 | | * | 100 | 109 | 43 | |
6565 | | * | 110 | 119 | 44 | |
6566 | | * | 120 | 129 | 38 | |
6567 | | * | 130 | 139 | 44 | |
6568 | | * | 140 | 149 | 35 | |
6569 | | * | 150 | 159 | 41 | |
6570 | | * | 160 | 169 | 34 | |
6571 | | * | 170 | 179 | 13 | |
6572 | | * | 180 | 189 | 24 | |
6573 | | * | 190 | 199 | 3 | |
6574 | | * | 200 | 209 | 0 | |
6575 | | * | 210 | 219 | 0 | |
6576 | | * | 220 | 229 | 2 | |
6577 | | * | 230 | 239 | 0 | |
6578 | | * | 240 | 249 | 0 | |
6579 | | * | 250 | 259 | 0 | |
6580 | | * | 260 | 269 | 0 | |
6581 | | * | 270 | 279 | 0 | |
6582 | | * | 280 | 289 | 0 | |
6583 | | * | 290 | 299 | 1 | |
6584 | | * | 300 | 309 | 0 | |
6585 | | * | 310 | 319 | 0 | |
6586 | | * | 320 | 329 | 0 | |
6587 | | * | 330 | 339 | 0 | |
6588 | | * | 340 | 349 | 0 | |
6589 | | * | 350 | 359 | 0 | |
6590 | | * | 360 | 369 | 0 | |
6591 | | * | 370 | 379 | 0 | |
6592 | | * | 380 | 389 | 0 | |
6593 | | * | 390 | 399 | 0 | |
6594 | | * | 400 | 409 | 0 | |
6595 | | * | 410 | 419 | 0 | |
6596 | | * | 420 | 429 | 0 | |
6597 | | * | 430 | 439 | 0 | |
6598 | | * | 440 | 449 | 0 | |
6599 | | * | 450 | 459 | 0 | |
6600 | | * | 460 | 469 | 0 | |
6601 | | * | 470 | 479 | 0 | |
6602 | | * | 480 | 489 | 0 | |
6603 | | * | 490 | inf | 0 | |
6604 | | * Done |
6605 | | * @endcode |
6606 | | * @par api_copy |
6607 | | * #otThreadGetTimeInQueueHistogram |
6608 | | * @csa{timeinqueue reset} |
6609 | | */ |
6610 | 5 | if (aArgs[0].IsEmpty()) |
6611 | 1 | { |
6612 | 1 | static const char *const kTimeInQueueTableTitles[] = {"Min", "Max", "Msg Count"}; |
6613 | 1 | static const uint8_t kTimeInQueueTableColumnWidths[] = {6, 6, 9}; |
6614 | | |
6615 | 1 | uint16_t numBins; |
6616 | 1 | uint32_t binInterval; |
6617 | 1 | const uint32_t *histogram; |
6618 | | |
6619 | 1 | OutputTableHeader(kTimeInQueueTableTitles, kTimeInQueueTableColumnWidths); |
6620 | | |
6621 | 1 | histogram = otThreadGetTimeInQueueHistogram(GetInstancePtr(), &numBins, &binInterval); |
6622 | | |
6623 | 51 | for (uint16_t index = 0; index < numBins; index++) |
6624 | 50 | { |
6625 | 50 | OutputFormat("| %4lu | ", ToUlong(index * binInterval)); |
6626 | | |
6627 | 50 | if (index < numBins - 1) |
6628 | 49 | { |
6629 | 49 | OutputFormat("%4lu", ToUlong((index + 1) * binInterval - 1)); |
6630 | 49 | } |
6631 | 1 | else |
6632 | 1 | { |
6633 | 1 | OutputFormat("%4s", "inf"); |
6634 | 1 | } |
6635 | | |
6636 | 50 | OutputLine(" | %7lu |", ToUlong(histogram[index])); |
6637 | 50 | } |
6638 | 1 | } |
6639 | | /** |
6640 | | * @cli timeinqueue max |
6641 | | * @code |
6642 | | * timeinqueue max |
6643 | | * 281 |
6644 | | * Done |
6645 | | * @endcode |
6646 | | * @par api_copy |
6647 | | * #otThreadGetMaxTimeInQueue |
6648 | | * @csa{timeinqueue reset} |
6649 | | */ |
6650 | 4 | else if (aArgs[0] == "max") |
6651 | 1 | { |
6652 | 1 | OutputLine("%lu", ToUlong(otThreadGetMaxTimeInQueue(GetInstancePtr()))); |
6653 | 1 | } |
6654 | | /** |
6655 | | * @cli timeinqueue reset |
6656 | | * @code |
6657 | | * timeinqueue reset |
6658 | | * Done |
6659 | | * @endcode |
6660 | | * @par api_copy |
6661 | | * #otThreadResetTimeInQueueStat |
6662 | | */ |
6663 | 3 | else if (aArgs[0] == "reset") |
6664 | 1 | { |
6665 | 1 | otThreadResetTimeInQueueStat(GetInstancePtr()); |
6666 | 1 | } |
6667 | 2 | else |
6668 | 2 | { |
6669 | 2 | error = OT_ERROR_INVALID_ARGS; |
6670 | 2 | } |
6671 | | |
6672 | 5 | return error; |
6673 | 5 | } |
6674 | | #endif // OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE |
6675 | | |
6676 | 691 | template <> otError Interpreter::Process<Cmd("dataset")>(Arg aArgs[]) { return mDataset.Process(aArgs); } |
6677 | | |
6678 | | /** |
6679 | | * @cli txpower (get,set) |
6680 | | * @code |
6681 | | * txpower -10 |
6682 | | * Done |
6683 | | * @endcode |
6684 | | * @code |
6685 | | * txpower |
6686 | | * -10 dBm |
6687 | | * Done |
6688 | | * @endcode |
6689 | | * @cparam txpower [@ca{txpower}] |
6690 | | * @par |
6691 | | * Gets (or sets with the use of the optional `txpower` argument) the transmit power in dBm. |
6692 | | * @sa otPlatRadioGetTransmitPower |
6693 | | * @sa otPlatRadioSetTransmitPower |
6694 | | */ |
6695 | | template <> otError Interpreter::Process<Cmd("txpower")>(Arg aArgs[]) |
6696 | 305 | { |
6697 | 305 | otError error = OT_ERROR_NONE; |
6698 | 305 | int8_t power; |
6699 | | |
6700 | 305 | if (aArgs[0].IsEmpty()) |
6701 | 1 | { |
6702 | 1 | SuccessOrExit(error = otPlatRadioGetTransmitPower(GetInstancePtr(), &power)); |
6703 | 1 | OutputLine("%d dBm", power); |
6704 | 1 | } |
6705 | 304 | else |
6706 | 304 | { |
6707 | 304 | SuccessOrExit(error = aArgs[0].ParseAsInt8(power)); |
6708 | 29 | error = otPlatRadioSetTransmitPower(GetInstancePtr(), power); |
6709 | 29 | } |
6710 | | |
6711 | 305 | exit: |
6712 | 305 | return error; |
6713 | 305 | } |
6714 | | |
6715 | | /** |
6716 | | * @cli targetpower (set) |
6717 | | * @code |
6718 | | * targetpower 12 2000 |
6719 | | * Done |
6720 | | * @endcode |
6721 | | * @cparam targetpower @ca{channel} @ca{targetpower} |
6722 | | * @par |
6723 | | * Sets the target power in the unit of 0.01 dBm. |
6724 | | * @sa otPlatRadioSetChannelTargetPower |
6725 | | */ |
6726 | | template <> otError Interpreter::Process<Cmd("targetpower")>(Arg aArgs[]) |
6727 | 85 | { |
6728 | 85 | otError error = OT_ERROR_NONE; |
6729 | 85 | uint8_t channel; |
6730 | 85 | int16_t targetPower; |
6731 | 85 | uint32_t channelMask; |
6732 | | |
6733 | 85 | SuccessOrExit(error = aArgs[0].ParseAsUint8(channel)); |
6734 | 84 | VerifyOrExit(channel < BitSizeOf(channelMask), error = OT_ERROR_INVALID_ARGS); |
6735 | | |
6736 | 80 | channelMask = otLinkGetSupportedChannelMask(GetInstancePtr()); |
6737 | 80 | VerifyOrExit((1 << channel) & channelMask, error = OT_ERROR_INVALID_ARGS); |
6738 | | |
6739 | 76 | SuccessOrExit(error = aArgs[1].ParseAsInt16(targetPower)); |
6740 | | |
6741 | 41 | error = otPlatRadioSetChannelTargetPower(GetInstancePtr(), channel, targetPower); |
6742 | | |
6743 | 85 | exit: |
6744 | 85 | return error; |
6745 | 41 | } |
6746 | | |
6747 | | /** |
6748 | | * @cli debug |
6749 | | * @par |
6750 | | * Executes a series of CLI commands to gather information about the device and thread network. This is intended for |
6751 | | * debugging. |
6752 | | * The output will display each executed CLI command preceded by `$`, followed by the corresponding command's |
6753 | | * generated output. |
6754 | | * The generated output encompasses the following information: |
6755 | | * - Version |
6756 | | * - Current state |
6757 | | * - RLOC16, extended MAC address |
6758 | | * - Unicast and multicast IPv6 address list |
6759 | | * - Channel |
6760 | | * - PAN ID and extended PAN ID |
6761 | | * - Network Data |
6762 | | * - Partition ID |
6763 | | * - Leader Data |
6764 | | * @par |
6765 | | * If the device is operating as FTD: |
6766 | | * - Child and neighbor table |
6767 | | * - Router table and next hop info |
6768 | | * - Address cache table |
6769 | | * - Registered MTD child IPv6 address |
6770 | | * - Device properties |
6771 | | * @par |
6772 | | * If the device supports and acts as an SRP client: |
6773 | | * - SRP client state |
6774 | | * - SRP client services and host info |
6775 | | * @par |
6776 | | * If the device supports and acts as an SRP sever: |
6777 | | * - SRP server state and address mode |
6778 | | * - SRP server registered hosts and services |
6779 | | * @par |
6780 | | * If the device supports TREL: |
6781 | | * - TREL status and peer table |
6782 | | * @par |
6783 | | * If the device supports and acts as a border router: |
6784 | | * - BR state |
6785 | | * - BR prefixes (OMR, on-link, NAT64) |
6786 | | * - Discovered prefix table |
6787 | | */ |
6788 | | template <> otError Interpreter::Process<Cmd("debug")>(Arg aArgs[]) |
6789 | 17 | { |
6790 | 17 | static constexpr uint16_t kMaxDebugCommandSize = 30; |
6791 | | |
6792 | 17 | static const char *const kDebugCommands[] = { |
6793 | 17 | "version", |
6794 | 17 | "state", |
6795 | 17 | "rloc16", |
6796 | 17 | "extaddr", |
6797 | 17 | "ipaddr", |
6798 | 17 | "ipmaddr", |
6799 | 17 | "channel", |
6800 | 17 | "panid", |
6801 | 17 | "extpanid", |
6802 | 17 | "netdata show", |
6803 | 17 | "netdata show -x", |
6804 | 17 | "partitionid", |
6805 | 17 | "leaderdata", |
6806 | 17 | #if OPENTHREAD_FTD |
6807 | 17 | "child table", |
6808 | 17 | "childip", |
6809 | 17 | "neighbor table", |
6810 | 17 | "router table", |
6811 | 17 | "nexthop", |
6812 | 17 | "eidcache", |
6813 | | #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE |
6814 | | "deviceprops", |
6815 | | #endif |
6816 | 17 | #endif // OPENTHREAD_FTD |
6817 | 17 | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE |
6818 | 17 | "srp client state", |
6819 | 17 | "srp client host", |
6820 | 17 | "srp client service", |
6821 | 17 | "srp client server", |
6822 | 17 | #endif |
6823 | 17 | #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
6824 | 17 | "srp server state", |
6825 | 17 | "srp server addrmode", |
6826 | 17 | "srp server host", |
6827 | 17 | "srp server service", |
6828 | 17 | #endif |
6829 | | #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE |
6830 | | "trel", |
6831 | | "trel peers", |
6832 | | #endif |
6833 | 17 | #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
6834 | 17 | "br state", |
6835 | 17 | "br omrprefix", |
6836 | 17 | "br onlinkprefix", |
6837 | 17 | "br prefixtable", |
6838 | | #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE |
6839 | | "br nat64prefix", |
6840 | | #endif |
6841 | | #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE |
6842 | | "br pd state", |
6843 | | "br pd omrprefix", |
6844 | | #endif |
6845 | 17 | #endif |
6846 | 17 | "bufferinfo", |
6847 | 17 | }; |
6848 | | |
6849 | 17 | char commandString[kMaxDebugCommandSize]; |
6850 | | |
6851 | 17 | OT_UNUSED_VARIABLE(aArgs); |
6852 | | |
6853 | 17 | mInternalDebugCommand = true; |
6854 | | |
6855 | 17 | for (const char *debugCommand : kDebugCommands) |
6856 | 544 | { |
6857 | 544 | strncpy(commandString, debugCommand, sizeof(commandString) - 1); |
6858 | 544 | commandString[sizeof(commandString) - 1] = '\0'; |
6859 | | |
6860 | 544 | OutputLine("$ %s", commandString); |
6861 | 544 | ProcessLine(commandString); |
6862 | 544 | } |
6863 | | |
6864 | 17 | mInternalDebugCommand = false; |
6865 | | |
6866 | 17 | return OT_ERROR_NONE; |
6867 | 17 | } |
6868 | | |
6869 | | #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE |
6870 | | template <> otError Interpreter::Process<Cmd("tcat")>(Arg aArgs[]) { return mTcat.Process(aArgs); } |
6871 | | #endif |
6872 | | |
6873 | | #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE |
6874 | 152 | template <> otError Interpreter::Process<Cmd("tcp")>(Arg aArgs[]) { return mTcp.Process(aArgs); } |
6875 | | #endif |
6876 | | |
6877 | 25 | template <> otError Interpreter::Process<Cmd("udp")>(Arg aArgs[]) { return mUdp.Process(aArgs); } |
6878 | | |
6879 | | template <> otError Interpreter::Process<Cmd("unsecureport")>(Arg aArgs[]) |
6880 | 10 | { |
6881 | 10 | otError error = OT_ERROR_NONE; |
6882 | | |
6883 | | /** |
6884 | | * @cli unsecureport add |
6885 | | * @code |
6886 | | * unsecureport add 1234 |
6887 | | * Done |
6888 | | * @endcode |
6889 | | * @cparam unsecureport add @ca{port} |
6890 | | * @par api_copy |
6891 | | * #otIp6AddUnsecurePort |
6892 | | */ |
6893 | 10 | if (aArgs[0] == "add") |
6894 | 4 | { |
6895 | 4 | error = ProcessSet(aArgs + 1, otIp6AddUnsecurePort); |
6896 | 4 | } |
6897 | | /** |
6898 | | * @cli unsecureport remove |
6899 | | * @code |
6900 | | * unsecureport remove 1234 |
6901 | | * Done |
6902 | | * @endcode |
6903 | | * @code |
6904 | | * unsecureport remove all |
6905 | | * Done |
6906 | | * @endcode |
6907 | | * @cparam unsecureport remove @ca{port}|all |
6908 | | * @par |
6909 | | * Removes a specified port or all ports from the allowed unsecured port list. |
6910 | | * @sa otIp6AddUnsecurePort |
6911 | | * @sa otIp6RemoveAllUnsecurePorts |
6912 | | */ |
6913 | 6 | else if (aArgs[0] == "remove") |
6914 | 4 | { |
6915 | 4 | if (aArgs[1] == "all") |
6916 | 1 | { |
6917 | 1 | otIp6RemoveAllUnsecurePorts(GetInstancePtr()); |
6918 | 1 | } |
6919 | 3 | else |
6920 | 3 | { |
6921 | 3 | error = ProcessSet(aArgs + 1, otIp6RemoveUnsecurePort); |
6922 | 3 | } |
6923 | 4 | } |
6924 | | /** |
6925 | | * @cli unsecure get |
6926 | | * @code |
6927 | | * unsecure get |
6928 | | * 1234 |
6929 | | * Done |
6930 | | * @endcode |
6931 | | * @par |
6932 | | * Lists all ports from the allowed unsecured port list. |
6933 | | * @sa otIp6GetUnsecurePorts |
6934 | | */ |
6935 | 2 | else if (aArgs[0] == "get") |
6936 | 1 | { |
6937 | 1 | const uint16_t *ports; |
6938 | 1 | uint8_t numPorts; |
6939 | | |
6940 | 1 | ports = otIp6GetUnsecurePorts(GetInstancePtr(), &numPorts); |
6941 | | |
6942 | 1 | if (ports != nullptr) |
6943 | 1 | { |
6944 | 1 | for (uint8_t i = 0; i < numPorts; i++) |
6945 | 0 | { |
6946 | 0 | OutputFormat("%u ", ports[i]); |
6947 | 0 | } |
6948 | 1 | } |
6949 | | |
6950 | 1 | OutputNewLine(); |
6951 | 1 | } |
6952 | 1 | else |
6953 | 1 | { |
6954 | 1 | error = OT_ERROR_INVALID_COMMAND; |
6955 | 1 | } |
6956 | | |
6957 | 10 | return error; |
6958 | 10 | } |
6959 | | |
6960 | | #if OPENTHREAD_CONFIG_UPTIME_ENABLE |
6961 | | template <> otError Interpreter::Process<Cmd("uptime")>(Arg aArgs[]) |
6962 | 5 | { |
6963 | 5 | otError error = OT_ERROR_NONE; |
6964 | | |
6965 | | /** |
6966 | | * @cli uptime |
6967 | | * @code |
6968 | | * uptime |
6969 | | * 12:46:35.469 |
6970 | | * Done |
6971 | | * @endcode |
6972 | | * @par api_copy |
6973 | | * #otInstanceGetUptimeAsString |
6974 | | */ |
6975 | 5 | if (aArgs[0].IsEmpty()) |
6976 | 3 | { |
6977 | 3 | char string[OT_UPTIME_STRING_SIZE]; |
6978 | | |
6979 | 3 | otInstanceGetUptimeAsString(GetInstancePtr(), string, sizeof(string)); |
6980 | 3 | OutputLine("%s", string); |
6981 | 3 | } |
6982 | | |
6983 | | /** |
6984 | | * @cli uptime ms |
6985 | | * @code |
6986 | | * uptime ms |
6987 | | * 426238 |
6988 | | * Done |
6989 | | * @endcode |
6990 | | * @par api_copy |
6991 | | * #otInstanceGetUptime |
6992 | | */ |
6993 | 2 | else if (aArgs[0] == "ms") |
6994 | 1 | { |
6995 | 1 | OutputUint64Line(otInstanceGetUptime(GetInstancePtr())); |
6996 | 1 | } |
6997 | 1 | else |
6998 | 1 | { |
6999 | 1 | error = OT_ERROR_INVALID_ARGS; |
7000 | 1 | } |
7001 | | |
7002 | 5 | return error; |
7003 | 5 | } |
7004 | | #endif |
7005 | | |
7006 | | #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD |
7007 | 171 | template <> otError Interpreter::Process<Cmd("commissioner")>(Arg aArgs[]) { return mCommissioner.Process(aArgs); } |
7008 | | #endif |
7009 | | |
7010 | | #if OPENTHREAD_CONFIG_JOINER_ENABLE |
7011 | 216 | template <> otError Interpreter::Process<Cmd("joiner")>(Arg aArgs[]) { return mJoiner.Process(aArgs); } |
7012 | | #endif |
7013 | | |
7014 | | #if OPENTHREAD_FTD |
7015 | | /** |
7016 | | * @cli joinerport |
7017 | | * @code |
7018 | | * joinerport |
7019 | | * 1000 |
7020 | | * Done |
7021 | | * @endcode |
7022 | | * @par api_copy |
7023 | | * #otThreadGetJoinerUdpPort |
7024 | | */ |
7025 | | template <> otError Interpreter::Process<Cmd("joinerport")>(Arg aArgs[]) |
7026 | 4 | { |
7027 | | /** |
7028 | | * @cli joinerport (set) |
7029 | | * @code |
7030 | | * joinerport 1000 |
7031 | | * Done |
7032 | | * @endcode |
7033 | | * @cparam joinerport @ca{udp-port} |
7034 | | * @par api_copy |
7035 | | * #otThreadSetJoinerUdpPort |
7036 | | */ |
7037 | 4 | return ProcessGetSet(aArgs, otThreadGetJoinerUdpPort, otThreadSetJoinerUdpPort); |
7038 | 4 | } |
7039 | | #endif |
7040 | | |
7041 | | #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |
7042 | 34 | template <> otError Interpreter::Process<Cmd("macfilter")>(Arg aArgs[]) { return mMacFilter.Process(aArgs); } |
7043 | | #endif |
7044 | | |
7045 | | template <> otError Interpreter::Process<Cmd("mac")>(Arg aArgs[]) |
7046 | 10 | { |
7047 | 10 | otError error = OT_ERROR_NONE; |
7048 | | |
7049 | | /** |
7050 | | * @cli mac altshortaddr |
7051 | | * @code |
7052 | | * mac altshortaddr |
7053 | | * 0x4802 |
7054 | | * Done |
7055 | | * @endcode |
7056 | | * @par api_copy |
7057 | | * #otLinkGetAlternateShortAddress |
7058 | | */ |
7059 | 10 | if (aArgs[0] == "altshortaddr") |
7060 | 0 | { |
7061 | 0 | OutputLine("0x%04x", otLinkGetAlternateShortAddress(GetInstancePtr())); |
7062 | 0 | } |
7063 | 10 | else if (aArgs[0] == "retries") |
7064 | 9 | { |
7065 | | /** |
7066 | | * @cli mac retries direct (get,set) |
7067 | | * @code |
7068 | | * mac retries direct |
7069 | | * 3 |
7070 | | * Done |
7071 | | * @endcode |
7072 | | * @code |
7073 | | * mac retries direct 5 |
7074 | | * Done |
7075 | | * @endcode |
7076 | | * @cparam mac retries direct [@ca{number}] |
7077 | | * Use the optional `number` argument to set the number of direct TX retries. |
7078 | | * @par |
7079 | | * Gets or sets the number of direct TX retries on the MAC layer. |
7080 | | * @sa otLinkGetMaxFrameRetriesDirect |
7081 | | * @sa otLinkSetMaxFrameRetriesDirect |
7082 | | */ |
7083 | 9 | if (aArgs[1] == "direct") |
7084 | 4 | { |
7085 | 4 | error = ProcessGetSet(aArgs + 2, otLinkGetMaxFrameRetriesDirect, otLinkSetMaxFrameRetriesDirect); |
7086 | 4 | } |
7087 | 5 | #if OPENTHREAD_FTD |
7088 | | /** |
7089 | | * @cli mac retries indirect (get,set) |
7090 | | * @code |
7091 | | * mac retries indirect |
7092 | | * 3 |
7093 | | * Done |
7094 | | * @endcode |
7095 | | * @code max retries indirect 5 |
7096 | | * Done |
7097 | | * @endcode |
7098 | | * @cparam mac retries indirect [@ca{number}] |
7099 | | * Use the optional `number` argument to set the number of indirect Tx retries. |
7100 | | * @par |
7101 | | * Gets or sets the number of indirect TX retries on the MAC layer. |
7102 | | * @sa otLinkGetMaxFrameRetriesIndirect |
7103 | | * @sa otLinkSetMaxFrameRetriesIndirect |
7104 | | */ |
7105 | 5 | else if (aArgs[1] == "indirect") |
7106 | 4 | { |
7107 | 4 | error = ProcessGetSet(aArgs + 2, otLinkGetMaxFrameRetriesIndirect, otLinkSetMaxFrameRetriesIndirect); |
7108 | 4 | } |
7109 | 1 | #endif |
7110 | 1 | else |
7111 | 1 | { |
7112 | 1 | error = OT_ERROR_INVALID_ARGS; |
7113 | 1 | } |
7114 | 9 | } |
7115 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
7116 | | /** |
7117 | | * @cli mac send |
7118 | | * @code |
7119 | | * mac send datarequest |
7120 | | * Done |
7121 | | * @endcode |
7122 | | * @code |
7123 | | * mac send emptydata |
7124 | | * Done |
7125 | | * @endcode |
7126 | | * @cparam mac send @ca{datarequest} | @ca{emptydata} |
7127 | | * You must choose one of the following two arguments: |
7128 | | * - `datarequest`: Enqueues an IEEE 802.15.4 Data Request message for transmission. |
7129 | | * - `emptydata`: Instructs the device to send an empty IEEE 802.15.4 data frame. |
7130 | | * @par |
7131 | | * Instructs an `Rx-Off-When-Idle` device to send a MAC frame to its parent. |
7132 | | * This command is for certification, and can only be used when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is |
7133 | | * enabled. |
7134 | | * @sa otLinkSendDataRequest |
7135 | | * @sa otLinkSendEmptyData |
7136 | | */ |
7137 | | else if (aArgs[0] == "send") |
7138 | | { |
7139 | | VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
7140 | | |
7141 | | if (aArgs[1] == "datarequest") |
7142 | | { |
7143 | | error = otLinkSendDataRequest(GetInstancePtr()); |
7144 | | } |
7145 | | else if (aArgs[1] == "emptydata") |
7146 | | { |
7147 | | error = otLinkSendEmptyData(GetInstancePtr()); |
7148 | | } |
7149 | | else |
7150 | | { |
7151 | | error = OT_ERROR_INVALID_ARGS; |
7152 | | } |
7153 | | } |
7154 | | #endif |
7155 | 1 | else |
7156 | 1 | { |
7157 | 1 | error = OT_ERROR_INVALID_COMMAND; |
7158 | 1 | ExitNow(); // To silence unused `exit` label warning when `REFERENCE_DEVICE_ENABLE` is not enabled. |
7159 | 1 | } |
7160 | | |
7161 | 10 | exit: |
7162 | 10 | return error; |
7163 | 10 | } |
7164 | | |
7165 | | /** |
7166 | | * @cli trel |
7167 | | * @code |
7168 | | * trel |
7169 | | * Enabled |
7170 | | * Done |
7171 | | * @endcode |
7172 | | * @par api_copy |
7173 | | * #otTrelIsEnabled |
7174 | | * @note `OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE` is required for all `trel` sub-commands. |
7175 | | */ |
7176 | | #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE |
7177 | | template <> otError Interpreter::Process<Cmd("trel")>(Arg aArgs[]) |
7178 | | { |
7179 | | otError error = OT_ERROR_NONE; |
7180 | | |
7181 | | /** |
7182 | | * @cli trel (enable,disable) |
7183 | | * @code |
7184 | | * trel enable |
7185 | | * Done |
7186 | | * @endcode |
7187 | | * @code |
7188 | | * trel disable |
7189 | | * Done |
7190 | | * @endcode |
7191 | | * @cparam trel @ca{enable}|@ca{disable} |
7192 | | * @par |
7193 | | * Enables or disables the TREL radio operation. |
7194 | | * @sa otTrelSetEnabled |
7195 | | */ |
7196 | | if (ProcessEnableDisable(aArgs, otTrelIsEnabled, otTrelSetEnabled) == OT_ERROR_NONE) |
7197 | | { |
7198 | | } |
7199 | | /** |
7200 | | * @cli trel filter |
7201 | | * @code |
7202 | | * trel filter |
7203 | | * Disabled |
7204 | | * Done |
7205 | | * @endcode |
7206 | | * @par |
7207 | | * Indicates whether TREL filter mode is enabled. |
7208 | | * @par |
7209 | | * When filter mode is enabled, all Rx and Tx traffic sent through the TREL interface gets silently dropped. |
7210 | | * @note This mode is used mostly for testing. |
7211 | | * @sa otTrelIsFilterEnabled |
7212 | | */ |
7213 | | else if (aArgs[0] == "filter") |
7214 | | /** |
7215 | | * @cli trel filter (enable,disable) |
7216 | | * @code |
7217 | | * trel filter enable |
7218 | | * Done |
7219 | | * @endcode |
7220 | | * @code |
7221 | | * trel filter disable |
7222 | | * Done |
7223 | | * @endcode |
7224 | | * @cparam trel filter @ca{enable}|@ca{disable} |
7225 | | * @par |
7226 | | * Enables or disables TREL filter mode. |
7227 | | * @sa otTrelSetFilterEnabled |
7228 | | */ |
7229 | | { |
7230 | | error = ProcessEnableDisable(aArgs + 1, otTrelIsFilterEnabled, otTrelSetFilterEnabled); |
7231 | | } |
7232 | | /** |
7233 | | * @cli trel peers |
7234 | | * @code |
7235 | | * trel peers |
7236 | | * | No | Ext MAC Address | Ext PAN Id | IPv6 Socket Address | |
7237 | | * +-----+------------------+------------------+--------------------------------------------------+ |
7238 | | * | 1 | 5e5785ba3a63adb9 | f0d9c001f00d2e43 | [fe80:0:0:0:cc79:2a29:d311:1aea]:9202 | |
7239 | | * | 2 | ce792a29d3111aea | dead00beef00cafe | [fe80:0:0:0:5c57:85ba:3a63:adb9]:9203 | |
7240 | | * Done |
7241 | | * @endcode |
7242 | | * @code |
7243 | | * trel peers list |
7244 | | * 001 ExtAddr:5e5785ba3a63adb9 ExtPanId:f0d9c001f00d2e43 SockAddr:[fe80:0:0:0:cc79:2a29:d311:1aea]:9202 |
7245 | | * 002 ExtAddr:ce792a29d3111aea ExtPanId:dead00beef00cafe SockAddr:[fe80:0:0:0:5c57:85ba:3a63:adb9]:9203 |
7246 | | * Done |
7247 | | * @endcode |
7248 | | * @cparam trel peers [@ca{list}] |
7249 | | * @par |
7250 | | * Gets the TREL peer table in table or list format. |
7251 | | * @sa otTrelGetNextPeer |
7252 | | */ |
7253 | | else if (aArgs[0] == "peers") |
7254 | | { |
7255 | | uint16_t index = 0; |
7256 | | otTrelPeerIterator iterator; |
7257 | | const otTrelPeer *peer; |
7258 | | bool isTable = true; |
7259 | | |
7260 | | if (aArgs[1] == "list") |
7261 | | { |
7262 | | isTable = false; |
7263 | | } |
7264 | | else |
7265 | | { |
7266 | | VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
7267 | | } |
7268 | | |
7269 | | if (isTable) |
7270 | | { |
7271 | | static const char *const kTrelPeerTableTitles[] = {"No", "Ext MAC Address", "Ext PAN Id", |
7272 | | "IPv6 Socket Address"}; |
7273 | | |
7274 | | static const uint8_t kTrelPeerTableColumnWidths[] = {5, 18, 18, 50}; |
7275 | | |
7276 | | OutputTableHeader(kTrelPeerTableTitles, kTrelPeerTableColumnWidths); |
7277 | | } |
7278 | | |
7279 | | otTrelInitPeerIterator(GetInstancePtr(), &iterator); |
7280 | | |
7281 | | while ((peer = otTrelGetNextPeer(GetInstancePtr(), &iterator)) != nullptr) |
7282 | | { |
7283 | | if (!isTable) |
7284 | | { |
7285 | | OutputFormat("%03u ExtAddr:", ++index); |
7286 | | OutputExtAddress(peer->mExtAddress); |
7287 | | OutputFormat(" ExtPanId:"); |
7288 | | OutputBytes(peer->mExtPanId.m8); |
7289 | | OutputFormat(" SockAddr:"); |
7290 | | OutputSockAddrLine(peer->mSockAddr); |
7291 | | } |
7292 | | else |
7293 | | { |
7294 | | char string[OT_IP6_SOCK_ADDR_STRING_SIZE]; |
7295 | | |
7296 | | OutputFormat("| %3u | ", ++index); |
7297 | | OutputExtAddress(peer->mExtAddress); |
7298 | | OutputFormat(" | "); |
7299 | | OutputBytes(peer->mExtPanId.m8); |
7300 | | otIp6SockAddrToString(&peer->mSockAddr, string, sizeof(string)); |
7301 | | OutputLine(" | %-48s |", string); |
7302 | | } |
7303 | | } |
7304 | | } |
7305 | | /** |
7306 | | * @cli trel counters |
7307 | | * @code |
7308 | | * trel counters |
7309 | | * Inbound: Packets 32 Bytes 4000 |
7310 | | * Outbound: Packets 4 Bytes 320 Failures 1 |
7311 | | * Done |
7312 | | * @endcode |
7313 | | * @par api_copy |
7314 | | * #otTrelGetCounters |
7315 | | */ |
7316 | | else if (aArgs[0] == "counters") |
7317 | | { |
7318 | | if (aArgs[1].IsEmpty()) |
7319 | | { |
7320 | | OutputTrelCounters(*otTrelGetCounters(GetInstancePtr())); |
7321 | | } |
7322 | | /** |
7323 | | * @cli trel counters reset |
7324 | | * @code |
7325 | | * trel counters reset |
7326 | | * Done |
7327 | | * @endcode |
7328 | | * @par api_copy |
7329 | | * #otTrelResetCounters |
7330 | | */ |
7331 | | else if ((aArgs[1] == "reset") && aArgs[2].IsEmpty()) |
7332 | | { |
7333 | | otTrelResetCounters(GetInstancePtr()); |
7334 | | } |
7335 | | else |
7336 | | { |
7337 | | error = OT_ERROR_INVALID_ARGS; |
7338 | | } |
7339 | | } |
7340 | | /** |
7341 | | * @cli trel port |
7342 | | * @code |
7343 | | * trel port |
7344 | | * 49153 |
7345 | | * Done |
7346 | | * @endcode |
7347 | | * @par api_copy |
7348 | | * #otTrelGetUdpPort |
7349 | | */ |
7350 | | else if (aArgs[0] == "port") |
7351 | | { |
7352 | | OutputLine("%hu", otTrelGetUdpPort(GetInstancePtr())); |
7353 | | } |
7354 | | else |
7355 | | { |
7356 | | error = OT_ERROR_INVALID_ARGS; |
7357 | | } |
7358 | | |
7359 | | exit: |
7360 | | return error; |
7361 | | } |
7362 | | |
7363 | | void Interpreter::OutputTrelCounters(const otTrelCounters &aCounters) |
7364 | | { |
7365 | | Uint64StringBuffer u64StringBuffer; |
7366 | | |
7367 | | OutputFormat("Inbound: Packets %s ", Uint64ToString(aCounters.mRxPackets, u64StringBuffer)); |
7368 | | OutputLine("Bytes %s", Uint64ToString(aCounters.mRxBytes, u64StringBuffer)); |
7369 | | |
7370 | | OutputFormat("Outbound: Packets %s ", Uint64ToString(aCounters.mTxPackets, u64StringBuffer)); |
7371 | | OutputFormat("Bytes %s ", Uint64ToString(aCounters.mTxBytes, u64StringBuffer)); |
7372 | | OutputLine("Failures %s", Uint64ToString(aCounters.mTxFailure, u64StringBuffer)); |
7373 | | } |
7374 | | |
7375 | | #endif |
7376 | | |
7377 | | template <> otError Interpreter::Process<Cmd("vendor")>(Arg aArgs[]) |
7378 | 9 | { |
7379 | 9 | Error error = OT_ERROR_INVALID_ARGS; |
7380 | | |
7381 | | /** |
7382 | | * @cli vendor name |
7383 | | * @code |
7384 | | * vendor name |
7385 | | * nest |
7386 | | * Done |
7387 | | * @endcode |
7388 | | * @par api_copy |
7389 | | * #otThreadGetVendorName |
7390 | | */ |
7391 | 9 | if (aArgs[0] == "name") |
7392 | 2 | { |
7393 | 2 | aArgs++; |
7394 | | |
7395 | 2 | #if !OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
7396 | 2 | error = ProcessGet(aArgs, otThreadGetVendorName); |
7397 | | #else |
7398 | | /** |
7399 | | * @cli vendor name (set) |
7400 | | * @code |
7401 | | * vendor name nest |
7402 | | * Done |
7403 | | * @endcode |
7404 | | * @par api_copy |
7405 | | * #otThreadSetVendorName |
7406 | | * @cparam vendor name @ca{name} |
7407 | | */ |
7408 | | error = ProcessGetSet(aArgs, otThreadGetVendorName, otThreadSetVendorName); |
7409 | | #endif |
7410 | 2 | } |
7411 | | /** |
7412 | | * @cli vendor model |
7413 | | * @code |
7414 | | * vendor model |
7415 | | * Hub Max |
7416 | | * Done |
7417 | | * @endcode |
7418 | | * @par api_copy |
7419 | | * #otThreadGetVendorModel |
7420 | | */ |
7421 | 7 | else if (aArgs[0] == "model") |
7422 | 2 | { |
7423 | 2 | aArgs++; |
7424 | | |
7425 | 2 | #if !OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
7426 | 2 | error = ProcessGet(aArgs, otThreadGetVendorModel); |
7427 | | #else |
7428 | | /** |
7429 | | * @cli vendor model (set) |
7430 | | * @code |
7431 | | * vendor model Hub\ Max |
7432 | | * Done |
7433 | | * @endcode |
7434 | | * @par api_copy |
7435 | | * #otThreadSetVendorModel |
7436 | | * @cparam vendor model @ca{name} |
7437 | | */ |
7438 | | error = ProcessGetSet(aArgs, otThreadGetVendorModel, otThreadSetVendorModel); |
7439 | | #endif |
7440 | 2 | } |
7441 | | /** |
7442 | | * @cli vendor swversion |
7443 | | * @code |
7444 | | * vendor swversion |
7445 | | * Marble3.5.1 |
7446 | | * Done |
7447 | | * @endcode |
7448 | | * @par api_copy |
7449 | | * #otThreadGetVendorSwVersion |
7450 | | */ |
7451 | 5 | else if (aArgs[0] == "swversion") |
7452 | 2 | { |
7453 | 2 | aArgs++; |
7454 | | |
7455 | 2 | #if !OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
7456 | 2 | error = ProcessGet(aArgs, otThreadGetVendorSwVersion); |
7457 | | #else |
7458 | | /** |
7459 | | * @cli vendor swversion (set) |
7460 | | * @code |
7461 | | * vendor swversion Marble3.5.1 |
7462 | | * Done |
7463 | | * @endcode |
7464 | | * @par api_copy |
7465 | | * #otThreadSetVendorSwVersion |
7466 | | * @cparam vendor swversion @ca{version} |
7467 | | */ |
7468 | | error = ProcessGetSet(aArgs, otThreadGetVendorSwVersion, otThreadSetVendorSwVersion); |
7469 | | #endif |
7470 | 2 | } |
7471 | | /** |
7472 | | * @cli vendor appurl |
7473 | | * @code |
7474 | | * vendor appurl |
7475 | | * http://www.example.com |
7476 | | * Done |
7477 | | * @endcode |
7478 | | * @par api_copy |
7479 | | * #otThreadGetVendorAppUrl |
7480 | | */ |
7481 | 3 | else if (aArgs[0] == "appurl") |
7482 | 2 | { |
7483 | 2 | aArgs++; |
7484 | | |
7485 | 2 | #if !OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE |
7486 | 2 | error = ProcessGet(aArgs, otThreadGetVendorAppUrl); |
7487 | | #else |
7488 | | /** |
7489 | | * @cli vendor appurl (set) |
7490 | | * @code |
7491 | | * vendor appurl http://www.example.com |
7492 | | * Done |
7493 | | * @endcode |
7494 | | * @par api_copy |
7495 | | * #otThreadSetVendorAppUrl |
7496 | | * @cparam vendor appurl @ca{url} |
7497 | | */ |
7498 | | error = ProcessGetSet(aArgs, otThreadGetVendorAppUrl, otThreadSetVendorAppUrl); |
7499 | | #endif |
7500 | 2 | } |
7501 | | |
7502 | 9 | return error; |
7503 | 9 | } |
7504 | | |
7505 | | #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
7506 | | |
7507 | | template <> otError Interpreter::Process<Cmd("networkdiagnostic")>(Arg aArgs[]) |
7508 | 58 | { |
7509 | 58 | static constexpr uint16_t kMaxTlvs = 35; |
7510 | | |
7511 | 58 | otError error = OT_ERROR_NONE; |
7512 | 58 | otIp6Address address; |
7513 | 58 | uint8_t tlvTypes[kMaxTlvs]; |
7514 | 58 | uint8_t count = 0; |
7515 | | |
7516 | 58 | if (aArgs[0] == "nonpreferredchannels") |
7517 | 0 | { |
7518 | | /** |
7519 | | * @cli networkdiagnostic nonpreferredchannels |
7520 | | * @code |
7521 | | * networkdiagnostic nonpreferredchannels |
7522 | | * 0x4000000 |
7523 | | * Done |
7524 | | * @endcode |
7525 | | * @par api_copy |
7526 | | * #otThreadGetNonPreferredChannels |
7527 | | */ |
7528 | 0 | if (aArgs[1].IsEmpty()) |
7529 | 0 | { |
7530 | 0 | OutputLine("0x%lx", ToUlong(otThreadGetNonPreferredChannels(GetInstancePtr()))); |
7531 | 0 | } |
7532 | | /** |
7533 | | * @cli networkdiagnostic nonpreferredchannels (set) |
7534 | | * @code |
7535 | | * networkdiagnostic nonpreferredchannels 0x4000000 |
7536 | | * Done |
7537 | | * @endcode |
7538 | | * @par api_copy |
7539 | | * #otThreadSetNonPreferredChannels |
7540 | | * @cparam networkdiagnostic nonprfchannelmas @ca{mask} |
7541 | | */ |
7542 | 0 | else |
7543 | 0 | { |
7544 | 0 | otChannelMask mask; |
7545 | |
|
7546 | 0 | SuccessOrExit(error = aArgs[1].ParseAsUint32(mask)); |
7547 | 0 | VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
7548 | 0 | otThreadSetNonPreferredChannels(GetInstancePtr(), mask); |
7549 | 0 | } |
7550 | | |
7551 | 0 | ExitNow(); |
7552 | 0 | } |
7553 | | |
7554 | | // Process args for `get` and `reset` commands. |
7555 | | |
7556 | 58 | SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); |
7557 | | |
7558 | 212 | for (Arg *arg = &aArgs[2]; !arg->IsEmpty(); arg++) |
7559 | 168 | { |
7560 | 168 | VerifyOrExit(count < sizeof(tlvTypes), error = OT_ERROR_INVALID_ARGS); |
7561 | 168 | SuccessOrExit(error = arg->ParseAsUint8(tlvTypes[count++])); |
7562 | 168 | } |
7563 | | |
7564 | | /** |
7565 | | * @cli networkdiagnostic get |
7566 | | * @code |
7567 | | * networkdiagnostic get fdde:ad00:beef:0:0:ff:fe00:fc00 0 1 6 23 |
7568 | | * DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c000608640b0f674074c503 |
7569 | | * Ext Address: 0e336e1c41494e1c |
7570 | | * Rloc16: 0x0c00 |
7571 | | * Leader Data: |
7572 | | * PartitionId: 0x640b0f67 |
7573 | | * Weighting: 64 |
7574 | | * DataVersion: 116 |
7575 | | * StableDataVersion: 197 |
7576 | | * LeaderRouterId: 0x03 |
7577 | | * EUI64: 18b4300000000004 |
7578 | | * Done |
7579 | | * @endcode |
7580 | | * @code |
7581 | | * networkdiagnostic get ff02::1 0 1 |
7582 | | * DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c00 |
7583 | | * Ext Address: 0e336e1c41494e1c |
7584 | | * Rloc16: 0x0c00 |
7585 | | * Done |
7586 | | * DIAG_GET.rsp/ans: 00083efcdb7e3f9eb0f201021800 |
7587 | | * Ext Address: 3efcdb7e3f9eb0f2 |
7588 | | * Rloc16: 0x1800 |
7589 | | * Done |
7590 | | * @endcode |
7591 | | * @cparam networkdiagnostic get @ca{addr} @ca{type(s)} |
7592 | | * For `addr`, a unicast address triggers a `Diagnostic Get`. |
7593 | | * A multicast address triggers a `Diagnostic Query`. |
7594 | | * TLV values you can specify (separated by a space if you specify more than one TLV): |
7595 | | * - `0`: MAC Extended Address TLV |
7596 | | * - `1`: Address16 TLV |
7597 | | * - `2`: Mode TLV |
7598 | | * - `3`: Timeout TLV (the maximum polling time period for SEDs) |
7599 | | * - `4`: Connectivity TLV |
7600 | | * - `5`: Route64 TLV |
7601 | | * - `6`: Leader Data TLV |
7602 | | * - `7`: Network Data TLV |
7603 | | * - `8`: IPv6 Address List TLV |
7604 | | * - `9`: MAC Counters TLV |
7605 | | * - `14`: Battery Level TLV |
7606 | | * - `15`: Supply Voltage TLV |
7607 | | * - `16`: Child Table TLV |
7608 | | * - `17`: Channel Pages TLV |
7609 | | * - `19`: Max Child Timeout TLV |
7610 | | * - `23`: EUI64 TLV |
7611 | | * - `24`: Version TLV (version number for the protocols and features) |
7612 | | * - `25`: Vendor Name TLV |
7613 | | * - `26`: Vendor Model TLV |
7614 | | * - `27`: Vendor SW Version TLV |
7615 | | * - `28`: Thread Stack Version TLV (version identifier as UTF-8 string for Thread stack codebase/commit/version) |
7616 | | * - `29`: Child TLV |
7617 | | * - `34`: MLE Counters TLV |
7618 | | * - `35`: Vendor App URL TLV |
7619 | | * - `37`: Enhanced Route TLV |
7620 | | * @par |
7621 | | * Sends a network diagnostic request to retrieve specified Type Length Values (TLVs) |
7622 | | * for the specified addresses(es). |
7623 | | * @sa otThreadSendDiagnosticGet |
7624 | | */ |
7625 | | |
7626 | 44 | if (aArgs[0] == "get") |
7627 | 27 | { |
7628 | 27 | SuccessOrExit(error = otThreadSendDiagnosticGet(GetInstancePtr(), &address, tlvTypes, count, |
7629 | 27 | &Interpreter::HandleDiagnosticGetResponse, this)); |
7630 | 25 | SetCommandTimeout(kNetworkDiagnosticTimeoutMsecs); |
7631 | 25 | error = OT_ERROR_PENDING; |
7632 | 25 | } |
7633 | | /** |
7634 | | * @cli networkdiagnostic reset |
7635 | | * @code |
7636 | | * networkdiagnostic reset fd00:db8::ff:fe00:0 9 |
7637 | | * Done |
7638 | | * @endcode |
7639 | | * @cparam networkdiagnostic reset @ca{addr} @ca{type(s)} |
7640 | | * @par |
7641 | | * Sends a network diagnostic request to reset the specified Type Length Values (TLVs) |
7642 | | * on the specified address(es). This command only supports the |
7643 | | * following TLV values: `9` (MAC Counters TLV) or `34` (MLE |
7644 | | * Counters TLV) |
7645 | | * @sa otThreadSendDiagnosticReset |
7646 | | */ |
7647 | 17 | else if (aArgs[0] == "reset") |
7648 | 2 | { |
7649 | 2 | IgnoreError(otThreadSendDiagnosticReset(GetInstancePtr(), &address, tlvTypes, count)); |
7650 | 2 | } |
7651 | 15 | else |
7652 | 15 | { |
7653 | 15 | error = OT_ERROR_INVALID_COMMAND; |
7654 | 15 | } |
7655 | | |
7656 | 58 | exit: |
7657 | 58 | return error; |
7658 | 44 | } |
7659 | | |
7660 | | void Interpreter::HandleDiagnosticGetResponse(otError aError, |
7661 | | otMessage *aMessage, |
7662 | | const otMessageInfo *aMessageInfo, |
7663 | | void *aContext) |
7664 | 21 | { |
7665 | 21 | static_cast<Interpreter *>(aContext)->HandleDiagnosticGetResponse( |
7666 | 21 | aError, aMessage, static_cast<const Ip6::MessageInfo *>(aMessageInfo)); |
7667 | 21 | } |
7668 | | |
7669 | | void Interpreter::HandleDiagnosticGetResponse(otError aError, |
7670 | | const otMessage *aMessage, |
7671 | | const Ip6::MessageInfo *aMessageInfo) |
7672 | 21 | { |
7673 | 21 | uint8_t buf[16]; |
7674 | 21 | uint16_t bytesToPrint; |
7675 | 21 | uint16_t bytesPrinted = 0; |
7676 | 21 | uint16_t length; |
7677 | 21 | otNetworkDiagTlv diagTlv; |
7678 | 21 | otNetworkDiagIterator iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT; |
7679 | | |
7680 | 21 | SuccessOrExit(aError); |
7681 | | |
7682 | 0 | OutputFormat("DIAG_GET.rsp/ans from "); |
7683 | 0 | OutputIp6Address(aMessageInfo->mPeerAddr); |
7684 | 0 | OutputFormat(": "); |
7685 | |
|
7686 | 0 | length = otMessageGetLength(aMessage) - otMessageGetOffset(aMessage); |
7687 | |
|
7688 | 0 | while (length > 0) |
7689 | 0 | { |
7690 | 0 | bytesToPrint = Min(length, static_cast<uint16_t>(sizeof(buf))); |
7691 | 0 | otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint); |
7692 | |
|
7693 | 0 | OutputBytes(buf, static_cast<uint8_t>(bytesToPrint)); |
7694 | |
|
7695 | 0 | length -= bytesToPrint; |
7696 | 0 | bytesPrinted += bytesToPrint; |
7697 | 0 | } |
7698 | |
|
7699 | 0 | OutputNewLine(); |
7700 | | |
7701 | | // Output Network Diagnostic TLV values in standard YAML format. |
7702 | 0 | while (otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv) == OT_ERROR_NONE) |
7703 | 0 | { |
7704 | 0 | switch (diagTlv.mType) |
7705 | 0 | { |
7706 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS: |
7707 | 0 | OutputFormat("Ext Address: "); |
7708 | 0 | OutputExtAddressLine(diagTlv.mData.mExtAddress); |
7709 | 0 | break; |
7710 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS: |
7711 | 0 | OutputLine("Rloc16: 0x%04x", diagTlv.mData.mAddr16); |
7712 | 0 | break; |
7713 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_MODE: |
7714 | 0 | OutputLine("Mode:"); |
7715 | 0 | OutputMode(kIndentSize, diagTlv.mData.mMode); |
7716 | 0 | break; |
7717 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT: |
7718 | 0 | OutputLine("Timeout: %lu", ToUlong(diagTlv.mData.mTimeout)); |
7719 | 0 | break; |
7720 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY: |
7721 | 0 | OutputLine("Connectivity:"); |
7722 | 0 | OutputConnectivity(kIndentSize, diagTlv.mData.mConnectivity); |
7723 | 0 | break; |
7724 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_ROUTE: |
7725 | 0 | OutputLine("Route:"); |
7726 | 0 | OutputRoute(kIndentSize, diagTlv.mData.mRoute); |
7727 | 0 | break; |
7728 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_ENHANCED_ROUTE: |
7729 | 0 | OutputLine("EnhRoute:"); |
7730 | 0 | OutputEnhRoute(kIndentSize, diagTlv.mData.mEnhRoute); |
7731 | 0 | break; |
7732 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA: |
7733 | 0 | OutputLine("Leader Data:"); |
7734 | 0 | OutputLeaderData(kIndentSize, diagTlv.mData.mLeaderData); |
7735 | 0 | break; |
7736 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA: |
7737 | 0 | OutputFormat("Network Data: "); |
7738 | 0 | OutputBytesLine(diagTlv.mData.mNetworkData.m8, diagTlv.mData.mNetworkData.mCount); |
7739 | 0 | break; |
7740 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST: |
7741 | 0 | OutputLine("IP6 Address List:"); |
7742 | 0 | for (uint16_t i = 0; i < diagTlv.mData.mIp6AddrList.mCount; ++i) |
7743 | 0 | { |
7744 | 0 | OutputFormat(kIndentSize, "- "); |
7745 | 0 | OutputIp6AddressLine(diagTlv.mData.mIp6AddrList.mList[i]); |
7746 | 0 | } |
7747 | 0 | break; |
7748 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS: |
7749 | 0 | OutputLine("MAC Counters:"); |
7750 | 0 | OutputNetworkDiagMacCounters(kIndentSize, diagTlv.mData.mMacCounters); |
7751 | 0 | break; |
7752 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS: |
7753 | 0 | OutputLine("MLE Counters:"); |
7754 | 0 | OutputNetworkDiagMleCounters(kIndentSize, diagTlv.mData.mMleCounters); |
7755 | 0 | break; |
7756 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL: |
7757 | 0 | OutputLine("Battery Level: %u%%", diagTlv.mData.mBatteryLevel); |
7758 | 0 | break; |
7759 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE: |
7760 | 0 | OutputLine("Supply Voltage: %umV", diagTlv.mData.mSupplyVoltage); |
7761 | 0 | break; |
7762 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE: |
7763 | 0 | OutputLine("Child Table:"); |
7764 | 0 | for (uint16_t i = 0; i < diagTlv.mData.mChildTable.mCount; ++i) |
7765 | 0 | { |
7766 | 0 | OutputFormat(kIndentSize, "- "); |
7767 | 0 | OutputChildTableEntry(kIndentSize + 2, diagTlv.mData.mChildTable.mTable[i]); |
7768 | 0 | } |
7769 | 0 | break; |
7770 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES: |
7771 | 0 | OutputFormat("Channel Pages: '"); |
7772 | 0 | OutputBytes(diagTlv.mData.mChannelPages.m8, diagTlv.mData.mChannelPages.mCount); |
7773 | 0 | OutputLine("'"); |
7774 | 0 | break; |
7775 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT: |
7776 | 0 | OutputLine("Max Child Timeout: %lu", ToUlong(diagTlv.mData.mMaxChildTimeout)); |
7777 | 0 | break; |
7778 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_EUI64: |
7779 | 0 | OutputFormat("EUI64: "); |
7780 | 0 | OutputExtAddressLine(diagTlv.mData.mEui64); |
7781 | 0 | break; |
7782 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_NAME: |
7783 | 0 | OutputLine("Vendor Name: %s", diagTlv.mData.mVendorName); |
7784 | 0 | break; |
7785 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_MODEL: |
7786 | 0 | OutputLine("Vendor Model: %s", diagTlv.mData.mVendorModel); |
7787 | 0 | break; |
7788 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION: |
7789 | 0 | OutputLine("Vendor SW Version: %s", diagTlv.mData.mVendorSwVersion); |
7790 | 0 | break; |
7791 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL: |
7792 | 0 | OutputLine("Vendor App URL: %s", diagTlv.mData.mVendorAppUrl); |
7793 | 0 | break; |
7794 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION: |
7795 | 0 | OutputLine("Thread Stack Version: %s", diagTlv.mData.mThreadStackVersion); |
7796 | 0 | break; |
7797 | 0 | case OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS: |
7798 | 0 | OutputLine("Non-preferred Channels Mask: 0x%lx", ToUlong(diagTlv.mData.mNonPreferredChannels)); |
7799 | 0 | break; |
7800 | 0 | default: |
7801 | 0 | break; |
7802 | 0 | } |
7803 | 0 | } |
7804 | | |
7805 | 21 | exit: |
7806 | 21 | return; |
7807 | 0 | } |
7808 | | |
7809 | | void Interpreter::OutputMode(uint8_t aIndentSize, const otLinkModeConfig &aMode) |
7810 | 0 | { |
7811 | 0 | OutputLine(aIndentSize, "RxOnWhenIdle: %d", aMode.mRxOnWhenIdle); |
7812 | 0 | OutputLine(aIndentSize, "DeviceType: %d", aMode.mDeviceType); |
7813 | 0 | OutputLine(aIndentSize, "NetworkData: %d", aMode.mNetworkData); |
7814 | 0 | } |
7815 | | |
7816 | | void Interpreter::OutputConnectivity(uint8_t aIndentSize, const otNetworkDiagConnectivity &aConnectivity) |
7817 | 0 | { |
7818 | 0 | OutputLine(aIndentSize, "ParentPriority: %d", aConnectivity.mParentPriority); |
7819 | 0 | OutputLine(aIndentSize, "LinkQuality3: %u", aConnectivity.mLinkQuality3); |
7820 | 0 | OutputLine(aIndentSize, "LinkQuality2: %u", aConnectivity.mLinkQuality2); |
7821 | 0 | OutputLine(aIndentSize, "LinkQuality1: %u", aConnectivity.mLinkQuality1); |
7822 | 0 | OutputLine(aIndentSize, "LeaderCost: %u", aConnectivity.mLeaderCost); |
7823 | 0 | OutputLine(aIndentSize, "IdSequence: %u", aConnectivity.mIdSequence); |
7824 | 0 | OutputLine(aIndentSize, "ActiveRouters: %u", aConnectivity.mActiveRouters); |
7825 | 0 | OutputLine(aIndentSize, "SedBufferSize: %u", aConnectivity.mSedBufferSize); |
7826 | 0 | OutputLine(aIndentSize, "SedDatagramCount: %u", aConnectivity.mSedDatagramCount); |
7827 | 0 | } |
7828 | | |
7829 | | void Interpreter::OutputRoute(uint8_t aIndentSize, const otNetworkDiagRoute &aRoute) |
7830 | 0 | { |
7831 | 0 | OutputLine(aIndentSize, "IdSequence: %u", aRoute.mIdSequence); |
7832 | 0 | OutputLine(aIndentSize, "RouteData:"); |
7833 | |
|
7834 | 0 | aIndentSize += kIndentSize; |
7835 | 0 | for (uint16_t i = 0; i < aRoute.mRouteCount; ++i) |
7836 | 0 | { |
7837 | 0 | OutputFormat(aIndentSize, "- "); |
7838 | 0 | OutputRouteData(aIndentSize + 2, aRoute.mRouteData[i]); |
7839 | 0 | } |
7840 | 0 | } |
7841 | | |
7842 | | void Interpreter::OutputRouteData(uint8_t aIndentSize, const otNetworkDiagRouteData &aRouteData) |
7843 | 0 | { |
7844 | 0 | OutputLine("RouteId: 0x%02x", aRouteData.mRouterId); |
7845 | |
|
7846 | 0 | OutputLine(aIndentSize, "LinkQualityOut: %u", aRouteData.mLinkQualityOut); |
7847 | 0 | OutputLine(aIndentSize, "LinkQualityIn: %u", aRouteData.mLinkQualityIn); |
7848 | 0 | OutputLine(aIndentSize, "RouteCost: %u", aRouteData.mRouteCost); |
7849 | 0 | } |
7850 | | |
7851 | | void Interpreter::OutputEnhRoute(uint8_t aIndentSize, const otNetworkDiagEnhRoute &aEnhRoute) |
7852 | 0 | { |
7853 | 0 | static constexpr uint8_t kInvalidRouterId = OT_NETWORK_MAX_ROUTER_ID + 1; |
7854 | |
|
7855 | 0 | for (uint8_t index = 0; index < aEnhRoute.mRouteCount; index++) |
7856 | 0 | { |
7857 | 0 | const otNetworkDiagEnhRouteData &routeData = aEnhRoute.mRouteData[index]; |
7858 | |
|
7859 | 0 | OutputFormat(aIndentSize, "- RouterId:%-2u", routeData.mRouterId); |
7860 | |
|
7861 | 0 | if (routeData.mIsSelf) |
7862 | 0 | { |
7863 | 0 | OutputLine(" The queried device"); |
7864 | 0 | continue; |
7865 | 0 | } |
7866 | | |
7867 | 0 | OutputFormat(" HasLink:%-3s LinkQualityOut:%u LinkQualityIn:%u ", routeData.mHasLink ? "yes" : "no", |
7868 | 0 | routeData.mLinkQualityOut, routeData.mLinkQualityIn); |
7869 | |
|
7870 | 0 | if (routeData.mNextHop == kInvalidRouterId) |
7871 | 0 | { |
7872 | 0 | OutputLine("NextHop:na NextHopCost:na"); |
7873 | 0 | } |
7874 | 0 | else |
7875 | 0 | { |
7876 | 0 | OutputLine("NextHop:%-2u NextHopCost:%u", routeData.mNextHop, routeData.mNextHopCost); |
7877 | 0 | } |
7878 | 0 | } |
7879 | 0 | } |
7880 | | |
7881 | | void Interpreter::OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLeaderData) |
7882 | 0 | { |
7883 | 0 | OutputLine(aIndentSize, "PartitionId: 0x%08lx", ToUlong(aLeaderData.mPartitionId)); |
7884 | 0 | OutputLine(aIndentSize, "Weighting: %u", aLeaderData.mWeighting); |
7885 | 0 | OutputLine(aIndentSize, "DataVersion: %u", aLeaderData.mDataVersion); |
7886 | 0 | OutputLine(aIndentSize, "StableDataVersion: %u", aLeaderData.mStableDataVersion); |
7887 | 0 | OutputLine(aIndentSize, "LeaderRouterId: 0x%02x", aLeaderData.mLeaderRouterId); |
7888 | 0 | } |
7889 | | |
7890 | | void Interpreter::OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters) |
7891 | 0 | { |
7892 | 0 | struct CounterName |
7893 | 0 | { |
7894 | 0 | const uint32_t otNetworkDiagMacCounters::*mValuePtr; |
7895 | 0 | const char *mName; |
7896 | 0 | }; |
7897 | |
|
7898 | 0 | static const CounterName kCounterNames[] = { |
7899 | 0 | {&otNetworkDiagMacCounters::mIfInUnknownProtos, "IfInUnknownProtos"}, |
7900 | 0 | {&otNetworkDiagMacCounters::mIfInErrors, "IfInErrors"}, |
7901 | 0 | {&otNetworkDiagMacCounters::mIfOutErrors, "IfOutErrors"}, |
7902 | 0 | {&otNetworkDiagMacCounters::mIfInUcastPkts, "IfInUcastPkts"}, |
7903 | 0 | {&otNetworkDiagMacCounters::mIfInBroadcastPkts, "IfInBroadcastPkts"}, |
7904 | 0 | {&otNetworkDiagMacCounters::mIfInDiscards, "IfInDiscards"}, |
7905 | 0 | {&otNetworkDiagMacCounters::mIfOutUcastPkts, "IfOutUcastPkts"}, |
7906 | 0 | {&otNetworkDiagMacCounters::mIfOutBroadcastPkts, "IfOutBroadcastPkts"}, |
7907 | 0 | {&otNetworkDiagMacCounters::mIfOutDiscards, "IfOutDiscards"}, |
7908 | 0 | }; |
7909 | |
|
7910 | 0 | for (const CounterName &counter : kCounterNames) |
7911 | 0 | { |
7912 | 0 | OutputLine(aIndentSize, "%s: %lu", counter.mName, ToUlong(aMacCounters.*counter.mValuePtr)); |
7913 | 0 | } |
7914 | 0 | } |
7915 | | |
7916 | | void Interpreter::OutputNetworkDiagMleCounters(uint8_t aIndentSize, const otNetworkDiagMleCounters &aMleCounters) |
7917 | 0 | { |
7918 | 0 | struct CounterName |
7919 | 0 | { |
7920 | 0 | const uint16_t otNetworkDiagMleCounters::*mValuePtr; |
7921 | 0 | const char *mName; |
7922 | 0 | }; |
7923 | |
|
7924 | 0 | struct TimeCounterName |
7925 | 0 | { |
7926 | 0 | const uint64_t otNetworkDiagMleCounters::*mValuePtr; |
7927 | 0 | const char *mName; |
7928 | 0 | }; |
7929 | |
|
7930 | 0 | static const CounterName kCounterNames[] = { |
7931 | 0 | {&otNetworkDiagMleCounters::mDisabledRole, "DisabledRole"}, |
7932 | 0 | {&otNetworkDiagMleCounters::mDetachedRole, "DetachedRole"}, |
7933 | 0 | {&otNetworkDiagMleCounters::mChildRole, "ChildRole"}, |
7934 | 0 | {&otNetworkDiagMleCounters::mRouterRole, "RouterRole"}, |
7935 | 0 | {&otNetworkDiagMleCounters::mLeaderRole, "LeaderRole"}, |
7936 | 0 | {&otNetworkDiagMleCounters::mAttachAttempts, "AttachAttempts"}, |
7937 | 0 | {&otNetworkDiagMleCounters::mPartitionIdChanges, "PartitionIdChanges"}, |
7938 | 0 | {&otNetworkDiagMleCounters::mBetterPartitionAttachAttempts, "BetterPartitionAttachAttempts"}, |
7939 | 0 | {&otNetworkDiagMleCounters::mParentChanges, "ParentChanges"}, |
7940 | 0 | }; |
7941 | |
|
7942 | 0 | static const TimeCounterName kTimeCounterNames[] = { |
7943 | 0 | {&otNetworkDiagMleCounters::mTrackedTime, "TrackedTime"}, |
7944 | 0 | {&otNetworkDiagMleCounters::mDisabledTime, "DisabledTime"}, |
7945 | 0 | {&otNetworkDiagMleCounters::mDetachedTime, "DetachedTime"}, |
7946 | 0 | {&otNetworkDiagMleCounters::mChildTime, "ChildTime"}, |
7947 | 0 | {&otNetworkDiagMleCounters::mRouterTime, "RouterTime"}, |
7948 | 0 | {&otNetworkDiagMleCounters::mLeaderTime, "LeaderTime"}, |
7949 | 0 | }; |
7950 | |
|
7951 | 0 | for (const CounterName &counter : kCounterNames) |
7952 | 0 | { |
7953 | 0 | OutputLine(aIndentSize, "%s: %u", counter.mName, aMleCounters.*counter.mValuePtr); |
7954 | 0 | } |
7955 | |
|
7956 | 0 | for (const TimeCounterName &counter : kTimeCounterNames) |
7957 | 0 | { |
7958 | 0 | OutputFormat("%s: ", counter.mName); |
7959 | 0 | OutputUint64Line(aMleCounters.*counter.mValuePtr); |
7960 | 0 | } |
7961 | 0 | } |
7962 | | |
7963 | | void Interpreter::OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry) |
7964 | 0 | { |
7965 | 0 | OutputLine("ChildId: 0x%04x", aChildEntry.mChildId); |
7966 | |
|
7967 | 0 | OutputLine(aIndentSize, "Timeout: %u", aChildEntry.mTimeout); |
7968 | 0 | OutputLine(aIndentSize, "Link Quality: %u", aChildEntry.mLinkQuality); |
7969 | 0 | OutputLine(aIndentSize, "Mode:"); |
7970 | 0 | OutputMode(aIndentSize + kIndentSize, aChildEntry.mMode); |
7971 | 0 | } |
7972 | | #endif // OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
7973 | | |
7974 | | #if OPENTHREAD_FTD |
7975 | | void Interpreter::HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo *aInfo, void *aContext) |
7976 | 0 | { |
7977 | 0 | static_cast<Interpreter *>(aContext)->HandleDiscoveryRequest(*aInfo); |
7978 | 0 | } |
7979 | | |
7980 | | void Interpreter::HandleDiscoveryRequest(const otThreadDiscoveryRequestInfo &aInfo) |
7981 | 0 | { |
7982 | 0 | OutputFormat("~ Discovery Request from "); |
7983 | 0 | OutputExtAddress(aInfo.mExtAddress); |
7984 | 0 | OutputLine(": version=%u,joiner=%d", aInfo.mVersion, aInfo.mIsJoiner); |
7985 | 0 | } |
7986 | | #endif |
7987 | | |
7988 | | #if OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK |
7989 | | void Interpreter::HandleIp6Receive(otMessage *aMessage, void *aContext) |
7990 | | { |
7991 | | OT_UNUSED_VARIABLE(aContext); |
7992 | | |
7993 | | otMessageFree(aMessage); |
7994 | | } |
7995 | | #endif |
7996 | | |
7997 | | #if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE |
7998 | | |
7999 | | template <> otError Interpreter::Process<Cmd("verhoeff")>(Arg aArgs[]) |
8000 | | { |
8001 | | otError error; |
8002 | | |
8003 | | /** |
8004 | | * @cli verhoeff calculate |
8005 | | * @code |
8006 | | * verhoeff calculate 30731842 |
8007 | | * 1 |
8008 | | * Done |
8009 | | * @endcode |
8010 | | * @cparam verhoeff calculate @ca{decimalstring} |
8011 | | * @par api_copy |
8012 | | * #otVerhoeffChecksumCalculate |
8013 | | */ |
8014 | | if (aArgs[0] == "calculate") |
8015 | | { |
8016 | | char checksum; |
8017 | | |
8018 | | VerifyOrExit(!aArgs[1].IsEmpty() && aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
8019 | | SuccessOrExit(error = otVerhoeffChecksumCalculate(aArgs[1].GetCString(), &checksum)); |
8020 | | OutputLine("%c", checksum); |
8021 | | } |
8022 | | /** |
8023 | | * @cli verhoeff validate |
8024 | | * @code |
8025 | | * verhoeff validate 307318421 |
8026 | | * Done |
8027 | | * @endcode |
8028 | | * @cparam verhoeff validate @ca{decimalstring} |
8029 | | * @par api_copy |
8030 | | * #otVerhoeffChecksumValidate |
8031 | | */ |
8032 | | else if (aArgs[0] == "validate") |
8033 | | { |
8034 | | VerifyOrExit(!aArgs[1].IsEmpty() && aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
8035 | | error = otVerhoeffChecksumValidate(aArgs[1].GetCString()); |
8036 | | } |
8037 | | else |
8038 | | { |
8039 | | error = OT_ERROR_INVALID_COMMAND; |
8040 | | } |
8041 | | |
8042 | | exit: |
8043 | | return error; |
8044 | | } |
8045 | | |
8046 | | #endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE |
8047 | | |
8048 | | #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE |
8049 | | template <> otError Interpreter::Process<Cmd("wakeup")>(Arg aArgs[]) |
8050 | | { |
8051 | | otError error = OT_ERROR_NONE; |
8052 | | |
8053 | | /** |
8054 | | * @cli wakeup channel (get,set) |
8055 | | * @code |
8056 | | * wakeup channel |
8057 | | * 12 |
8058 | | * Done |
8059 | | * @endcode |
8060 | | * @code |
8061 | | * wakeup channel 12 |
8062 | | * Done |
8063 | | * @endcode |
8064 | | * @cparam wakeup channel [@ca{channel}] |
8065 | | * Use `channel` to set the wake-up channel. |
8066 | | * @par |
8067 | | * Gets or sets the wake-up channel value. |
8068 | | * @sa otLinkGetWakeupChannel |
8069 | | * @sa otLinkSetWakeupChannel |
8070 | | */ |
8071 | | if (aArgs[0] == "channel") |
8072 | | { |
8073 | | error = ProcessGetSet(aArgs + 1, otLinkGetWakeupChannel, otLinkSetWakeupChannel); |
8074 | | } |
8075 | | #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE |
8076 | | /** |
8077 | | * @cli wakeup parameters (get,set) |
8078 | | * @code |
8079 | | * wakeup parameters |
8080 | | * interval: 1000000us |
8081 | | * duration: 8000us |
8082 | | * Done |
8083 | | * @endcode |
8084 | | * @code |
8085 | | * wakeup parameters 1000000 8000 |
8086 | | * Done |
8087 | | * @endcode |
8088 | | * @cparam wakeup parameters @ca{interval} @ca{duration} |
8089 | | * @par |
8090 | | * Gets or sets the wake-up listen interval and wake-up listen duration values. |
8091 | | * @sa otLinkGetWakeUpListenParameters |
8092 | | * @sa otLinkSetWakeUpListenParameters |
8093 | | */ |
8094 | | else if (aArgs[0] == "parameters") |
8095 | | { |
8096 | | uint32_t interval; |
8097 | | uint32_t duration; |
8098 | | |
8099 | | if (aArgs[1].IsEmpty()) |
8100 | | { |
8101 | | otLinkGetWakeupListenParameters(GetInstancePtr(), &interval, &duration); |
8102 | | OutputLine("interval: %luus", ToUlong(interval)); |
8103 | | OutputLine("duration: %luus", ToUlong(duration)); |
8104 | | } |
8105 | | else |
8106 | | { |
8107 | | SuccessOrExit(error = aArgs[1].ParseAsUint32(interval)); |
8108 | | SuccessOrExit(error = aArgs[2].ParseAsUint32(duration)); |
8109 | | error = otLinkSetWakeupListenParameters(GetInstancePtr(), interval, duration); |
8110 | | } |
8111 | | } |
8112 | | /** |
8113 | | * @cli wakeup listen (enable,disable) |
8114 | | * @code |
8115 | | * wakeup listen |
8116 | | * disabled |
8117 | | * Done |
8118 | | * @endcode |
8119 | | * @code |
8120 | | * wakeup listen enable |
8121 | | * Done |
8122 | | * @endcode |
8123 | | * @code |
8124 | | * wakeup listen |
8125 | | * enabled |
8126 | | * Done |
8127 | | * @endcode |
8128 | | * @cparam wakeup listen @ca{enable} |
8129 | | * @par |
8130 | | * Gets or sets current wake-up listening link state. |
8131 | | * @sa otLinkIsWakeupListenEnabled |
8132 | | * @sa otLinkSetWakeUpListenEnabled |
8133 | | */ |
8134 | | else if (aArgs[0] == "listen") |
8135 | | { |
8136 | | error = ProcessEnableDisable(aArgs + 1, otLinkIsWakeupListenEnabled, otLinkSetWakeUpListenEnabled); |
8137 | | } |
8138 | | #endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE |
8139 | | #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE |
8140 | | /** |
8141 | | * @cli wakeup wake |
8142 | | * @code |
8143 | | * wakeup wake 1ece0a6c4653a7c1 7500 1090 |
8144 | | * Done |
8145 | | * @endcode |
8146 | | * @cparam wakeup wake @ca{extaddr} @ca{wakeup-interval} @ca{wakeup-duration} |
8147 | | * @par |
8148 | | * Wakes a Wake-up End Device identified by its MAC extended address, using the provided wake-up interval (in the |
8149 | | * units of microseconds), and wake-up duration (in the units of milliseconds). |
8150 | | */ |
8151 | | else if (aArgs[0] == "wake") |
8152 | | { |
8153 | | otExtAddress extAddress; |
8154 | | uint16_t wakeupIntervalUs; |
8155 | | uint16_t wakeupDurationMs; |
8156 | | |
8157 | | SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddress.m8)); |
8158 | | SuccessOrExit(error = aArgs[2].ParseAsUint16(wakeupIntervalUs)); |
8159 | | SuccessOrExit(error = aArgs[3].ParseAsUint16(wakeupDurationMs)); |
8160 | | |
8161 | | SuccessOrExit(error = otThreadWakeup(GetInstancePtr(), &extAddress, wakeupIntervalUs, wakeupDurationMs, |
8162 | | HandleWakeupResult, this)); |
8163 | | error = OT_ERROR_PENDING; |
8164 | | } |
8165 | | #endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE |
8166 | | else |
8167 | | { |
8168 | | ExitNow(error = OT_ERROR_INVALID_ARGS); |
8169 | | } |
8170 | | |
8171 | | exit: |
8172 | | return error; |
8173 | | } |
8174 | | #endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE |
8175 | | |
8176 | | #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE |
8177 | | void Interpreter::HandleWakeupResult(otError aError, void *aContext) |
8178 | | { |
8179 | | static_cast<Interpreter *>(aContext)->HandleWakeupResult(aError); |
8180 | | } |
8181 | | |
8182 | | void Interpreter::HandleWakeupResult(otError aError) { OutputResult(aError); } |
8183 | | #endif |
8184 | | |
8185 | | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8186 | | |
8187 | | void Interpreter::Initialize(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext) |
8188 | 7.46k | { |
8189 | 7.46k | Instance *instance = static_cast<Instance *>(aInstance); |
8190 | | |
8191 | 7.46k | Interpreter::sInterpreter = new (&sInterpreterRaw) Interpreter(instance, aCallback, aContext); |
8192 | 7.46k | } |
8193 | | |
8194 | | void Interpreter::OutputPrompt(void) |
8195 | 14.3k | { |
8196 | 14.3k | #if OPENTHREAD_CONFIG_CLI_PROMPT_ENABLE |
8197 | 14.3k | static const char sPrompt[] = "> "; |
8198 | | |
8199 | | // The `OutputFormat()` below is adding the prompt which is not |
8200 | | // part of any command output, so we set the `EmittingCommandOutput` |
8201 | | // flag to false to avoid it being included in the command output |
8202 | | // log (under `OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE`). |
8203 | | |
8204 | 14.3k | SetEmittingCommandOutput(false); |
8205 | 14.3k | OutputFormat("%s", sPrompt); |
8206 | 14.3k | SetEmittingCommandOutput(true); |
8207 | 14.3k | #endif // OPENTHREAD_CONFIG_CLI_PROMPT_ENABLE |
8208 | 14.3k | } |
8209 | | |
8210 | | void Interpreter::HandleTimer(Timer &aTimer) |
8211 | 0 | { |
8212 | 0 | static_cast<Interpreter *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleTimer(); |
8213 | 0 | } |
8214 | | |
8215 | | void Interpreter::HandleTimer(void) |
8216 | 0 | { |
8217 | | #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE |
8218 | | if (mLocateInProgress) |
8219 | | { |
8220 | | mLocateInProgress = false; |
8221 | | OutputResult(OT_ERROR_RESPONSE_TIMEOUT); |
8222 | | } |
8223 | | else |
8224 | | #endif |
8225 | 0 | { |
8226 | 0 | OutputResult(OT_ERROR_NONE); |
8227 | 0 | } |
8228 | 0 | } |
8229 | | |
8230 | | void Interpreter::SetCommandTimeout(uint32_t aTimeoutMilli) |
8231 | 25 | { |
8232 | 25 | OT_ASSERT(mCommandIsPending); |
8233 | 25 | mTimer.Start(aTimeoutMilli); |
8234 | 25 | } |
8235 | | |
8236 | | otError Interpreter::ProcessCommand(Arg aArgs[]) |
8237 | 7.98k | { |
8238 | 7.98k | #define CmdEntry(aCommandString) \ |
8239 | 758k | { \ |
8240 | 758k | aCommandString, &Interpreter::Process<Cmd(aCommandString)> \ |
8241 | 758k | } |
8242 | | |
8243 | 7.98k | static constexpr Command kCommands[] = { |
8244 | 7.98k | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
8245 | 7.98k | CmdEntry("attachtime"), |
8246 | 7.98k | #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE |
8247 | 7.98k | CmdEntry("ba"), |
8248 | 7.98k | #endif |
8249 | 7.98k | #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
8250 | 7.98k | CmdEntry("bbr"), |
8251 | 7.98k | #endif |
8252 | 7.98k | #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE |
8253 | 7.98k | CmdEntry("br"), |
8254 | 7.98k | #endif |
8255 | 7.98k | CmdEntry("bufferinfo"), |
8256 | 7.98k | CmdEntry("ccathreshold"), |
8257 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8258 | | CmdEntry("ccm"), |
8259 | | #endif |
8260 | 7.98k | CmdEntry("channel"), |
8261 | 7.98k | #if OPENTHREAD_FTD |
8262 | 7.98k | CmdEntry("child"), |
8263 | 7.98k | CmdEntry("childip"), |
8264 | 7.98k | CmdEntry("childmax"), |
8265 | 7.98k | CmdEntry("childrouterlinks"), |
8266 | 7.98k | #endif |
8267 | 7.98k | CmdEntry("childsupervision"), |
8268 | 7.98k | CmdEntry("childtimeout"), |
8269 | 7.98k | #if OPENTHREAD_CONFIG_COAP_API_ENABLE |
8270 | 7.98k | CmdEntry("coap"), |
8271 | 7.98k | #endif |
8272 | 7.98k | #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE |
8273 | 7.98k | CmdEntry("coaps"), |
8274 | 7.98k | #endif |
8275 | | #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE |
8276 | | CmdEntry("coex"), |
8277 | | #endif |
8278 | 7.98k | #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD |
8279 | 7.98k | CmdEntry("commissioner"), |
8280 | 7.98k | #endif |
8281 | 7.98k | #if OPENTHREAD_FTD |
8282 | 7.98k | CmdEntry("contextreusedelay"), |
8283 | 7.98k | #endif |
8284 | 7.98k | CmdEntry("counters"), |
8285 | | #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE |
8286 | | CmdEntry("csl"), |
8287 | | #endif |
8288 | 7.98k | CmdEntry("dataset"), |
8289 | 7.98k | CmdEntry("debug"), |
8290 | 7.98k | #if OPENTHREAD_FTD |
8291 | 7.98k | CmdEntry("delaytimermin"), |
8292 | 7.98k | #endif |
8293 | 7.98k | CmdEntry("detach"), |
8294 | 7.98k | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8295 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE |
8296 | | CmdEntry("deviceprops"), |
8297 | | #endif |
8298 | | #if OPENTHREAD_CONFIG_DIAG_ENABLE |
8299 | | CmdEntry("diag"), |
8300 | | #endif |
8301 | 7.98k | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
8302 | 7.98k | CmdEntry("discover"), |
8303 | 7.98k | #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE || OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE || \ |
8304 | 7.98k | OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8305 | 7.98k | CmdEntry("dns"), |
8306 | 7.98k | #endif |
8307 | 7.98k | #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) |
8308 | 7.98k | CmdEntry("domainname"), |
8309 | 7.98k | #endif |
8310 | | #if OPENTHREAD_CONFIG_DUA_ENABLE |
8311 | | CmdEntry("dua"), |
8312 | | #endif |
8313 | 7.98k | #if OPENTHREAD_FTD |
8314 | 7.98k | CmdEntry("eidcache"), |
8315 | 7.98k | #endif |
8316 | 7.98k | CmdEntry("eui64"), |
8317 | 7.98k | CmdEntry("extaddr"), |
8318 | 7.98k | CmdEntry("extpanid"), |
8319 | 7.98k | CmdEntry("factoryreset"), |
8320 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8321 | | CmdEntry("fake"), |
8322 | | #endif |
8323 | 7.98k | CmdEntry("fem"), |
8324 | 7.98k | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8325 | 7.98k | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
8326 | 7.98k | #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE |
8327 | 7.98k | CmdEntry("history"), |
8328 | 7.98k | #endif |
8329 | 7.98k | CmdEntry("ifconfig"), |
8330 | 7.98k | CmdEntry("instanceid"), |
8331 | 7.98k | CmdEntry("ipaddr"), |
8332 | 7.98k | CmdEntry("ipmaddr"), |
8333 | 7.98k | #if OPENTHREAD_CONFIG_JOINER_ENABLE |
8334 | 7.98k | CmdEntry("joiner"), |
8335 | 7.98k | #endif |
8336 | 7.98k | #if OPENTHREAD_FTD |
8337 | 7.98k | CmdEntry("joinerport"), |
8338 | 7.98k | #endif |
8339 | 7.98k | CmdEntry("keysequence"), |
8340 | 7.98k | CmdEntry("leaderdata"), |
8341 | 7.98k | #if OPENTHREAD_FTD |
8342 | 7.98k | CmdEntry("leaderweight"), |
8343 | 7.98k | #endif |
8344 | | #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE |
8345 | | CmdEntry("linkmetrics"), |
8346 | | #if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE |
8347 | | CmdEntry("linkmetricsmgr"), |
8348 | | #endif |
8349 | | #endif |
8350 | | #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE |
8351 | | CmdEntry("locate"), |
8352 | | #endif |
8353 | 7.98k | CmdEntry("log"), |
8354 | 7.98k | CmdEntry("mac"), |
8355 | 7.98k | #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |
8356 | 7.98k | CmdEntry("macfilter"), |
8357 | 7.98k | #endif |
8358 | | #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE |
8359 | | CmdEntry("mdns"), |
8360 | | #endif |
8361 | 7.98k | #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD |
8362 | 7.98k | CmdEntry("meshdiag"), |
8363 | 7.98k | #endif |
8364 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8365 | | CmdEntry("mleadvimax"), |
8366 | | #endif |
8367 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8368 | | CmdEntry("mliid"), |
8369 | | #endif |
8370 | 7.98k | #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE |
8371 | 7.98k | CmdEntry("mlr"), |
8372 | 7.98k | #endif |
8373 | 7.98k | CmdEntry("mode"), |
8374 | 7.98k | CmdEntry("multiradio"), |
8375 | | #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE |
8376 | | CmdEntry("nat64"), |
8377 | | #endif |
8378 | 7.98k | #if OPENTHREAD_FTD |
8379 | 7.98k | CmdEntry("neighbor"), |
8380 | 7.98k | #endif |
8381 | 7.98k | CmdEntry("netdata"), |
8382 | 7.98k | CmdEntry("netstat"), |
8383 | 7.98k | #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
8384 | 7.98k | CmdEntry("networkdiagnostic"), |
8385 | 7.98k | #endif |
8386 | 7.98k | #if OPENTHREAD_FTD |
8387 | 7.98k | CmdEntry("networkidtimeout"), |
8388 | 7.98k | #endif |
8389 | 7.98k | CmdEntry("networkkey"), |
8390 | | #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE |
8391 | | CmdEntry("networkkeyref"), |
8392 | | #endif |
8393 | 7.98k | CmdEntry("networkname"), |
8394 | | #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE |
8395 | | CmdEntry("networktime"), |
8396 | | #endif |
8397 | 7.98k | #if OPENTHREAD_FTD |
8398 | 7.98k | CmdEntry("nexthop"), |
8399 | 7.98k | #endif |
8400 | 7.98k | CmdEntry("panid"), |
8401 | 7.98k | CmdEntry("parent"), |
8402 | 7.98k | #if OPENTHREAD_FTD |
8403 | 7.98k | CmdEntry("parentpriority"), |
8404 | 7.98k | CmdEntry("partitionid"), |
8405 | 7.98k | #endif |
8406 | 7.98k | #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE |
8407 | 7.98k | CmdEntry("ping"), |
8408 | 7.98k | #endif |
8409 | 7.98k | CmdEntry("platform"), |
8410 | 7.98k | CmdEntry("pollperiod"), |
8411 | 7.98k | #if OPENTHREAD_FTD |
8412 | 7.98k | CmdEntry("preferrouterid"), |
8413 | 7.98k | #endif |
8414 | 7.98k | #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
8415 | 7.98k | CmdEntry("prefix"), |
8416 | 7.98k | #endif |
8417 | 7.98k | CmdEntry("promiscuous"), |
8418 | 7.98k | #if OPENTHREAD_FTD |
8419 | 7.98k | CmdEntry("pskc"), |
8420 | | #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE |
8421 | | CmdEntry("pskcref"), |
8422 | | #endif |
8423 | 7.98k | #endif |
8424 | | #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE |
8425 | | CmdEntry("radio"), |
8426 | | #endif |
8427 | 7.98k | #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE && OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE |
8428 | 7.98k | CmdEntry("radiofilter"), |
8429 | 7.98k | #endif |
8430 | 7.98k | CmdEntry("rcp"), |
8431 | 7.98k | CmdEntry("region"), |
8432 | 7.98k | #if OPENTHREAD_FTD |
8433 | 7.98k | CmdEntry("releaserouterid"), |
8434 | 7.98k | #endif |
8435 | 7.98k | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8436 | 7.98k | CmdEntry("reset"), |
8437 | 7.98k | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
8438 | 7.98k | CmdEntry("rloc16"), |
8439 | 7.98k | #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE |
8440 | 7.98k | CmdEntry("route"), |
8441 | 7.98k | #endif |
8442 | 7.98k | #if OPENTHREAD_FTD |
8443 | 7.98k | CmdEntry("router"), |
8444 | 7.98k | CmdEntry("routerdowngradethreshold"), |
8445 | 7.98k | CmdEntry("routereligible"), |
8446 | | #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8447 | | CmdEntry("routeridrange"), |
8448 | | #endif |
8449 | 7.98k | CmdEntry("routerselectionjitter"), |
8450 | 7.98k | CmdEntry("routerupgradethreshold"), |
8451 | 7.98k | #endif |
8452 | 7.98k | CmdEntry("scan"), |
8453 | 7.98k | #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE |
8454 | 7.98k | CmdEntry("service"), |
8455 | 7.98k | #endif |
8456 | 7.98k | CmdEntry("singleton"), |
8457 | 7.98k | #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE |
8458 | 7.98k | CmdEntry("sntp"), |
8459 | 7.98k | #endif |
8460 | 7.98k | #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE || OPENTHREAD_CONFIG_SRP_SERVER_ENABLE |
8461 | 7.98k | CmdEntry("srp"), |
8462 | 7.98k | #endif |
8463 | 7.98k | CmdEntry("state"), |
8464 | 7.98k | CmdEntry("targetpower"), |
8465 | | #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE |
8466 | | CmdEntry("tcat"), |
8467 | | #endif |
8468 | 7.98k | #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE |
8469 | 7.98k | CmdEntry("tcp"), |
8470 | 7.98k | #endif |
8471 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8472 | | CmdEntry("test"), |
8473 | | #endif |
8474 | 7.98k | CmdEntry("thread"), |
8475 | 7.98k | #if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE |
8476 | 7.98k | CmdEntry("timeinqueue"), |
8477 | 7.98k | #endif |
8478 | | #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE |
8479 | | CmdEntry("trel"), |
8480 | | #endif |
8481 | | #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE |
8482 | | CmdEntry("tvcheck"), |
8483 | | #endif |
8484 | 7.98k | CmdEntry("txpower"), |
8485 | 7.98k | CmdEntry("udp"), |
8486 | 7.98k | CmdEntry("unsecureport"), |
8487 | 7.98k | #if OPENTHREAD_CONFIG_UPTIME_ENABLE |
8488 | 7.98k | CmdEntry("uptime"), |
8489 | 7.98k | #endif |
8490 | 7.98k | CmdEntry("vendor"), |
8491 | | #if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE |
8492 | | CmdEntry("verhoeff"), |
8493 | | #endif |
8494 | 7.98k | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8495 | 7.98k | CmdEntry("version"), |
8496 | 7.98k | #if OPENTHREAD_FTD || OPENTHREAD_MTD |
8497 | | #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE |
8498 | | CmdEntry("wakeup"), |
8499 | | #endif |
8500 | 7.98k | #endif // OPENTHREAD_FTD || OPENTHREAD_MTD |
8501 | 7.98k | }; |
8502 | | |
8503 | 7.98k | #undef CmdEntry |
8504 | | |
8505 | 7.98k | static_assert(BinarySearch::IsSorted(kCommands), "Command Table is not sorted"); |
8506 | | |
8507 | 7.98k | otError error = OT_ERROR_NONE; |
8508 | 7.98k | const Command *command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); |
8509 | | |
8510 | 7.98k | if (command != nullptr) |
8511 | 7.69k | { |
8512 | 7.69k | error = (this->*command->mHandler)(aArgs + 1); |
8513 | 7.69k | } |
8514 | 290 | else if (aArgs[0] == "help") |
8515 | 1 | { |
8516 | 1 | OutputCommandTable(kCommands); |
8517 | | |
8518 | 1 | for (const UserCommandsEntry &entry : mUserCommands) |
8519 | 1 | { |
8520 | 1 | for (uint8_t i = 0; i < entry.mLength; i++) |
8521 | 0 | { |
8522 | 0 | OutputLine("%s", entry.mCommands[i].mName); |
8523 | 0 | } |
8524 | 1 | } |
8525 | 1 | } |
8526 | 289 | else |
8527 | 289 | { |
8528 | 289 | error = ProcessUserCommands(aArgs); |
8529 | 289 | } |
8530 | | |
8531 | 7.98k | return error; |
8532 | 7.98k | } |
8533 | | |
8534 | | extern "C" void otCliInit(otInstance *aInstance, otCliOutputCallback aCallback, void *aContext) |
8535 | 7.46k | { |
8536 | 7.46k | Interpreter::Initialize(aInstance, aCallback, aContext); |
8537 | | |
8538 | | #if OPENTHREAD_CONFIG_CLI_VENDOR_COMMANDS_ENABLE && OPENTHREAD_CONFIG_CLI_MAX_USER_CMD_ENTRIES > 1 |
8539 | | otCliVendorSetUserCommands(); |
8540 | | #endif |
8541 | 7.46k | } |
8542 | | |
8543 | 7.46k | extern "C" void otCliInputLine(char *aBuf) { Interpreter::GetInterpreter().ProcessLine(aBuf); } |
8544 | | |
8545 | | extern "C" otError otCliSetUserCommands(const otCliCommand *aUserCommands, uint8_t aLength, void *aContext) |
8546 | 0 | { |
8547 | 0 | return Interpreter::GetInterpreter().SetUserCommands(aUserCommands, aLength, aContext); |
8548 | 0 | } |
8549 | | |
8550 | | extern "C" void otCliOutputBytes(const uint8_t *aBytes, uint8_t aLength) |
8551 | 0 | { |
8552 | 0 | Interpreter::GetInterpreter().OutputBytes(aBytes, aLength); |
8553 | 0 | } |
8554 | | |
8555 | | extern "C" void otCliOutputFormat(const char *aFmt, ...) |
8556 | 0 | { |
8557 | 0 | va_list aAp; |
8558 | 0 | va_start(aAp, aFmt); |
8559 | 0 | Interpreter::GetInterpreter().OutputFormatV(aFmt, aAp); |
8560 | 0 | va_end(aAp); |
8561 | 0 | } |
8562 | | |
8563 | 0 | extern "C" void otCliAppendResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); } |
8564 | | |
8565 | | extern "C" void otCliPlatLogv(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, va_list aArgs) |
8566 | 0 | { |
8567 | 0 | OT_UNUSED_VARIABLE(aLogLevel); |
8568 | 0 | OT_UNUSED_VARIABLE(aLogRegion); |
8569 | |
|
8570 | 0 | VerifyOrExit(Interpreter::IsInitialized()); |
8571 | | |
8572 | | // CLI output is being used for logging, so we set the flag |
8573 | | // `EmittingCommandOutput` to false indicate this. |
8574 | 0 | Interpreter::GetInterpreter().SetEmittingCommandOutput(false); |
8575 | 0 | Interpreter::GetInterpreter().OutputFormatV(aFormat, aArgs); |
8576 | 0 | Interpreter::GetInterpreter().OutputNewLine(); |
8577 | 0 | Interpreter::GetInterpreter().SetEmittingCommandOutput(true); |
8578 | |
|
8579 | 0 | exit: |
8580 | 0 | return; |
8581 | 0 | } |
8582 | | |
8583 | | } // namespace Cli |
8584 | | } // namespace ot |