1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2021, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker * All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker *
5*cfb92d14SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker * 3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker * names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker *
16*cfb92d14SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*cfb92d14SAndroid Build Coastguard Worker * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*cfb92d14SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*cfb92d14SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*cfb92d14SAndroid Build Coastguard Worker * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*cfb92d14SAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*cfb92d14SAndroid Build Coastguard Worker * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*cfb92d14SAndroid Build Coastguard Worker * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*cfb92d14SAndroid Build Coastguard Worker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*cfb92d14SAndroid Build Coastguard Worker * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*cfb92d14SAndroid Build Coastguard Worker * POSSIBILITY OF SUCH DAMAGE.
27*cfb92d14SAndroid Build Coastguard Worker */
28*cfb92d14SAndroid Build Coastguard Worker
29*cfb92d14SAndroid Build Coastguard Worker /**
30*cfb92d14SAndroid Build Coastguard Worker * @file
31*cfb92d14SAndroid Build Coastguard Worker * This file contains implementation of the CLI output module.
32*cfb92d14SAndroid Build Coastguard Worker */
33*cfb92d14SAndroid Build Coastguard Worker
34*cfb92d14SAndroid Build Coastguard Worker #include "cli_utils.hpp"
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard Worker #include <stdio.h>
37*cfb92d14SAndroid Build Coastguard Worker #include <stdlib.h>
38*cfb92d14SAndroid Build Coastguard Worker #include <string.h>
39*cfb92d14SAndroid Build Coastguard Worker
40*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_FTD || OPENTHREAD_MTD
41*cfb92d14SAndroid Build Coastguard Worker #include <openthread/dns.h>
42*cfb92d14SAndroid Build Coastguard Worker #endif
43*cfb92d14SAndroid Build Coastguard Worker #include <openthread/logging.h>
44*cfb92d14SAndroid Build Coastguard Worker
45*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli.hpp"
46*cfb92d14SAndroid Build Coastguard Worker #include "common/string.hpp"
47*cfb92d14SAndroid Build Coastguard Worker
48*cfb92d14SAndroid Build Coastguard Worker namespace ot {
49*cfb92d14SAndroid Build Coastguard Worker namespace Cli {
50*cfb92d14SAndroid Build Coastguard Worker
51*cfb92d14SAndroid Build Coastguard Worker const char Utils::kUnknownString[] = "unknown";
52*cfb92d14SAndroid Build Coastguard Worker
OutputImplementer(otCliOutputCallback aCallback,void * aCallbackContext)53*cfb92d14SAndroid Build Coastguard Worker OutputImplementer::OutputImplementer(otCliOutputCallback aCallback, void *aCallbackContext)
54*cfb92d14SAndroid Build Coastguard Worker : mCallback(aCallback)
55*cfb92d14SAndroid Build Coastguard Worker , mCallbackContext(aCallbackContext)
56*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
57*cfb92d14SAndroid Build Coastguard Worker , mOutputLength(0)
58*cfb92d14SAndroid Build Coastguard Worker , mEmittingCommandOutput(true)
59*cfb92d14SAndroid Build Coastguard Worker #endif
60*cfb92d14SAndroid Build Coastguard Worker {
61*cfb92d14SAndroid Build Coastguard Worker }
62*cfb92d14SAndroid Build Coastguard Worker
OutputFormat(const char * aFormat,...)63*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputFormat(const char *aFormat, ...)
64*cfb92d14SAndroid Build Coastguard Worker {
65*cfb92d14SAndroid Build Coastguard Worker va_list args;
66*cfb92d14SAndroid Build Coastguard Worker
67*cfb92d14SAndroid Build Coastguard Worker va_start(args, aFormat);
68*cfb92d14SAndroid Build Coastguard Worker OutputFormatV(aFormat, args);
69*cfb92d14SAndroid Build Coastguard Worker va_end(args);
70*cfb92d14SAndroid Build Coastguard Worker }
71*cfb92d14SAndroid Build Coastguard Worker
OutputFormat(uint8_t aIndentSize,const char * aFormat,...)72*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputFormat(uint8_t aIndentSize, const char *aFormat, ...)
73*cfb92d14SAndroid Build Coastguard Worker {
74*cfb92d14SAndroid Build Coastguard Worker va_list args;
75*cfb92d14SAndroid Build Coastguard Worker
76*cfb92d14SAndroid Build Coastguard Worker OutputSpaces(aIndentSize);
77*cfb92d14SAndroid Build Coastguard Worker
78*cfb92d14SAndroid Build Coastguard Worker va_start(args, aFormat);
79*cfb92d14SAndroid Build Coastguard Worker OutputFormatV(aFormat, args);
80*cfb92d14SAndroid Build Coastguard Worker va_end(args);
81*cfb92d14SAndroid Build Coastguard Worker }
82*cfb92d14SAndroid Build Coastguard Worker
OutputLine(const char * aFormat,...)83*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputLine(const char *aFormat, ...)
84*cfb92d14SAndroid Build Coastguard Worker {
85*cfb92d14SAndroid Build Coastguard Worker va_list args;
86*cfb92d14SAndroid Build Coastguard Worker
87*cfb92d14SAndroid Build Coastguard Worker va_start(args, aFormat);
88*cfb92d14SAndroid Build Coastguard Worker OutputFormatV(aFormat, args);
89*cfb92d14SAndroid Build Coastguard Worker va_end(args);
90*cfb92d14SAndroid Build Coastguard Worker
91*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
92*cfb92d14SAndroid Build Coastguard Worker }
93*cfb92d14SAndroid Build Coastguard Worker
OutputLine(uint8_t aIndentSize,const char * aFormat,...)94*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputLine(uint8_t aIndentSize, const char *aFormat, ...)
95*cfb92d14SAndroid Build Coastguard Worker {
96*cfb92d14SAndroid Build Coastguard Worker va_list args;
97*cfb92d14SAndroid Build Coastguard Worker
98*cfb92d14SAndroid Build Coastguard Worker OutputSpaces(aIndentSize);
99*cfb92d14SAndroid Build Coastguard Worker
100*cfb92d14SAndroid Build Coastguard Worker va_start(args, aFormat);
101*cfb92d14SAndroid Build Coastguard Worker OutputFormatV(aFormat, args);
102*cfb92d14SAndroid Build Coastguard Worker va_end(args);
103*cfb92d14SAndroid Build Coastguard Worker
104*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
105*cfb92d14SAndroid Build Coastguard Worker }
106*cfb92d14SAndroid Build Coastguard Worker
OutputNewLine(void)107*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputNewLine(void) { OutputFormat("\r\n"); }
108*cfb92d14SAndroid Build Coastguard Worker
OutputSpaces(uint8_t aCount)109*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputSpaces(uint8_t aCount) { OutputFormat("%*s", aCount, ""); }
110*cfb92d14SAndroid Build Coastguard Worker
OutputBytes(const uint8_t * aBytes,uint16_t aLength)111*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputBytes(const uint8_t *aBytes, uint16_t aLength)
112*cfb92d14SAndroid Build Coastguard Worker {
113*cfb92d14SAndroid Build Coastguard Worker for (uint16_t i = 0; i < aLength; i++)
114*cfb92d14SAndroid Build Coastguard Worker {
115*cfb92d14SAndroid Build Coastguard Worker OutputFormat("%02x", aBytes[i]);
116*cfb92d14SAndroid Build Coastguard Worker }
117*cfb92d14SAndroid Build Coastguard Worker }
118*cfb92d14SAndroid Build Coastguard Worker
OutputBytesLine(const uint8_t * aBytes,uint16_t aLength)119*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputBytesLine(const uint8_t *aBytes, uint16_t aLength)
120*cfb92d14SAndroid Build Coastguard Worker {
121*cfb92d14SAndroid Build Coastguard Worker OutputBytes(aBytes, aLength);
122*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
123*cfb92d14SAndroid Build Coastguard Worker }
124*cfb92d14SAndroid Build Coastguard Worker
Uint64ToString(uint64_t aUint64,Uint64StringBuffer & aBuffer)125*cfb92d14SAndroid Build Coastguard Worker const char *Utils::Uint64ToString(uint64_t aUint64, Uint64StringBuffer &aBuffer)
126*cfb92d14SAndroid Build Coastguard Worker {
127*cfb92d14SAndroid Build Coastguard Worker char *cur = &aBuffer.mChars[Uint64StringBuffer::kSize - 1];
128*cfb92d14SAndroid Build Coastguard Worker
129*cfb92d14SAndroid Build Coastguard Worker *cur = '\0';
130*cfb92d14SAndroid Build Coastguard Worker
131*cfb92d14SAndroid Build Coastguard Worker if (aUint64 == 0)
132*cfb92d14SAndroid Build Coastguard Worker {
133*cfb92d14SAndroid Build Coastguard Worker *(--cur) = '0';
134*cfb92d14SAndroid Build Coastguard Worker }
135*cfb92d14SAndroid Build Coastguard Worker else
136*cfb92d14SAndroid Build Coastguard Worker {
137*cfb92d14SAndroid Build Coastguard Worker for (; aUint64 != 0; aUint64 /= 10)
138*cfb92d14SAndroid Build Coastguard Worker {
139*cfb92d14SAndroid Build Coastguard Worker *(--cur) = static_cast<char>('0' + static_cast<uint8_t>(aUint64 % 10));
140*cfb92d14SAndroid Build Coastguard Worker }
141*cfb92d14SAndroid Build Coastguard Worker }
142*cfb92d14SAndroid Build Coastguard Worker
143*cfb92d14SAndroid Build Coastguard Worker return cur;
144*cfb92d14SAndroid Build Coastguard Worker }
145*cfb92d14SAndroid Build Coastguard Worker
OutputUint64(uint64_t aUint64)146*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputUint64(uint64_t aUint64)
147*cfb92d14SAndroid Build Coastguard Worker {
148*cfb92d14SAndroid Build Coastguard Worker Uint64StringBuffer buffer;
149*cfb92d14SAndroid Build Coastguard Worker
150*cfb92d14SAndroid Build Coastguard Worker OutputFormat("%s", Uint64ToString(aUint64, buffer));
151*cfb92d14SAndroid Build Coastguard Worker }
152*cfb92d14SAndroid Build Coastguard Worker
OutputUint64Line(uint64_t aUint64)153*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputUint64Line(uint64_t aUint64)
154*cfb92d14SAndroid Build Coastguard Worker {
155*cfb92d14SAndroid Build Coastguard Worker OutputUint64(aUint64);
156*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
157*cfb92d14SAndroid Build Coastguard Worker }
158*cfb92d14SAndroid Build Coastguard Worker
OutputEnabledDisabledStatus(bool aEnabled)159*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputEnabledDisabledStatus(bool aEnabled) { OutputLine(aEnabled ? "Enabled" : "Disabled"); }
160*cfb92d14SAndroid Build Coastguard Worker
161*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_FTD || OPENTHREAD_MTD
162*cfb92d14SAndroid Build Coastguard Worker
OutputIp6Address(const otIp6Address & aAddress)163*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6Address(const otIp6Address &aAddress)
164*cfb92d14SAndroid Build Coastguard Worker {
165*cfb92d14SAndroid Build Coastguard Worker char string[OT_IP6_ADDRESS_STRING_SIZE];
166*cfb92d14SAndroid Build Coastguard Worker
167*cfb92d14SAndroid Build Coastguard Worker otIp6AddressToString(&aAddress, string, sizeof(string));
168*cfb92d14SAndroid Build Coastguard Worker
169*cfb92d14SAndroid Build Coastguard Worker return OutputFormat("%s", string);
170*cfb92d14SAndroid Build Coastguard Worker }
171*cfb92d14SAndroid Build Coastguard Worker
OutputIp6AddressLine(const otIp6Address & aAddress)172*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6AddressLine(const otIp6Address &aAddress)
173*cfb92d14SAndroid Build Coastguard Worker {
174*cfb92d14SAndroid Build Coastguard Worker OutputIp6Address(aAddress);
175*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
176*cfb92d14SAndroid Build Coastguard Worker }
177*cfb92d14SAndroid Build Coastguard Worker
OutputIp6Prefix(const otIp6Prefix & aPrefix)178*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6Prefix(const otIp6Prefix &aPrefix)
179*cfb92d14SAndroid Build Coastguard Worker {
180*cfb92d14SAndroid Build Coastguard Worker char string[OT_IP6_PREFIX_STRING_SIZE];
181*cfb92d14SAndroid Build Coastguard Worker
182*cfb92d14SAndroid Build Coastguard Worker otIp6PrefixToString(&aPrefix, string, sizeof(string));
183*cfb92d14SAndroid Build Coastguard Worker
184*cfb92d14SAndroid Build Coastguard Worker OutputFormat("%s", string);
185*cfb92d14SAndroid Build Coastguard Worker }
186*cfb92d14SAndroid Build Coastguard Worker
OutputIp6PrefixLine(const otIp6Prefix & aPrefix)187*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6PrefixLine(const otIp6Prefix &aPrefix)
188*cfb92d14SAndroid Build Coastguard Worker {
189*cfb92d14SAndroid Build Coastguard Worker OutputIp6Prefix(aPrefix);
190*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
191*cfb92d14SAndroid Build Coastguard Worker }
192*cfb92d14SAndroid Build Coastguard Worker
OutputIp6Prefix(const otIp6NetworkPrefix & aPrefix)193*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6Prefix(const otIp6NetworkPrefix &aPrefix)
194*cfb92d14SAndroid Build Coastguard Worker {
195*cfb92d14SAndroid Build Coastguard Worker OutputFormat("%x:%x:%x:%x::/64", (aPrefix.m8[0] << 8) | aPrefix.m8[1], (aPrefix.m8[2] << 8) | aPrefix.m8[3],
196*cfb92d14SAndroid Build Coastguard Worker (aPrefix.m8[4] << 8) | aPrefix.m8[5], (aPrefix.m8[6] << 8) | aPrefix.m8[7]);
197*cfb92d14SAndroid Build Coastguard Worker }
198*cfb92d14SAndroid Build Coastguard Worker
OutputIp6PrefixLine(const otIp6NetworkPrefix & aPrefix)199*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputIp6PrefixLine(const otIp6NetworkPrefix &aPrefix)
200*cfb92d14SAndroid Build Coastguard Worker {
201*cfb92d14SAndroid Build Coastguard Worker OutputIp6Prefix(aPrefix);
202*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
203*cfb92d14SAndroid Build Coastguard Worker }
204*cfb92d14SAndroid Build Coastguard Worker
OutputSockAddr(const otSockAddr & aSockAddr)205*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputSockAddr(const otSockAddr &aSockAddr)
206*cfb92d14SAndroid Build Coastguard Worker {
207*cfb92d14SAndroid Build Coastguard Worker char string[OT_IP6_SOCK_ADDR_STRING_SIZE];
208*cfb92d14SAndroid Build Coastguard Worker
209*cfb92d14SAndroid Build Coastguard Worker otIp6SockAddrToString(&aSockAddr, string, sizeof(string));
210*cfb92d14SAndroid Build Coastguard Worker
211*cfb92d14SAndroid Build Coastguard Worker return OutputFormat("%s", string);
212*cfb92d14SAndroid Build Coastguard Worker }
213*cfb92d14SAndroid Build Coastguard Worker
OutputSockAddrLine(const otSockAddr & aSockAddr)214*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputSockAddrLine(const otSockAddr &aSockAddr)
215*cfb92d14SAndroid Build Coastguard Worker {
216*cfb92d14SAndroid Build Coastguard Worker OutputSockAddr(aSockAddr);
217*cfb92d14SAndroid Build Coastguard Worker OutputNewLine();
218*cfb92d14SAndroid Build Coastguard Worker }
219*cfb92d14SAndroid Build Coastguard Worker
OutputDnsTxtData(const uint8_t * aTxtData,uint16_t aTxtDataLength)220*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength)
221*cfb92d14SAndroid Build Coastguard Worker {
222*cfb92d14SAndroid Build Coastguard Worker otDnsTxtEntry entry;
223*cfb92d14SAndroid Build Coastguard Worker otDnsTxtEntryIterator iterator;
224*cfb92d14SAndroid Build Coastguard Worker bool isFirst = true;
225*cfb92d14SAndroid Build Coastguard Worker
226*cfb92d14SAndroid Build Coastguard Worker otDnsInitTxtEntryIterator(&iterator, aTxtData, aTxtDataLength);
227*cfb92d14SAndroid Build Coastguard Worker
228*cfb92d14SAndroid Build Coastguard Worker OutputFormat("[");
229*cfb92d14SAndroid Build Coastguard Worker
230*cfb92d14SAndroid Build Coastguard Worker while (otDnsGetNextTxtEntry(&iterator, &entry) == OT_ERROR_NONE)
231*cfb92d14SAndroid Build Coastguard Worker {
232*cfb92d14SAndroid Build Coastguard Worker if (!isFirst)
233*cfb92d14SAndroid Build Coastguard Worker {
234*cfb92d14SAndroid Build Coastguard Worker OutputFormat(", ");
235*cfb92d14SAndroid Build Coastguard Worker }
236*cfb92d14SAndroid Build Coastguard Worker
237*cfb92d14SAndroid Build Coastguard Worker if (entry.mKey == nullptr)
238*cfb92d14SAndroid Build Coastguard Worker {
239*cfb92d14SAndroid Build Coastguard Worker // A null `mKey` indicates that the key in the entry is
240*cfb92d14SAndroid Build Coastguard Worker // longer than the recommended max key length, so the entry
241*cfb92d14SAndroid Build Coastguard Worker // could not be parsed. In this case, the whole entry is
242*cfb92d14SAndroid Build Coastguard Worker // returned encoded in `mValue`.
243*cfb92d14SAndroid Build Coastguard Worker
244*cfb92d14SAndroid Build Coastguard Worker OutputFormat("[");
245*cfb92d14SAndroid Build Coastguard Worker OutputBytes(entry.mValue, entry.mValueLength);
246*cfb92d14SAndroid Build Coastguard Worker OutputFormat("]");
247*cfb92d14SAndroid Build Coastguard Worker }
248*cfb92d14SAndroid Build Coastguard Worker else
249*cfb92d14SAndroid Build Coastguard Worker {
250*cfb92d14SAndroid Build Coastguard Worker OutputFormat("%s", entry.mKey);
251*cfb92d14SAndroid Build Coastguard Worker
252*cfb92d14SAndroid Build Coastguard Worker if (entry.mValue != nullptr)
253*cfb92d14SAndroid Build Coastguard Worker {
254*cfb92d14SAndroid Build Coastguard Worker OutputFormat("=");
255*cfb92d14SAndroid Build Coastguard Worker OutputBytes(entry.mValue, entry.mValueLength);
256*cfb92d14SAndroid Build Coastguard Worker }
257*cfb92d14SAndroid Build Coastguard Worker }
258*cfb92d14SAndroid Build Coastguard Worker
259*cfb92d14SAndroid Build Coastguard Worker isFirst = false;
260*cfb92d14SAndroid Build Coastguard Worker }
261*cfb92d14SAndroid Build Coastguard Worker
262*cfb92d14SAndroid Build Coastguard Worker OutputFormat("]");
263*cfb92d14SAndroid Build Coastguard Worker }
264*cfb92d14SAndroid Build Coastguard Worker
PercentageToString(uint16_t aValue,PercentageStringBuffer & aBuffer)265*cfb92d14SAndroid Build Coastguard Worker const char *Utils::PercentageToString(uint16_t aValue, PercentageStringBuffer &aBuffer)
266*cfb92d14SAndroid Build Coastguard Worker {
267*cfb92d14SAndroid Build Coastguard Worker uint32_t scaledValue = aValue;
268*cfb92d14SAndroid Build Coastguard Worker StringWriter writer(aBuffer.mChars, sizeof(aBuffer.mChars));
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker scaledValue = (scaledValue * 10000) / 0xffff;
271*cfb92d14SAndroid Build Coastguard Worker writer.Append("%u.%02u", static_cast<uint16_t>(scaledValue / 100), static_cast<uint16_t>(scaledValue % 100));
272*cfb92d14SAndroid Build Coastguard Worker
273*cfb92d14SAndroid Build Coastguard Worker return aBuffer.mChars;
274*cfb92d14SAndroid Build Coastguard Worker }
275*cfb92d14SAndroid Build Coastguard Worker
276*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_FTD || OPENTHREAD_MTD
277*cfb92d14SAndroid Build Coastguard Worker
OutputFormatV(const char * aFormat,va_list aArguments)278*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputFormatV(const char *aFormat, va_list aArguments) { mImplementer.OutputV(aFormat, aArguments); }
279*cfb92d14SAndroid Build Coastguard Worker
OutputV(const char * aFormat,va_list aArguments)280*cfb92d14SAndroid Build Coastguard Worker void OutputImplementer::OutputV(const char *aFormat, va_list aArguments)
281*cfb92d14SAndroid Build Coastguard Worker {
282*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
283*cfb92d14SAndroid Build Coastguard Worker va_list args;
284*cfb92d14SAndroid Build Coastguard Worker int charsWritten;
285*cfb92d14SAndroid Build Coastguard Worker bool truncated = false;
286*cfb92d14SAndroid Build Coastguard Worker
287*cfb92d14SAndroid Build Coastguard Worker va_copy(args, aArguments);
288*cfb92d14SAndroid Build Coastguard Worker #endif
289*cfb92d14SAndroid Build Coastguard Worker
290*cfb92d14SAndroid Build Coastguard Worker mCallback(mCallbackContext, aFormat, aArguments);
291*cfb92d14SAndroid Build Coastguard Worker
292*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
293*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(mEmittingCommandOutput);
294*cfb92d14SAndroid Build Coastguard Worker
295*cfb92d14SAndroid Build Coastguard Worker charsWritten = vsnprintf(&mOutputString[mOutputLength], sizeof(mOutputString) - mOutputLength, aFormat, args);
296*cfb92d14SAndroid Build Coastguard Worker
297*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(charsWritten >= 0, mOutputLength = 0);
298*cfb92d14SAndroid Build Coastguard Worker
299*cfb92d14SAndroid Build Coastguard Worker if (static_cast<uint32_t>(charsWritten) >= sizeof(mOutputString) - mOutputLength)
300*cfb92d14SAndroid Build Coastguard Worker {
301*cfb92d14SAndroid Build Coastguard Worker truncated = true;
302*cfb92d14SAndroid Build Coastguard Worker mOutputLength = sizeof(mOutputString) - 1;
303*cfb92d14SAndroid Build Coastguard Worker }
304*cfb92d14SAndroid Build Coastguard Worker else
305*cfb92d14SAndroid Build Coastguard Worker {
306*cfb92d14SAndroid Build Coastguard Worker mOutputLength += charsWritten;
307*cfb92d14SAndroid Build Coastguard Worker }
308*cfb92d14SAndroid Build Coastguard Worker
309*cfb92d14SAndroid Build Coastguard Worker while (true)
310*cfb92d14SAndroid Build Coastguard Worker {
311*cfb92d14SAndroid Build Coastguard Worker char *lineEnd = strchr(mOutputString, '\r');
312*cfb92d14SAndroid Build Coastguard Worker
313*cfb92d14SAndroid Build Coastguard Worker if (lineEnd == nullptr)
314*cfb92d14SAndroid Build Coastguard Worker {
315*cfb92d14SAndroid Build Coastguard Worker break;
316*cfb92d14SAndroid Build Coastguard Worker }
317*cfb92d14SAndroid Build Coastguard Worker
318*cfb92d14SAndroid Build Coastguard Worker *lineEnd = '\0';
319*cfb92d14SAndroid Build Coastguard Worker
320*cfb92d14SAndroid Build Coastguard Worker if (lineEnd > mOutputString)
321*cfb92d14SAndroid Build Coastguard Worker {
322*cfb92d14SAndroid Build Coastguard Worker otLogCli(OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LEVEL, "Output: %s", mOutputString);
323*cfb92d14SAndroid Build Coastguard Worker }
324*cfb92d14SAndroid Build Coastguard Worker
325*cfb92d14SAndroid Build Coastguard Worker lineEnd++;
326*cfb92d14SAndroid Build Coastguard Worker
327*cfb92d14SAndroid Build Coastguard Worker while ((*lineEnd == '\n') || (*lineEnd == '\r'))
328*cfb92d14SAndroid Build Coastguard Worker {
329*cfb92d14SAndroid Build Coastguard Worker lineEnd++;
330*cfb92d14SAndroid Build Coastguard Worker }
331*cfb92d14SAndroid Build Coastguard Worker
332*cfb92d14SAndroid Build Coastguard Worker // Example of the pointers and lengths.
333*cfb92d14SAndroid Build Coastguard Worker //
334*cfb92d14SAndroid Build Coastguard Worker // - mOutputString = "hi\r\nmore"
335*cfb92d14SAndroid Build Coastguard Worker // - mOutputLength = 8
336*cfb92d14SAndroid Build Coastguard Worker // - lineEnd = &mOutputString[4]
337*cfb92d14SAndroid Build Coastguard Worker //
338*cfb92d14SAndroid Build Coastguard Worker //
339*cfb92d14SAndroid Build Coastguard Worker // 0 1 2 3 4 5 6 7 8 9
340*cfb92d14SAndroid Build Coastguard Worker // +----+----+----+----+----+----+----+----+----+---
341*cfb92d14SAndroid Build Coastguard Worker // | h | i | \r | \n | m | o | r | e | \0 |
342*cfb92d14SAndroid Build Coastguard Worker // +----+----+----+----+----+----+----+----+----+---
343*cfb92d14SAndroid Build Coastguard Worker // ^ ^
344*cfb92d14SAndroid Build Coastguard Worker // | |
345*cfb92d14SAndroid Build Coastguard Worker // lineEnd mOutputString[mOutputLength]
346*cfb92d14SAndroid Build Coastguard Worker //
347*cfb92d14SAndroid Build Coastguard Worker //
348*cfb92d14SAndroid Build Coastguard Worker // New length is `&mOutputString[8] - &mOutputString[4] -> 4`.
349*cfb92d14SAndroid Build Coastguard Worker //
350*cfb92d14SAndroid Build Coastguard Worker // We move (newLen + 1 = 5) chars from `lineEnd` to start of
351*cfb92d14SAndroid Build Coastguard Worker // `mOutputString` which will include the `\0` char.
352*cfb92d14SAndroid Build Coastguard Worker //
353*cfb92d14SAndroid Build Coastguard Worker // If `lineEnd` and `mOutputString[mOutputLength]` are the same
354*cfb92d14SAndroid Build Coastguard Worker // the code works correctly as well (new length set to zero and
355*cfb92d14SAndroid Build Coastguard Worker // the `\0` is copied).
356*cfb92d14SAndroid Build Coastguard Worker
357*cfb92d14SAndroid Build Coastguard Worker mOutputLength = static_cast<uint16_t>(&mOutputString[mOutputLength] - lineEnd);
358*cfb92d14SAndroid Build Coastguard Worker memmove(mOutputString, lineEnd, mOutputLength + 1);
359*cfb92d14SAndroid Build Coastguard Worker }
360*cfb92d14SAndroid Build Coastguard Worker
361*cfb92d14SAndroid Build Coastguard Worker if (truncated)
362*cfb92d14SAndroid Build Coastguard Worker {
363*cfb92d14SAndroid Build Coastguard Worker otLogCli(OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LEVEL, "Output: %s ...", mOutputString);
364*cfb92d14SAndroid Build Coastguard Worker mOutputLength = 0;
365*cfb92d14SAndroid Build Coastguard Worker }
366*cfb92d14SAndroid Build Coastguard Worker
367*cfb92d14SAndroid Build Coastguard Worker exit:
368*cfb92d14SAndroid Build Coastguard Worker va_end(args);
369*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
370*cfb92d14SAndroid Build Coastguard Worker }
371*cfb92d14SAndroid Build Coastguard Worker
372*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_ENABLE
LogInput(const Arg * aArgs)373*cfb92d14SAndroid Build Coastguard Worker void Utils::LogInput(const Arg *aArgs)
374*cfb92d14SAndroid Build Coastguard Worker {
375*cfb92d14SAndroid Build Coastguard Worker String<kInputOutputLogStringSize> inputString;
376*cfb92d14SAndroid Build Coastguard Worker
377*cfb92d14SAndroid Build Coastguard Worker for (bool isFirst = true; !aArgs->IsEmpty(); aArgs++, isFirst = false)
378*cfb92d14SAndroid Build Coastguard Worker {
379*cfb92d14SAndroid Build Coastguard Worker inputString.Append(isFirst ? "%s" : " %s", aArgs->GetCString());
380*cfb92d14SAndroid Build Coastguard Worker }
381*cfb92d14SAndroid Build Coastguard Worker
382*cfb92d14SAndroid Build Coastguard Worker otLogCli(OPENTHREAD_CONFIG_CLI_LOG_INPUT_OUTPUT_LEVEL, "Input: %s", inputString.AsCString());
383*cfb92d14SAndroid Build Coastguard Worker }
384*cfb92d14SAndroid Build Coastguard Worker #endif
385*cfb92d14SAndroid Build Coastguard Worker
OutputTableHeader(uint8_t aNumColumns,const char * const aTitles[],const uint8_t aWidths[])386*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputTableHeader(uint8_t aNumColumns, const char *const aTitles[], const uint8_t aWidths[])
387*cfb92d14SAndroid Build Coastguard Worker {
388*cfb92d14SAndroid Build Coastguard Worker for (uint8_t index = 0; index < aNumColumns; index++)
389*cfb92d14SAndroid Build Coastguard Worker {
390*cfb92d14SAndroid Build Coastguard Worker const char *title = aTitles[index];
391*cfb92d14SAndroid Build Coastguard Worker uint8_t width = aWidths[index];
392*cfb92d14SAndroid Build Coastguard Worker size_t titleLength = strlen(title);
393*cfb92d14SAndroid Build Coastguard Worker
394*cfb92d14SAndroid Build Coastguard Worker if (titleLength + 2 <= width)
395*cfb92d14SAndroid Build Coastguard Worker {
396*cfb92d14SAndroid Build Coastguard Worker // `title` fits in column width so we write it with extra space
397*cfb92d14SAndroid Build Coastguard Worker // at beginning and end ("| Title |").
398*cfb92d14SAndroid Build Coastguard Worker
399*cfb92d14SAndroid Build Coastguard Worker OutputFormat("| %*s", -static_cast<int>(width - 1), title);
400*cfb92d14SAndroid Build Coastguard Worker }
401*cfb92d14SAndroid Build Coastguard Worker else
402*cfb92d14SAndroid Build Coastguard Worker {
403*cfb92d14SAndroid Build Coastguard Worker // Use narrow style (no space at beginning) and write as many
404*cfb92d14SAndroid Build Coastguard Worker // chars from `title` as it can fit in the given column width
405*cfb92d14SAndroid Build Coastguard Worker // ("|Title|").
406*cfb92d14SAndroid Build Coastguard Worker
407*cfb92d14SAndroid Build Coastguard Worker OutputFormat("|%*.*s", -static_cast<int>(width), width, title);
408*cfb92d14SAndroid Build Coastguard Worker }
409*cfb92d14SAndroid Build Coastguard Worker }
410*cfb92d14SAndroid Build Coastguard Worker
411*cfb92d14SAndroid Build Coastguard Worker OutputLine("|");
412*cfb92d14SAndroid Build Coastguard Worker OutputTableSeparator(aNumColumns, aWidths);
413*cfb92d14SAndroid Build Coastguard Worker }
414*cfb92d14SAndroid Build Coastguard Worker
OutputTableSeparator(uint8_t aNumColumns,const uint8_t aWidths[])415*cfb92d14SAndroid Build Coastguard Worker void Utils::OutputTableSeparator(uint8_t aNumColumns, const uint8_t aWidths[])
416*cfb92d14SAndroid Build Coastguard Worker {
417*cfb92d14SAndroid Build Coastguard Worker for (uint8_t index = 0; index < aNumColumns; index++)
418*cfb92d14SAndroid Build Coastguard Worker {
419*cfb92d14SAndroid Build Coastguard Worker OutputFormat("+");
420*cfb92d14SAndroid Build Coastguard Worker
421*cfb92d14SAndroid Build Coastguard Worker for (uint8_t width = aWidths[index]; width != 0; width--)
422*cfb92d14SAndroid Build Coastguard Worker {
423*cfb92d14SAndroid Build Coastguard Worker OutputFormat("-");
424*cfb92d14SAndroid Build Coastguard Worker }
425*cfb92d14SAndroid Build Coastguard Worker }
426*cfb92d14SAndroid Build Coastguard Worker
427*cfb92d14SAndroid Build Coastguard Worker OutputLine("+");
428*cfb92d14SAndroid Build Coastguard Worker }
429*cfb92d14SAndroid Build Coastguard Worker
ParseEnableOrDisable(const Arg & aArg,bool & aEnable)430*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParseEnableOrDisable(const Arg &aArg, bool &aEnable)
431*cfb92d14SAndroid Build Coastguard Worker {
432*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
433*cfb92d14SAndroid Build Coastguard Worker
434*cfb92d14SAndroid Build Coastguard Worker if (aArg == "enable")
435*cfb92d14SAndroid Build Coastguard Worker {
436*cfb92d14SAndroid Build Coastguard Worker aEnable = true;
437*cfb92d14SAndroid Build Coastguard Worker }
438*cfb92d14SAndroid Build Coastguard Worker else if (aArg == "disable")
439*cfb92d14SAndroid Build Coastguard Worker {
440*cfb92d14SAndroid Build Coastguard Worker aEnable = false;
441*cfb92d14SAndroid Build Coastguard Worker }
442*cfb92d14SAndroid Build Coastguard Worker else
443*cfb92d14SAndroid Build Coastguard Worker {
444*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_COMMAND;
445*cfb92d14SAndroid Build Coastguard Worker }
446*cfb92d14SAndroid Build Coastguard Worker
447*cfb92d14SAndroid Build Coastguard Worker return error;
448*cfb92d14SAndroid Build Coastguard Worker }
449*cfb92d14SAndroid Build Coastguard Worker
ProcessEnableDisable(Arg aArgs[],SetEnabledHandler aSetEnabledHandler)450*cfb92d14SAndroid Build Coastguard Worker otError Utils::ProcessEnableDisable(Arg aArgs[], SetEnabledHandler aSetEnabledHandler)
451*cfb92d14SAndroid Build Coastguard Worker {
452*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
453*cfb92d14SAndroid Build Coastguard Worker bool enable;
454*cfb92d14SAndroid Build Coastguard Worker
455*cfb92d14SAndroid Build Coastguard Worker if (ParseEnableOrDisable(aArgs[0], enable) == OT_ERROR_NONE)
456*cfb92d14SAndroid Build Coastguard Worker {
457*cfb92d14SAndroid Build Coastguard Worker aSetEnabledHandler(GetInstancePtr(), enable);
458*cfb92d14SAndroid Build Coastguard Worker }
459*cfb92d14SAndroid Build Coastguard Worker else
460*cfb92d14SAndroid Build Coastguard Worker {
461*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_COMMAND;
462*cfb92d14SAndroid Build Coastguard Worker }
463*cfb92d14SAndroid Build Coastguard Worker
464*cfb92d14SAndroid Build Coastguard Worker return error;
465*cfb92d14SAndroid Build Coastguard Worker }
466*cfb92d14SAndroid Build Coastguard Worker
ProcessEnableDisable(Arg aArgs[],SetEnabledHandlerFailable aSetEnabledHandler)467*cfb92d14SAndroid Build Coastguard Worker otError Utils::ProcessEnableDisable(Arg aArgs[], SetEnabledHandlerFailable aSetEnabledHandler)
468*cfb92d14SAndroid Build Coastguard Worker {
469*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
470*cfb92d14SAndroid Build Coastguard Worker bool enable;
471*cfb92d14SAndroid Build Coastguard Worker
472*cfb92d14SAndroid Build Coastguard Worker if (ParseEnableOrDisable(aArgs[0], enable) == OT_ERROR_NONE)
473*cfb92d14SAndroid Build Coastguard Worker {
474*cfb92d14SAndroid Build Coastguard Worker error = aSetEnabledHandler(GetInstancePtr(), enable);
475*cfb92d14SAndroid Build Coastguard Worker }
476*cfb92d14SAndroid Build Coastguard Worker else
477*cfb92d14SAndroid Build Coastguard Worker {
478*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_COMMAND;
479*cfb92d14SAndroid Build Coastguard Worker }
480*cfb92d14SAndroid Build Coastguard Worker
481*cfb92d14SAndroid Build Coastguard Worker return error;
482*cfb92d14SAndroid Build Coastguard Worker }
483*cfb92d14SAndroid Build Coastguard Worker
ProcessEnableDisable(Arg aArgs[],IsEnabledHandler aIsEnabledHandler,SetEnabledHandler aSetEnabledHandler)484*cfb92d14SAndroid Build Coastguard Worker otError Utils::ProcessEnableDisable(Arg aArgs[],
485*cfb92d14SAndroid Build Coastguard Worker IsEnabledHandler aIsEnabledHandler,
486*cfb92d14SAndroid Build Coastguard Worker SetEnabledHandler aSetEnabledHandler)
487*cfb92d14SAndroid Build Coastguard Worker {
488*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
489*cfb92d14SAndroid Build Coastguard Worker
490*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0].IsEmpty())
491*cfb92d14SAndroid Build Coastguard Worker {
492*cfb92d14SAndroid Build Coastguard Worker OutputEnabledDisabledStatus(aIsEnabledHandler(GetInstancePtr()));
493*cfb92d14SAndroid Build Coastguard Worker }
494*cfb92d14SAndroid Build Coastguard Worker else
495*cfb92d14SAndroid Build Coastguard Worker {
496*cfb92d14SAndroid Build Coastguard Worker error = ProcessEnableDisable(aArgs, aSetEnabledHandler);
497*cfb92d14SAndroid Build Coastguard Worker }
498*cfb92d14SAndroid Build Coastguard Worker
499*cfb92d14SAndroid Build Coastguard Worker return error;
500*cfb92d14SAndroid Build Coastguard Worker }
501*cfb92d14SAndroid Build Coastguard Worker
ProcessEnableDisable(Arg aArgs[],IsEnabledHandler aIsEnabledHandler,SetEnabledHandlerFailable aSetEnabledHandler)502*cfb92d14SAndroid Build Coastguard Worker otError Utils::ProcessEnableDisable(Arg aArgs[],
503*cfb92d14SAndroid Build Coastguard Worker IsEnabledHandler aIsEnabledHandler,
504*cfb92d14SAndroid Build Coastguard Worker SetEnabledHandlerFailable aSetEnabledHandler)
505*cfb92d14SAndroid Build Coastguard Worker {
506*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
507*cfb92d14SAndroid Build Coastguard Worker
508*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0].IsEmpty())
509*cfb92d14SAndroid Build Coastguard Worker {
510*cfb92d14SAndroid Build Coastguard Worker OutputEnabledDisabledStatus(aIsEnabledHandler(GetInstancePtr()));
511*cfb92d14SAndroid Build Coastguard Worker }
512*cfb92d14SAndroid Build Coastguard Worker else
513*cfb92d14SAndroid Build Coastguard Worker {
514*cfb92d14SAndroid Build Coastguard Worker error = ProcessEnableDisable(aArgs, aSetEnabledHandler);
515*cfb92d14SAndroid Build Coastguard Worker }
516*cfb92d14SAndroid Build Coastguard Worker
517*cfb92d14SAndroid Build Coastguard Worker return error;
518*cfb92d14SAndroid Build Coastguard Worker }
519*cfb92d14SAndroid Build Coastguard Worker
ParseJoinerDiscerner(Arg & aArg,otJoinerDiscerner & aDiscerner)520*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner)
521*cfb92d14SAndroid Build Coastguard Worker {
522*cfb92d14SAndroid Build Coastguard Worker otError error;
523*cfb92d14SAndroid Build Coastguard Worker char *separator;
524*cfb92d14SAndroid Build Coastguard Worker
525*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS);
526*cfb92d14SAndroid Build Coastguard Worker
527*cfb92d14SAndroid Build Coastguard Worker separator = strstr(aArg.GetCString(), "/");
528*cfb92d14SAndroid Build Coastguard Worker
529*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(separator != nullptr, error = OT_ERROR_NOT_FOUND);
530*cfb92d14SAndroid Build Coastguard Worker
531*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsUint8(separator + 1, aDiscerner.mLength));
532*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(aDiscerner.mLength > 0 && aDiscerner.mLength <= 64, error = OT_ERROR_INVALID_ARGS);
533*cfb92d14SAndroid Build Coastguard Worker *separator = '\0';
534*cfb92d14SAndroid Build Coastguard Worker error = aArg.ParseAsUint64(aDiscerner.mValue);
535*cfb92d14SAndroid Build Coastguard Worker
536*cfb92d14SAndroid Build Coastguard Worker exit:
537*cfb92d14SAndroid Build Coastguard Worker return error;
538*cfb92d14SAndroid Build Coastguard Worker }
539*cfb92d14SAndroid Build Coastguard Worker
ParsePreference(const Arg & aArg,otRoutePreference & aPreference)540*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParsePreference(const Arg &aArg, otRoutePreference &aPreference)
541*cfb92d14SAndroid Build Coastguard Worker {
542*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
543*cfb92d14SAndroid Build Coastguard Worker
544*cfb92d14SAndroid Build Coastguard Worker if (aArg == "high")
545*cfb92d14SAndroid Build Coastguard Worker {
546*cfb92d14SAndroid Build Coastguard Worker aPreference = OT_ROUTE_PREFERENCE_HIGH;
547*cfb92d14SAndroid Build Coastguard Worker }
548*cfb92d14SAndroid Build Coastguard Worker else if (aArg == "med")
549*cfb92d14SAndroid Build Coastguard Worker {
550*cfb92d14SAndroid Build Coastguard Worker aPreference = OT_ROUTE_PREFERENCE_MED;
551*cfb92d14SAndroid Build Coastguard Worker }
552*cfb92d14SAndroid Build Coastguard Worker else if (aArg == "low")
553*cfb92d14SAndroid Build Coastguard Worker {
554*cfb92d14SAndroid Build Coastguard Worker aPreference = OT_ROUTE_PREFERENCE_LOW;
555*cfb92d14SAndroid Build Coastguard Worker }
556*cfb92d14SAndroid Build Coastguard Worker else
557*cfb92d14SAndroid Build Coastguard Worker {
558*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_ARGS;
559*cfb92d14SAndroid Build Coastguard Worker }
560*cfb92d14SAndroid Build Coastguard Worker
561*cfb92d14SAndroid Build Coastguard Worker return error;
562*cfb92d14SAndroid Build Coastguard Worker }
563*cfb92d14SAndroid Build Coastguard Worker
PreferenceToString(signed int aPreference)564*cfb92d14SAndroid Build Coastguard Worker const char *Utils::PreferenceToString(signed int aPreference)
565*cfb92d14SAndroid Build Coastguard Worker {
566*cfb92d14SAndroid Build Coastguard Worker const char *str = "";
567*cfb92d14SAndroid Build Coastguard Worker
568*cfb92d14SAndroid Build Coastguard Worker switch (aPreference)
569*cfb92d14SAndroid Build Coastguard Worker {
570*cfb92d14SAndroid Build Coastguard Worker case OT_ROUTE_PREFERENCE_LOW:
571*cfb92d14SAndroid Build Coastguard Worker str = "low";
572*cfb92d14SAndroid Build Coastguard Worker break;
573*cfb92d14SAndroid Build Coastguard Worker
574*cfb92d14SAndroid Build Coastguard Worker case OT_ROUTE_PREFERENCE_MED:
575*cfb92d14SAndroid Build Coastguard Worker str = "med";
576*cfb92d14SAndroid Build Coastguard Worker break;
577*cfb92d14SAndroid Build Coastguard Worker
578*cfb92d14SAndroid Build Coastguard Worker case OT_ROUTE_PREFERENCE_HIGH:
579*cfb92d14SAndroid Build Coastguard Worker str = "high";
580*cfb92d14SAndroid Build Coastguard Worker break;
581*cfb92d14SAndroid Build Coastguard Worker
582*cfb92d14SAndroid Build Coastguard Worker default:
583*cfb92d14SAndroid Build Coastguard Worker break;
584*cfb92d14SAndroid Build Coastguard Worker }
585*cfb92d14SAndroid Build Coastguard Worker
586*cfb92d14SAndroid Build Coastguard Worker return str;
587*cfb92d14SAndroid Build Coastguard Worker }
588*cfb92d14SAndroid Build Coastguard Worker
589*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_FTD || OPENTHREAD_MTD
ParseToIp6Address(otInstance * aInstance,const Arg & aArg,otIp6Address & aAddress,bool & aSynthesized)590*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParseToIp6Address(otInstance *aInstance, const Arg &aArg, otIp6Address &aAddress, bool &aSynthesized)
591*cfb92d14SAndroid Build Coastguard Worker {
592*cfb92d14SAndroid Build Coastguard Worker Error error = OT_ERROR_NONE;
593*cfb92d14SAndroid Build Coastguard Worker
594*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS);
595*cfb92d14SAndroid Build Coastguard Worker error = aArg.ParseAsIp6Address(aAddress);
596*cfb92d14SAndroid Build Coastguard Worker aSynthesized = false;
597*cfb92d14SAndroid Build Coastguard Worker
598*cfb92d14SAndroid Build Coastguard Worker if (error != OT_ERROR_NONE)
599*cfb92d14SAndroid Build Coastguard Worker {
600*cfb92d14SAndroid Build Coastguard Worker // It might be an IPv4 address, let's have a try.
601*cfb92d14SAndroid Build Coastguard Worker otIp4Address ip4Address;
602*cfb92d14SAndroid Build Coastguard Worker
603*cfb92d14SAndroid Build Coastguard Worker // Do not touch the error value if we failed to parse it as an IPv4 address.
604*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(aArg.ParseAsIp4Address(ip4Address));
605*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = otNat64SynthesizeIp6Address(aInstance, &ip4Address, &aAddress));
606*cfb92d14SAndroid Build Coastguard Worker aSynthesized = true;
607*cfb92d14SAndroid Build Coastguard Worker }
608*cfb92d14SAndroid Build Coastguard Worker
609*cfb92d14SAndroid Build Coastguard Worker exit:
610*cfb92d14SAndroid Build Coastguard Worker return error;
611*cfb92d14SAndroid Build Coastguard Worker }
612*cfb92d14SAndroid Build Coastguard Worker
613*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
ParsePrefix(Arg aArgs[],otBorderRouterConfig & aConfig)614*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig)
615*cfb92d14SAndroid Build Coastguard Worker {
616*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
617*cfb92d14SAndroid Build Coastguard Worker
618*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(aConfig);
619*cfb92d14SAndroid Build Coastguard Worker
620*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix));
621*cfb92d14SAndroid Build Coastguard Worker aArgs++;
622*cfb92d14SAndroid Build Coastguard Worker
623*cfb92d14SAndroid Build Coastguard Worker for (; !aArgs->IsEmpty(); aArgs++)
624*cfb92d14SAndroid Build Coastguard Worker {
625*cfb92d14SAndroid Build Coastguard Worker otRoutePreference preference;
626*cfb92d14SAndroid Build Coastguard Worker
627*cfb92d14SAndroid Build Coastguard Worker if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE)
628*cfb92d14SAndroid Build Coastguard Worker {
629*cfb92d14SAndroid Build Coastguard Worker aConfig.mPreference = preference;
630*cfb92d14SAndroid Build Coastguard Worker }
631*cfb92d14SAndroid Build Coastguard Worker else
632*cfb92d14SAndroid Build Coastguard Worker {
633*cfb92d14SAndroid Build Coastguard Worker for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++)
634*cfb92d14SAndroid Build Coastguard Worker {
635*cfb92d14SAndroid Build Coastguard Worker switch (*arg)
636*cfb92d14SAndroid Build Coastguard Worker {
637*cfb92d14SAndroid Build Coastguard Worker case 'p':
638*cfb92d14SAndroid Build Coastguard Worker aConfig.mPreferred = true;
639*cfb92d14SAndroid Build Coastguard Worker break;
640*cfb92d14SAndroid Build Coastguard Worker
641*cfb92d14SAndroid Build Coastguard Worker case 'a':
642*cfb92d14SAndroid Build Coastguard Worker aConfig.mSlaac = true;
643*cfb92d14SAndroid Build Coastguard Worker break;
644*cfb92d14SAndroid Build Coastguard Worker
645*cfb92d14SAndroid Build Coastguard Worker case 'd':
646*cfb92d14SAndroid Build Coastguard Worker aConfig.mDhcp = true;
647*cfb92d14SAndroid Build Coastguard Worker break;
648*cfb92d14SAndroid Build Coastguard Worker
649*cfb92d14SAndroid Build Coastguard Worker case 'c':
650*cfb92d14SAndroid Build Coastguard Worker aConfig.mConfigure = true;
651*cfb92d14SAndroid Build Coastguard Worker break;
652*cfb92d14SAndroid Build Coastguard Worker
653*cfb92d14SAndroid Build Coastguard Worker case 'r':
654*cfb92d14SAndroid Build Coastguard Worker aConfig.mDefaultRoute = true;
655*cfb92d14SAndroid Build Coastguard Worker break;
656*cfb92d14SAndroid Build Coastguard Worker
657*cfb92d14SAndroid Build Coastguard Worker case 'o':
658*cfb92d14SAndroid Build Coastguard Worker aConfig.mOnMesh = true;
659*cfb92d14SAndroid Build Coastguard Worker break;
660*cfb92d14SAndroid Build Coastguard Worker
661*cfb92d14SAndroid Build Coastguard Worker case 's':
662*cfb92d14SAndroid Build Coastguard Worker aConfig.mStable = true;
663*cfb92d14SAndroid Build Coastguard Worker break;
664*cfb92d14SAndroid Build Coastguard Worker
665*cfb92d14SAndroid Build Coastguard Worker case 'n':
666*cfb92d14SAndroid Build Coastguard Worker aConfig.mNdDns = true;
667*cfb92d14SAndroid Build Coastguard Worker break;
668*cfb92d14SAndroid Build Coastguard Worker
669*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
670*cfb92d14SAndroid Build Coastguard Worker case 'D':
671*cfb92d14SAndroid Build Coastguard Worker aConfig.mDp = true;
672*cfb92d14SAndroid Build Coastguard Worker break;
673*cfb92d14SAndroid Build Coastguard Worker #endif
674*cfb92d14SAndroid Build Coastguard Worker case '-':
675*cfb92d14SAndroid Build Coastguard Worker break;
676*cfb92d14SAndroid Build Coastguard Worker
677*cfb92d14SAndroid Build Coastguard Worker default:
678*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
679*cfb92d14SAndroid Build Coastguard Worker }
680*cfb92d14SAndroid Build Coastguard Worker }
681*cfb92d14SAndroid Build Coastguard Worker }
682*cfb92d14SAndroid Build Coastguard Worker }
683*cfb92d14SAndroid Build Coastguard Worker
684*cfb92d14SAndroid Build Coastguard Worker exit:
685*cfb92d14SAndroid Build Coastguard Worker return error;
686*cfb92d14SAndroid Build Coastguard Worker }
687*cfb92d14SAndroid Build Coastguard Worker
ParseRoute(Arg aArgs[],otExternalRouteConfig & aConfig)688*cfb92d14SAndroid Build Coastguard Worker otError Utils::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig)
689*cfb92d14SAndroid Build Coastguard Worker {
690*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
691*cfb92d14SAndroid Build Coastguard Worker
692*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(aConfig);
693*cfb92d14SAndroid Build Coastguard Worker
694*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix));
695*cfb92d14SAndroid Build Coastguard Worker aArgs++;
696*cfb92d14SAndroid Build Coastguard Worker
697*cfb92d14SAndroid Build Coastguard Worker for (; !aArgs->IsEmpty(); aArgs++)
698*cfb92d14SAndroid Build Coastguard Worker {
699*cfb92d14SAndroid Build Coastguard Worker otRoutePreference preference;
700*cfb92d14SAndroid Build Coastguard Worker
701*cfb92d14SAndroid Build Coastguard Worker if (ParsePreference(*aArgs, preference) == OT_ERROR_NONE)
702*cfb92d14SAndroid Build Coastguard Worker {
703*cfb92d14SAndroid Build Coastguard Worker aConfig.mPreference = preference;
704*cfb92d14SAndroid Build Coastguard Worker }
705*cfb92d14SAndroid Build Coastguard Worker else
706*cfb92d14SAndroid Build Coastguard Worker {
707*cfb92d14SAndroid Build Coastguard Worker for (char *arg = aArgs->GetCString(); *arg != '\0'; arg++)
708*cfb92d14SAndroid Build Coastguard Worker {
709*cfb92d14SAndroid Build Coastguard Worker switch (*arg)
710*cfb92d14SAndroid Build Coastguard Worker {
711*cfb92d14SAndroid Build Coastguard Worker case 's':
712*cfb92d14SAndroid Build Coastguard Worker aConfig.mStable = true;
713*cfb92d14SAndroid Build Coastguard Worker break;
714*cfb92d14SAndroid Build Coastguard Worker
715*cfb92d14SAndroid Build Coastguard Worker case 'n':
716*cfb92d14SAndroid Build Coastguard Worker aConfig.mNat64 = true;
717*cfb92d14SAndroid Build Coastguard Worker break;
718*cfb92d14SAndroid Build Coastguard Worker
719*cfb92d14SAndroid Build Coastguard Worker case 'a':
720*cfb92d14SAndroid Build Coastguard Worker aConfig.mAdvPio = true;
721*cfb92d14SAndroid Build Coastguard Worker break;
722*cfb92d14SAndroid Build Coastguard Worker
723*cfb92d14SAndroid Build Coastguard Worker case '-':
724*cfb92d14SAndroid Build Coastguard Worker break;
725*cfb92d14SAndroid Build Coastguard Worker
726*cfb92d14SAndroid Build Coastguard Worker default:
727*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
728*cfb92d14SAndroid Build Coastguard Worker }
729*cfb92d14SAndroid Build Coastguard Worker }
730*cfb92d14SAndroid Build Coastguard Worker }
731*cfb92d14SAndroid Build Coastguard Worker }
732*cfb92d14SAndroid Build Coastguard Worker
733*cfb92d14SAndroid Build Coastguard Worker exit:
734*cfb92d14SAndroid Build Coastguard Worker return error;
735*cfb92d14SAndroid Build Coastguard Worker }
736*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
737*cfb92d14SAndroid Build Coastguard Worker #endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD
738*cfb92d14SAndroid Build Coastguard Worker
LinkModeToString(const otLinkModeConfig & aLinkMode,char (& aStringBuffer)[kLinkModeStringSize])739*cfb92d14SAndroid Build Coastguard Worker const char *Utils::LinkModeToString(const otLinkModeConfig &aLinkMode, char (&aStringBuffer)[kLinkModeStringSize])
740*cfb92d14SAndroid Build Coastguard Worker {
741*cfb92d14SAndroid Build Coastguard Worker char *flagsPtr = &aStringBuffer[0];
742*cfb92d14SAndroid Build Coastguard Worker
743*cfb92d14SAndroid Build Coastguard Worker if (aLinkMode.mRxOnWhenIdle)
744*cfb92d14SAndroid Build Coastguard Worker {
745*cfb92d14SAndroid Build Coastguard Worker *flagsPtr++ = 'r';
746*cfb92d14SAndroid Build Coastguard Worker }
747*cfb92d14SAndroid Build Coastguard Worker
748*cfb92d14SAndroid Build Coastguard Worker if (aLinkMode.mDeviceType)
749*cfb92d14SAndroid Build Coastguard Worker {
750*cfb92d14SAndroid Build Coastguard Worker *flagsPtr++ = 'd';
751*cfb92d14SAndroid Build Coastguard Worker }
752*cfb92d14SAndroid Build Coastguard Worker
753*cfb92d14SAndroid Build Coastguard Worker if (aLinkMode.mNetworkData)
754*cfb92d14SAndroid Build Coastguard Worker {
755*cfb92d14SAndroid Build Coastguard Worker *flagsPtr++ = 'n';
756*cfb92d14SAndroid Build Coastguard Worker }
757*cfb92d14SAndroid Build Coastguard Worker
758*cfb92d14SAndroid Build Coastguard Worker if (flagsPtr == &aStringBuffer[0])
759*cfb92d14SAndroid Build Coastguard Worker {
760*cfb92d14SAndroid Build Coastguard Worker *flagsPtr++ = '-';
761*cfb92d14SAndroid Build Coastguard Worker }
762*cfb92d14SAndroid Build Coastguard Worker
763*cfb92d14SAndroid Build Coastguard Worker *flagsPtr = '\0';
764*cfb92d14SAndroid Build Coastguard Worker
765*cfb92d14SAndroid Build Coastguard Worker return aStringBuffer;
766*cfb92d14SAndroid Build Coastguard Worker }
767*cfb92d14SAndroid Build Coastguard Worker
AddressOriginToString(uint8_t aOrigin)768*cfb92d14SAndroid Build Coastguard Worker const char *Utils::AddressOriginToString(uint8_t aOrigin)
769*cfb92d14SAndroid Build Coastguard Worker {
770*cfb92d14SAndroid Build Coastguard Worker static const char *const kOriginStrings[4] = {
771*cfb92d14SAndroid Build Coastguard Worker "thread", // 0, OT_ADDRESS_ORIGIN_THREAD
772*cfb92d14SAndroid Build Coastguard Worker "slaac", // 1, OT_ADDRESS_ORIGIN_SLAAC
773*cfb92d14SAndroid Build Coastguard Worker "dhcp6", // 2, OT_ADDRESS_ORIGIN_DHCPV6
774*cfb92d14SAndroid Build Coastguard Worker "manual", // 3, OT_ADDRESS_ORIGIN_MANUAL
775*cfb92d14SAndroid Build Coastguard Worker };
776*cfb92d14SAndroid Build Coastguard Worker
777*cfb92d14SAndroid Build Coastguard Worker static_assert(0 == OT_ADDRESS_ORIGIN_THREAD, "OT_ADDRESS_ORIGIN_THREAD value is incorrect");
778*cfb92d14SAndroid Build Coastguard Worker static_assert(1 == OT_ADDRESS_ORIGIN_SLAAC, "OT_ADDRESS_ORIGIN_SLAAC value is incorrect");
779*cfb92d14SAndroid Build Coastguard Worker static_assert(2 == OT_ADDRESS_ORIGIN_DHCPV6, "OT_ADDRESS_ORIGIN_DHCPV6 value is incorrect");
780*cfb92d14SAndroid Build Coastguard Worker static_assert(3 == OT_ADDRESS_ORIGIN_MANUAL, "OT_ADDRESS_ORIGIN_MANUAL value is incorrect");
781*cfb92d14SAndroid Build Coastguard Worker
782*cfb92d14SAndroid Build Coastguard Worker return Stringify(aOrigin, kOriginStrings);
783*cfb92d14SAndroid Build Coastguard Worker }
784*cfb92d14SAndroid Build Coastguard Worker
785*cfb92d14SAndroid Build Coastguard Worker } // namespace Cli
786*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
787