1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2023, 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 implements the CLI interpreter for Link Metrics function.
32*cfb92d14SAndroid Build Coastguard Worker */
33*cfb92d14SAndroid Build Coastguard Worker
34*cfb92d14SAndroid Build Coastguard Worker #include "cli_link_metrics.hpp"
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard Worker #include <openthread/link_metrics.h>
37*cfb92d14SAndroid Build Coastguard Worker
38*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli.hpp"
39*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli_utils.hpp"
40*cfb92d14SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
41*cfb92d14SAndroid Build Coastguard Worker
42*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
43*cfb92d14SAndroid Build Coastguard Worker
44*cfb92d14SAndroid Build Coastguard Worker namespace ot {
45*cfb92d14SAndroid Build Coastguard Worker namespace Cli {
46*cfb92d14SAndroid Build Coastguard Worker
LinkMetrics(otInstance * aInstance,OutputImplementer & aOutputImplementer)47*cfb92d14SAndroid Build Coastguard Worker LinkMetrics::LinkMetrics(otInstance *aInstance, OutputImplementer &aOutputImplementer)
48*cfb92d14SAndroid Build Coastguard Worker : Utils(aInstance, aOutputImplementer)
49*cfb92d14SAndroid Build Coastguard Worker , mQuerySync(false)
50*cfb92d14SAndroid Build Coastguard Worker , mConfigForwardTrackingSeriesSync(false)
51*cfb92d14SAndroid Build Coastguard Worker , mConfigEnhAckProbingSync(false)
52*cfb92d14SAndroid Build Coastguard Worker {
53*cfb92d14SAndroid Build Coastguard Worker }
54*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])55*cfb92d14SAndroid Build Coastguard Worker template <> otError LinkMetrics::Process<Cmd("query")>(Arg aArgs[])
56*cfb92d14SAndroid Build Coastguard Worker {
57*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aArgs);
58*cfb92d14SAndroid Build Coastguard Worker OutputLine("The command \"linkmetrics query\" has been replaced by the command \"linkmetrics request\".");
59*cfb92d14SAndroid Build Coastguard Worker return OT_ERROR_INVALID_COMMAND;
60*cfb92d14SAndroid Build Coastguard Worker }
61*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])62*cfb92d14SAndroid Build Coastguard Worker template <> otError LinkMetrics::Process<Cmd("request")>(Arg aArgs[])
63*cfb92d14SAndroid Build Coastguard Worker {
64*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
65*cfb92d14SAndroid Build Coastguard Worker otIp6Address address;
66*cfb92d14SAndroid Build Coastguard Worker bool sync = true;
67*cfb92d14SAndroid Build Coastguard Worker bool isSingle;
68*cfb92d14SAndroid Build Coastguard Worker uint8_t seriesId;
69*cfb92d14SAndroid Build Coastguard Worker otLinkMetrics linkMetrics;
70*cfb92d14SAndroid Build Coastguard Worker
71*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0] == "async")
72*cfb92d14SAndroid Build Coastguard Worker {
73*cfb92d14SAndroid Build Coastguard Worker sync = false;
74*cfb92d14SAndroid Build Coastguard Worker aArgs++;
75*cfb92d14SAndroid Build Coastguard Worker }
76*cfb92d14SAndroid Build Coastguard Worker
77*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address));
78*cfb92d14SAndroid Build Coastguard Worker
79*cfb92d14SAndroid Build Coastguard Worker /**
80*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics request single
81*cfb92d14SAndroid Build Coastguard Worker * @code
82*cfb92d14SAndroid Build Coastguard Worker * linkmetrics request fe80:0:0:0:3092:f334:1455:1ad2 single qmr
83*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2
84*cfb92d14SAndroid Build Coastguard Worker * - LQI: 76 (Exponential Moving Average)
85*cfb92d14SAndroid Build Coastguard Worker * - Margin: 82 (dB) (Exponential Moving Average)
86*cfb92d14SAndroid Build Coastguard Worker * - RSSI: -18 (dBm) (Exponential Moving Average)
87*cfb92d14SAndroid Build Coastguard Worker * Done
88*cfb92d14SAndroid Build Coastguard Worker * @endcode
89*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics request [@ca{async}] @ca{peer-ipaddr} single [@ca{pqmr}]
90*cfb92d14SAndroid Build Coastguard Worker * - `async`: Use the non-blocking mode.
91*cfb92d14SAndroid Build Coastguard Worker * - `peer-ipaddr`: Peer address.
92*cfb92d14SAndroid Build Coastguard Worker * - [`p`, `q`, `m`, and `r`] map to #otLinkMetrics.
93*cfb92d14SAndroid Build Coastguard Worker * - `p`: Layer 2 Number of PDUs received.
94*cfb92d14SAndroid Build Coastguard Worker * - `q`: Layer 2 LQI.
95*cfb92d14SAndroid Build Coastguard Worker * - `m`: Link Margin.
96*cfb92d14SAndroid Build Coastguard Worker * - `r`: RSSI.
97*cfb92d14SAndroid Build Coastguard Worker * @par
98*cfb92d14SAndroid Build Coastguard Worker * Perform a Link Metrics query (Single Probe).
99*cfb92d14SAndroid Build Coastguard Worker * @sa otLinkMetricsQuery
100*cfb92d14SAndroid Build Coastguard Worker */
101*cfb92d14SAndroid Build Coastguard Worker if (aArgs[1] == "single")
102*cfb92d14SAndroid Build Coastguard Worker {
103*cfb92d14SAndroid Build Coastguard Worker isSingle = true;
104*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[2]));
105*cfb92d14SAndroid Build Coastguard Worker }
106*cfb92d14SAndroid Build Coastguard Worker /**
107*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics request forward
108*cfb92d14SAndroid Build Coastguard Worker * @code
109*cfb92d14SAndroid Build Coastguard Worker * linkmetrics request fe80:0:0:0:3092:f334:1455:1ad2 forward 1
110*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2
111*cfb92d14SAndroid Build Coastguard Worker * - PDU Counter: 2 (Count/Summation)
112*cfb92d14SAndroid Build Coastguard Worker * - LQI: 76 (Exponential Moving Average)
113*cfb92d14SAndroid Build Coastguard Worker * - Margin: 82 (dB) (Exponential Moving Average)
114*cfb92d14SAndroid Build Coastguard Worker * - RSSI: -18 (dBm) (Exponential Moving Average)
115*cfb92d14SAndroid Build Coastguard Worker * Done
116*cfb92d14SAndroid Build Coastguard Worker * @endcode
117*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics query [@ca{async}] @ca{peer-ipaddr} forward @ca{series-id}
118*cfb92d14SAndroid Build Coastguard Worker * - `async`: Use the non-blocking mode.
119*cfb92d14SAndroid Build Coastguard Worker * - `peer-ipaddr`: Peer address.
120*cfb92d14SAndroid Build Coastguard Worker * - `series-id`: The Series ID.
121*cfb92d14SAndroid Build Coastguard Worker * @par
122*cfb92d14SAndroid Build Coastguard Worker * Perform a Link Metrics query (Forward Tracking Series).
123*cfb92d14SAndroid Build Coastguard Worker * @sa otLinkMetricsQuery
124*cfb92d14SAndroid Build Coastguard Worker */
125*cfb92d14SAndroid Build Coastguard Worker else if (aArgs[1] == "forward")
126*cfb92d14SAndroid Build Coastguard Worker {
127*cfb92d14SAndroid Build Coastguard Worker isSingle = false;
128*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId));
129*cfb92d14SAndroid Build Coastguard Worker }
130*cfb92d14SAndroid Build Coastguard Worker else
131*cfb92d14SAndroid Build Coastguard Worker {
132*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
133*cfb92d14SAndroid Build Coastguard Worker }
134*cfb92d14SAndroid Build Coastguard Worker
135*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = otLinkMetricsQuery(GetInstancePtr(), &address, isSingle ? 0 : seriesId,
136*cfb92d14SAndroid Build Coastguard Worker isSingle ? &linkMetrics : nullptr, HandleLinkMetricsReport, this));
137*cfb92d14SAndroid Build Coastguard Worker
138*cfb92d14SAndroid Build Coastguard Worker if (sync)
139*cfb92d14SAndroid Build Coastguard Worker {
140*cfb92d14SAndroid Build Coastguard Worker mQuerySync = true;
141*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_PENDING;
142*cfb92d14SAndroid Build Coastguard Worker }
143*cfb92d14SAndroid Build Coastguard Worker
144*cfb92d14SAndroid Build Coastguard Worker exit:
145*cfb92d14SAndroid Build Coastguard Worker return error;
146*cfb92d14SAndroid Build Coastguard Worker }
147*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])148*cfb92d14SAndroid Build Coastguard Worker template <> otError LinkMetrics::Process<Cmd("mgmt")>(Arg aArgs[])
149*cfb92d14SAndroid Build Coastguard Worker {
150*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aArgs);
151*cfb92d14SAndroid Build Coastguard Worker OutputLine("The command \"linkmetrics mgmt\" has been replaced by the command \"linkmetrics config\".");
152*cfb92d14SAndroid Build Coastguard Worker return OT_ERROR_INVALID_COMMAND;
153*cfb92d14SAndroid Build Coastguard Worker }
154*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])155*cfb92d14SAndroid Build Coastguard Worker template <> otError LinkMetrics::Process<Cmd("config")>(Arg aArgs[])
156*cfb92d14SAndroid Build Coastguard Worker {
157*cfb92d14SAndroid Build Coastguard Worker otError error;
158*cfb92d14SAndroid Build Coastguard Worker otIp6Address address;
159*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsSeriesFlags seriesFlags;
160*cfb92d14SAndroid Build Coastguard Worker bool sync = true;
161*cfb92d14SAndroid Build Coastguard Worker bool clear = false;
162*cfb92d14SAndroid Build Coastguard Worker
163*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0] == "async")
164*cfb92d14SAndroid Build Coastguard Worker {
165*cfb92d14SAndroid Build Coastguard Worker sync = false;
166*cfb92d14SAndroid Build Coastguard Worker aArgs++;
167*cfb92d14SAndroid Build Coastguard Worker }
168*cfb92d14SAndroid Build Coastguard Worker
169*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address));
170*cfb92d14SAndroid Build Coastguard Worker
171*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(seriesFlags);
172*cfb92d14SAndroid Build Coastguard Worker
173*cfb92d14SAndroid Build Coastguard Worker /**
174*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics config forward
175*cfb92d14SAndroid Build Coastguard Worker * @code
176*cfb92d14SAndroid Build Coastguard Worker * linkmetrics config fe80:0:0:0:3092:f334:1455:1ad2 forward 1 dra pqmr
177*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
178*cfb92d14SAndroid Build Coastguard Worker * Status: SUCCESS
179*cfb92d14SAndroid Build Coastguard Worker * Done
180*cfb92d14SAndroid Build Coastguard Worker * @endcode
181*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics config [@ca{async}] @ca{peer-ipaddr} forward @ca{series-id} [@ca{ldraX}][@ca{pqmr}]
182*cfb92d14SAndroid Build Coastguard Worker * - `async`: Use the non-blocking mode.
183*cfb92d14SAndroid Build Coastguard Worker * - `peer-ipaddr`: Peer address.
184*cfb92d14SAndroid Build Coastguard Worker * - `series-id`: The Series ID.
185*cfb92d14SAndroid Build Coastguard Worker * - [`l`, `d`, `r`, and `a`] map to #otLinkMetricsSeriesFlags. `X` represents none of the
186*cfb92d14SAndroid Build Coastguard Worker * `otLinkMetricsSeriesFlags`, and stops the accounting and removes the series.
187*cfb92d14SAndroid Build Coastguard Worker * - `l`: MLE Link Probe.
188*cfb92d14SAndroid Build Coastguard Worker * - `d`: MAC Data.
189*cfb92d14SAndroid Build Coastguard Worker * - `r`: MAC Data Request.
190*cfb92d14SAndroid Build Coastguard Worker * - `a`: MAC Ack.
191*cfb92d14SAndroid Build Coastguard Worker * - `X`: Can only be used without any other flags.
192*cfb92d14SAndroid Build Coastguard Worker * - [`p`, `q`, `m`, and `r`] map to #otLinkMetricsValues.
193*cfb92d14SAndroid Build Coastguard Worker * - `p`: Layer 2 Number of PDUs received.
194*cfb92d14SAndroid Build Coastguard Worker * - `q`: Layer 2 LQI.
195*cfb92d14SAndroid Build Coastguard Worker * - `m`: Link Margin.
196*cfb92d14SAndroid Build Coastguard Worker * - `r`: RSSI.
197*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
198*cfb92d14SAndroid Build Coastguard Worker * #otLinkMetricsConfigForwardTrackingSeries
199*cfb92d14SAndroid Build Coastguard Worker */
200*cfb92d14SAndroid Build Coastguard Worker if (aArgs[1] == "forward")
201*cfb92d14SAndroid Build Coastguard Worker {
202*cfb92d14SAndroid Build Coastguard Worker uint8_t seriesId;
203*cfb92d14SAndroid Build Coastguard Worker otLinkMetrics linkMetrics;
204*cfb92d14SAndroid Build Coastguard Worker
205*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(linkMetrics);
206*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId));
207*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
208*cfb92d14SAndroid Build Coastguard Worker
209*cfb92d14SAndroid Build Coastguard Worker for (const char *arg = aArgs[3].GetCString(); *arg != '\0'; arg++)
210*cfb92d14SAndroid Build Coastguard Worker {
211*cfb92d14SAndroid Build Coastguard Worker switch (*arg)
212*cfb92d14SAndroid Build Coastguard Worker {
213*cfb92d14SAndroid Build Coastguard Worker case 'l':
214*cfb92d14SAndroid Build Coastguard Worker seriesFlags.mLinkProbe = true;
215*cfb92d14SAndroid Build Coastguard Worker break;
216*cfb92d14SAndroid Build Coastguard Worker
217*cfb92d14SAndroid Build Coastguard Worker case 'd':
218*cfb92d14SAndroid Build Coastguard Worker seriesFlags.mMacData = true;
219*cfb92d14SAndroid Build Coastguard Worker break;
220*cfb92d14SAndroid Build Coastguard Worker
221*cfb92d14SAndroid Build Coastguard Worker case 'r':
222*cfb92d14SAndroid Build Coastguard Worker seriesFlags.mMacDataRequest = true;
223*cfb92d14SAndroid Build Coastguard Worker break;
224*cfb92d14SAndroid Build Coastguard Worker
225*cfb92d14SAndroid Build Coastguard Worker case 'a':
226*cfb92d14SAndroid Build Coastguard Worker seriesFlags.mMacAck = true;
227*cfb92d14SAndroid Build Coastguard Worker break;
228*cfb92d14SAndroid Build Coastguard Worker
229*cfb92d14SAndroid Build Coastguard Worker case 'X':
230*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(arg == aArgs[3].GetCString() && *(arg + 1) == '\0' && aArgs[4].IsEmpty(),
231*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_ARGS); // Ensure the flags only contain 'X'
232*cfb92d14SAndroid Build Coastguard Worker clear = true;
233*cfb92d14SAndroid Build Coastguard Worker break;
234*cfb92d14SAndroid Build Coastguard Worker
235*cfb92d14SAndroid Build Coastguard Worker default:
236*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
237*cfb92d14SAndroid Build Coastguard Worker }
238*cfb92d14SAndroid Build Coastguard Worker }
239*cfb92d14SAndroid Build Coastguard Worker
240*cfb92d14SAndroid Build Coastguard Worker if (!clear)
241*cfb92d14SAndroid Build Coastguard Worker {
242*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[4]));
243*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(aArgs[5].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
244*cfb92d14SAndroid Build Coastguard Worker }
245*cfb92d14SAndroid Build Coastguard Worker
246*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = otLinkMetricsConfigForwardTrackingSeries(
247*cfb92d14SAndroid Build Coastguard Worker GetInstancePtr(), &address, seriesId, seriesFlags, clear ? nullptr : &linkMetrics,
248*cfb92d14SAndroid Build Coastguard Worker &LinkMetrics::HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse, this));
249*cfb92d14SAndroid Build Coastguard Worker
250*cfb92d14SAndroid Build Coastguard Worker if (sync)
251*cfb92d14SAndroid Build Coastguard Worker {
252*cfb92d14SAndroid Build Coastguard Worker mConfigForwardTrackingSeriesSync = true;
253*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_PENDING;
254*cfb92d14SAndroid Build Coastguard Worker }
255*cfb92d14SAndroid Build Coastguard Worker }
256*cfb92d14SAndroid Build Coastguard Worker else if (aArgs[1] == "enhanced-ack")
257*cfb92d14SAndroid Build Coastguard Worker {
258*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsEnhAckFlags enhAckFlags;
259*cfb92d14SAndroid Build Coastguard Worker otLinkMetrics linkMetrics;
260*cfb92d14SAndroid Build Coastguard Worker otLinkMetrics *pLinkMetrics = &linkMetrics;
261*cfb92d14SAndroid Build Coastguard Worker
262*cfb92d14SAndroid Build Coastguard Worker /**
263*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics config enhanced-ack clear
264*cfb92d14SAndroid Build Coastguard Worker * @code
265*cfb92d14SAndroid Build Coastguard Worker * linkmetrics config fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack clear
266*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
267*cfb92d14SAndroid Build Coastguard Worker * Status: Success
268*cfb92d14SAndroid Build Coastguard Worker * Done
269*cfb92d14SAndroid Build Coastguard Worker * @endcode
270*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics config [@ca{async}] @ca{peer-ipaddr} enhanced-ack clear
271*cfb92d14SAndroid Build Coastguard Worker * - `async`: Use the non-blocking mode.
272*cfb92d14SAndroid Build Coastguard Worker * - `peer-ipaddr` should be the Link Local address of the neighboring device.
273*cfb92d14SAndroid Build Coastguard Worker * @par
274*cfb92d14SAndroid Build Coastguard Worker * Sends a Link Metrics Management Request to clear an Enhanced-ACK Based Probing.
275*cfb92d14SAndroid Build Coastguard Worker * @sa otLinkMetricsConfigEnhAckProbing
276*cfb92d14SAndroid Build Coastguard Worker */
277*cfb92d14SAndroid Build Coastguard Worker if (aArgs[2] == "clear")
278*cfb92d14SAndroid Build Coastguard Worker {
279*cfb92d14SAndroid Build Coastguard Worker enhAckFlags = OT_LINK_METRICS_ENH_ACK_CLEAR;
280*cfb92d14SAndroid Build Coastguard Worker pLinkMetrics = nullptr;
281*cfb92d14SAndroid Build Coastguard Worker }
282*cfb92d14SAndroid Build Coastguard Worker /**
283*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics config enhanced-ack register
284*cfb92d14SAndroid Build Coastguard Worker * @code
285*cfb92d14SAndroid Build Coastguard Worker * linkmetrics config fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm
286*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
287*cfb92d14SAndroid Build Coastguard Worker * Status: Success
288*cfb92d14SAndroid Build Coastguard Worker * Done
289*cfb92d14SAndroid Build Coastguard Worker * @endcode
290*cfb92d14SAndroid Build Coastguard Worker * @code
291*cfb92d14SAndroid Build Coastguard Worker * > linkmetrics config fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm r
292*cfb92d14SAndroid Build Coastguard Worker * Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
293*cfb92d14SAndroid Build Coastguard Worker * Status: Cannot support new series
294*cfb92d14SAndroid Build Coastguard Worker * Done
295*cfb92d14SAndroid Build Coastguard Worker * @endcode
296*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics config [@ca{async}] @ca{peer-ipaddr} enhanced-ack register [@ca{qmr}][@ca{r}]
297*cfb92d14SAndroid Build Coastguard Worker * - `async`: Use the non-blocking mode.
298*cfb92d14SAndroid Build Coastguard Worker * - [`q`, `m`, and `r`] map to #otLinkMetricsValues. Per spec 4.11.3.4.4.6, you can
299*cfb92d14SAndroid Build Coastguard Worker * only use a maximum of two options at once, for example `q`, or `qm`.
300*cfb92d14SAndroid Build Coastguard Worker * - `q`: Layer 2 LQI.
301*cfb92d14SAndroid Build Coastguard Worker * - `m`: Link Margin.
302*cfb92d14SAndroid Build Coastguard Worker * - `r`: RSSI.
303*cfb92d14SAndroid Build Coastguard Worker * @par
304*cfb92d14SAndroid Build Coastguard Worker * The additional `r` is optional and only used for reference devices. When this option
305*cfb92d14SAndroid Build Coastguard Worker * is specified, Type/Average Enum of each Type Id Flags is set to reserved. This is
306*cfb92d14SAndroid Build Coastguard Worker * used to verify that the Probing Subject correctly handles invalid Type Id Flags, and
307*cfb92d14SAndroid Build Coastguard Worker * only available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
308*cfb92d14SAndroid Build Coastguard Worker * @par
309*cfb92d14SAndroid Build Coastguard Worker * Sends a Link Metrics Management Request to register an Enhanced-ACK Based Probing.
310*cfb92d14SAndroid Build Coastguard Worker * @sa otLinkMetricsConfigEnhAckProbing
311*cfb92d14SAndroid Build Coastguard Worker */
312*cfb92d14SAndroid Build Coastguard Worker else if (aArgs[2] == "register")
313*cfb92d14SAndroid Build Coastguard Worker {
314*cfb92d14SAndroid Build Coastguard Worker enhAckFlags = OT_LINK_METRICS_ENH_ACK_REGISTER;
315*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[3]));
316*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
317*cfb92d14SAndroid Build Coastguard Worker if (aArgs[4] == "r")
318*cfb92d14SAndroid Build Coastguard Worker {
319*cfb92d14SAndroid Build Coastguard Worker linkMetrics.mReserved = true;
320*cfb92d14SAndroid Build Coastguard Worker }
321*cfb92d14SAndroid Build Coastguard Worker #endif
322*cfb92d14SAndroid Build Coastguard Worker }
323*cfb92d14SAndroid Build Coastguard Worker else
324*cfb92d14SAndroid Build Coastguard Worker {
325*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
326*cfb92d14SAndroid Build Coastguard Worker }
327*cfb92d14SAndroid Build Coastguard Worker
328*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(
329*cfb92d14SAndroid Build Coastguard Worker error = otLinkMetricsConfigEnhAckProbing(GetInstancePtr(), &address, enhAckFlags, pLinkMetrics,
330*cfb92d14SAndroid Build Coastguard Worker &LinkMetrics::HandleLinkMetricsConfigEnhAckProbingMgmtResponse,
331*cfb92d14SAndroid Build Coastguard Worker this, &LinkMetrics::HandleLinkMetricsEnhAckProbingIe, this));
332*cfb92d14SAndroid Build Coastguard Worker
333*cfb92d14SAndroid Build Coastguard Worker if (sync)
334*cfb92d14SAndroid Build Coastguard Worker {
335*cfb92d14SAndroid Build Coastguard Worker mConfigEnhAckProbingSync = true;
336*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_PENDING;
337*cfb92d14SAndroid Build Coastguard Worker }
338*cfb92d14SAndroid Build Coastguard Worker }
339*cfb92d14SAndroid Build Coastguard Worker else
340*cfb92d14SAndroid Build Coastguard Worker {
341*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_INVALID_ARGS;
342*cfb92d14SAndroid Build Coastguard Worker }
343*cfb92d14SAndroid Build Coastguard Worker
344*cfb92d14SAndroid Build Coastguard Worker exit:
345*cfb92d14SAndroid Build Coastguard Worker return error;
346*cfb92d14SAndroid Build Coastguard Worker }
347*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])348*cfb92d14SAndroid Build Coastguard Worker template <> otError LinkMetrics::Process<Cmd("probe")>(Arg aArgs[])
349*cfb92d14SAndroid Build Coastguard Worker {
350*cfb92d14SAndroid Build Coastguard Worker /**
351*cfb92d14SAndroid Build Coastguard Worker * @cli linkmetrics probe
352*cfb92d14SAndroid Build Coastguard Worker * @code
353*cfb92d14SAndroid Build Coastguard Worker * linkmetrics probe fe80:0:0:0:3092:f334:1455:1ad2 1 10
354*cfb92d14SAndroid Build Coastguard Worker * Done
355*cfb92d14SAndroid Build Coastguard Worker * @endcode
356*cfb92d14SAndroid Build Coastguard Worker * @cparam linkmetrics probe @ca{peer-ipaddr} @ca{series-id} @ca{length}
357*cfb92d14SAndroid Build Coastguard Worker * - `peer-ipaddr`: Peer address.
358*cfb92d14SAndroid Build Coastguard Worker * - `series-id`: The Series ID for which this Probe message targets.
359*cfb92d14SAndroid Build Coastguard Worker * - `length`: The length of the Probe message. A valid range is [0, 64].
360*cfb92d14SAndroid Build Coastguard Worker * @par api_copy
361*cfb92d14SAndroid Build Coastguard Worker * #otLinkMetricsSendLinkProbe
362*cfb92d14SAndroid Build Coastguard Worker */
363*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
364*cfb92d14SAndroid Build Coastguard Worker
365*cfb92d14SAndroid Build Coastguard Worker otIp6Address address;
366*cfb92d14SAndroid Build Coastguard Worker uint8_t seriesId;
367*cfb92d14SAndroid Build Coastguard Worker uint8_t length;
368*cfb92d14SAndroid Build Coastguard Worker
369*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address));
370*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[1].ParseAsUint8(seriesId));
371*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = aArgs[2].ParseAsUint8(length));
372*cfb92d14SAndroid Build Coastguard Worker
373*cfb92d14SAndroid Build Coastguard Worker error = otLinkMetricsSendLinkProbe(GetInstancePtr(), &address, seriesId, length);
374*cfb92d14SAndroid Build Coastguard Worker exit:
375*cfb92d14SAndroid Build Coastguard Worker return error;
376*cfb92d14SAndroid Build Coastguard Worker }
377*cfb92d14SAndroid Build Coastguard Worker
Process(Arg aArgs[])378*cfb92d14SAndroid Build Coastguard Worker otError LinkMetrics::Process(Arg aArgs[])
379*cfb92d14SAndroid Build Coastguard Worker {
380*cfb92d14SAndroid Build Coastguard Worker #define CmdEntry(aCommandString) \
381*cfb92d14SAndroid Build Coastguard Worker { \
382*cfb92d14SAndroid Build Coastguard Worker aCommandString, &LinkMetrics::Process<Cmd(aCommandString)> \
383*cfb92d14SAndroid Build Coastguard Worker }
384*cfb92d14SAndroid Build Coastguard Worker
385*cfb92d14SAndroid Build Coastguard Worker static constexpr Command kCommands[] = {
386*cfb92d14SAndroid Build Coastguard Worker CmdEntry("config"), CmdEntry("mgmt"), CmdEntry("probe"), CmdEntry("query"), CmdEntry("request"),
387*cfb92d14SAndroid Build Coastguard Worker };
388*cfb92d14SAndroid Build Coastguard Worker
389*cfb92d14SAndroid Build Coastguard Worker static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
390*cfb92d14SAndroid Build Coastguard Worker
391*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_INVALID_COMMAND;
392*cfb92d14SAndroid Build Coastguard Worker const Command *command;
393*cfb92d14SAndroid Build Coastguard Worker
394*cfb92d14SAndroid Build Coastguard Worker if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
395*cfb92d14SAndroid Build Coastguard Worker {
396*cfb92d14SAndroid Build Coastguard Worker OutputCommandTable(kCommands);
397*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
398*cfb92d14SAndroid Build Coastguard Worker }
399*cfb92d14SAndroid Build Coastguard Worker
400*cfb92d14SAndroid Build Coastguard Worker command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
401*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(command != nullptr);
402*cfb92d14SAndroid Build Coastguard Worker
403*cfb92d14SAndroid Build Coastguard Worker error = (this->*command->mHandler)(aArgs + 1);
404*cfb92d14SAndroid Build Coastguard Worker
405*cfb92d14SAndroid Build Coastguard Worker exit:
406*cfb92d14SAndroid Build Coastguard Worker return error;
407*cfb92d14SAndroid Build Coastguard Worker }
408*cfb92d14SAndroid Build Coastguard Worker
ParseLinkMetricsFlags(otLinkMetrics & aLinkMetrics,const Arg & aFlags)409*cfb92d14SAndroid Build Coastguard Worker otError LinkMetrics::ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags)
410*cfb92d14SAndroid Build Coastguard Worker {
411*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
412*cfb92d14SAndroid Build Coastguard Worker
413*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!aFlags.IsEmpty(), error = OT_ERROR_INVALID_ARGS);
414*cfb92d14SAndroid Build Coastguard Worker
415*cfb92d14SAndroid Build Coastguard Worker ClearAllBytes(aLinkMetrics);
416*cfb92d14SAndroid Build Coastguard Worker
417*cfb92d14SAndroid Build Coastguard Worker for (const char *arg = aFlags.GetCString(); *arg != '\0'; arg++)
418*cfb92d14SAndroid Build Coastguard Worker {
419*cfb92d14SAndroid Build Coastguard Worker switch (*arg)
420*cfb92d14SAndroid Build Coastguard Worker {
421*cfb92d14SAndroid Build Coastguard Worker case 'p':
422*cfb92d14SAndroid Build Coastguard Worker aLinkMetrics.mPduCount = true;
423*cfb92d14SAndroid Build Coastguard Worker break;
424*cfb92d14SAndroid Build Coastguard Worker
425*cfb92d14SAndroid Build Coastguard Worker case 'q':
426*cfb92d14SAndroid Build Coastguard Worker aLinkMetrics.mLqi = true;
427*cfb92d14SAndroid Build Coastguard Worker break;
428*cfb92d14SAndroid Build Coastguard Worker
429*cfb92d14SAndroid Build Coastguard Worker case 'm':
430*cfb92d14SAndroid Build Coastguard Worker aLinkMetrics.mLinkMargin = true;
431*cfb92d14SAndroid Build Coastguard Worker break;
432*cfb92d14SAndroid Build Coastguard Worker
433*cfb92d14SAndroid Build Coastguard Worker case 'r':
434*cfb92d14SAndroid Build Coastguard Worker aLinkMetrics.mRssi = true;
435*cfb92d14SAndroid Build Coastguard Worker break;
436*cfb92d14SAndroid Build Coastguard Worker
437*cfb92d14SAndroid Build Coastguard Worker default:
438*cfb92d14SAndroid Build Coastguard Worker ExitNow(error = OT_ERROR_INVALID_ARGS);
439*cfb92d14SAndroid Build Coastguard Worker }
440*cfb92d14SAndroid Build Coastguard Worker }
441*cfb92d14SAndroid Build Coastguard Worker
442*cfb92d14SAndroid Build Coastguard Worker exit:
443*cfb92d14SAndroid Build Coastguard Worker return error;
444*cfb92d14SAndroid Build Coastguard Worker }
445*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsReport(const otIp6Address * aAddress,const otLinkMetricsValues * aMetricsValues,otLinkMetricsStatus aStatus,void * aContext)446*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsReport(const otIp6Address *aAddress,
447*cfb92d14SAndroid Build Coastguard Worker const otLinkMetricsValues *aMetricsValues,
448*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus,
449*cfb92d14SAndroid Build Coastguard Worker void *aContext)
450*cfb92d14SAndroid Build Coastguard Worker {
451*cfb92d14SAndroid Build Coastguard Worker static_cast<LinkMetrics *>(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues, aStatus);
452*cfb92d14SAndroid Build Coastguard Worker }
453*cfb92d14SAndroid Build Coastguard Worker
PrintLinkMetricsValue(const otLinkMetricsValues * aMetricsValues)454*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues)
455*cfb92d14SAndroid Build Coastguard Worker {
456*cfb92d14SAndroid Build Coastguard Worker static const char kLinkMetricsTypeAverage[] = "(Exponential Moving Average)";
457*cfb92d14SAndroid Build Coastguard Worker
458*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues->mMetrics.mPduCount)
459*cfb92d14SAndroid Build Coastguard Worker {
460*cfb92d14SAndroid Build Coastguard Worker OutputLine(" - PDU Counter: %lu (Count/Summation)", ToUlong(aMetricsValues->mPduCountValue));
461*cfb92d14SAndroid Build Coastguard Worker }
462*cfb92d14SAndroid Build Coastguard Worker
463*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues->mMetrics.mLqi)
464*cfb92d14SAndroid Build Coastguard Worker {
465*cfb92d14SAndroid Build Coastguard Worker OutputLine(" - LQI: %u %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage);
466*cfb92d14SAndroid Build Coastguard Worker }
467*cfb92d14SAndroid Build Coastguard Worker
468*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues->mMetrics.mLinkMargin)
469*cfb92d14SAndroid Build Coastguard Worker {
470*cfb92d14SAndroid Build Coastguard Worker OutputLine(" - Margin: %u (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage);
471*cfb92d14SAndroid Build Coastguard Worker }
472*cfb92d14SAndroid Build Coastguard Worker
473*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues->mMetrics.mRssi)
474*cfb92d14SAndroid Build Coastguard Worker {
475*cfb92d14SAndroid Build Coastguard Worker OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage);
476*cfb92d14SAndroid Build Coastguard Worker }
477*cfb92d14SAndroid Build Coastguard Worker }
478*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsReport(const otIp6Address * aAddress,const otLinkMetricsValues * aMetricsValues,otLinkMetricsStatus aStatus)479*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsReport(const otIp6Address *aAddress,
480*cfb92d14SAndroid Build Coastguard Worker const otLinkMetricsValues *aMetricsValues,
481*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus)
482*cfb92d14SAndroid Build Coastguard Worker {
483*cfb92d14SAndroid Build Coastguard Worker OutputFormat("Received Link Metrics Report from: ");
484*cfb92d14SAndroid Build Coastguard Worker OutputIp6AddressLine(*aAddress);
485*cfb92d14SAndroid Build Coastguard Worker
486*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues != nullptr)
487*cfb92d14SAndroid Build Coastguard Worker {
488*cfb92d14SAndroid Build Coastguard Worker PrintLinkMetricsValue(aMetricsValues);
489*cfb92d14SAndroid Build Coastguard Worker }
490*cfb92d14SAndroid Build Coastguard Worker else
491*cfb92d14SAndroid Build Coastguard Worker {
492*cfb92d14SAndroid Build Coastguard Worker OutputLine("Link Metrics Report, status: %s", LinkMetricsStatusToStr(aStatus));
493*cfb92d14SAndroid Build Coastguard Worker }
494*cfb92d14SAndroid Build Coastguard Worker
495*cfb92d14SAndroid Build Coastguard Worker if (mQuerySync)
496*cfb92d14SAndroid Build Coastguard Worker {
497*cfb92d14SAndroid Build Coastguard Worker mQuerySync = false;
498*cfb92d14SAndroid Build Coastguard Worker OutputResult(OT_ERROR_NONE);
499*cfb92d14SAndroid Build Coastguard Worker }
500*cfb92d14SAndroid Build Coastguard Worker }
501*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse(const otIp6Address * aAddress,otLinkMetricsStatus aStatus,void * aContext)502*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse(const otIp6Address *aAddress,
503*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus,
504*cfb92d14SAndroid Build Coastguard Worker void *aContext)
505*cfb92d14SAndroid Build Coastguard Worker {
506*cfb92d14SAndroid Build Coastguard Worker static_cast<LinkMetrics *>(aContext)->HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse(aAddress, aStatus);
507*cfb92d14SAndroid Build Coastguard Worker }
508*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse(const otIp6Address * aAddress,otLinkMetricsStatus aStatus)509*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsConfigForwardTrackingSeriesMgmtResponse(const otIp6Address *aAddress,
510*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus)
511*cfb92d14SAndroid Build Coastguard Worker {
512*cfb92d14SAndroid Build Coastguard Worker HandleLinkMetricsMgmtResponse(aAddress, aStatus);
513*cfb92d14SAndroid Build Coastguard Worker
514*cfb92d14SAndroid Build Coastguard Worker if (mConfigForwardTrackingSeriesSync)
515*cfb92d14SAndroid Build Coastguard Worker {
516*cfb92d14SAndroid Build Coastguard Worker mConfigForwardTrackingSeriesSync = false;
517*cfb92d14SAndroid Build Coastguard Worker OutputResult(OT_ERROR_NONE);
518*cfb92d14SAndroid Build Coastguard Worker }
519*cfb92d14SAndroid Build Coastguard Worker }
520*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsConfigEnhAckProbingMgmtResponse(const otIp6Address * aAddress,otLinkMetricsStatus aStatus,void * aContext)521*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsConfigEnhAckProbingMgmtResponse(const otIp6Address *aAddress,
522*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus,
523*cfb92d14SAndroid Build Coastguard Worker void *aContext)
524*cfb92d14SAndroid Build Coastguard Worker {
525*cfb92d14SAndroid Build Coastguard Worker static_cast<LinkMetrics *>(aContext)->HandleLinkMetricsConfigEnhAckProbingMgmtResponse(aAddress, aStatus);
526*cfb92d14SAndroid Build Coastguard Worker }
527*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsConfigEnhAckProbingMgmtResponse(const otIp6Address * aAddress,otLinkMetricsStatus aStatus)528*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsConfigEnhAckProbingMgmtResponse(const otIp6Address *aAddress,
529*cfb92d14SAndroid Build Coastguard Worker otLinkMetricsStatus aStatus)
530*cfb92d14SAndroid Build Coastguard Worker {
531*cfb92d14SAndroid Build Coastguard Worker HandleLinkMetricsMgmtResponse(aAddress, aStatus);
532*cfb92d14SAndroid Build Coastguard Worker
533*cfb92d14SAndroid Build Coastguard Worker if (mConfigEnhAckProbingSync)
534*cfb92d14SAndroid Build Coastguard Worker {
535*cfb92d14SAndroid Build Coastguard Worker mConfigEnhAckProbingSync = false;
536*cfb92d14SAndroid Build Coastguard Worker OutputResult(OT_ERROR_NONE);
537*cfb92d14SAndroid Build Coastguard Worker }
538*cfb92d14SAndroid Build Coastguard Worker }
539*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsMgmtResponse(const otIp6Address * aAddress,otLinkMetricsStatus aStatus)540*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus)
541*cfb92d14SAndroid Build Coastguard Worker {
542*cfb92d14SAndroid Build Coastguard Worker OutputFormat("Received Link Metrics Management Response from: ");
543*cfb92d14SAndroid Build Coastguard Worker OutputIp6AddressLine(*aAddress);
544*cfb92d14SAndroid Build Coastguard Worker
545*cfb92d14SAndroid Build Coastguard Worker OutputLine("Status: %s", LinkMetricsStatusToStr(aStatus));
546*cfb92d14SAndroid Build Coastguard Worker }
547*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,const otExtAddress * aExtAddress,const otLinkMetricsValues * aMetricsValues,void * aContext)548*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
549*cfb92d14SAndroid Build Coastguard Worker const otExtAddress *aExtAddress,
550*cfb92d14SAndroid Build Coastguard Worker const otLinkMetricsValues *aMetricsValues,
551*cfb92d14SAndroid Build Coastguard Worker void *aContext)
552*cfb92d14SAndroid Build Coastguard Worker {
553*cfb92d14SAndroid Build Coastguard Worker static_cast<LinkMetrics *>(aContext)->HandleLinkMetricsEnhAckProbingIe(aShortAddress, aExtAddress, aMetricsValues);
554*cfb92d14SAndroid Build Coastguard Worker }
555*cfb92d14SAndroid Build Coastguard Worker
HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,const otExtAddress * aExtAddress,const otLinkMetricsValues * aMetricsValues)556*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
557*cfb92d14SAndroid Build Coastguard Worker const otExtAddress *aExtAddress,
558*cfb92d14SAndroid Build Coastguard Worker const otLinkMetricsValues *aMetricsValues)
559*cfb92d14SAndroid Build Coastguard Worker {
560*cfb92d14SAndroid Build Coastguard Worker OutputFormat("Received Link Metrics data in Enh Ack from neighbor, short address:0x%02x , extended address:",
561*cfb92d14SAndroid Build Coastguard Worker aShortAddress);
562*cfb92d14SAndroid Build Coastguard Worker OutputExtAddressLine(*aExtAddress);
563*cfb92d14SAndroid Build Coastguard Worker
564*cfb92d14SAndroid Build Coastguard Worker if (aMetricsValues != nullptr)
565*cfb92d14SAndroid Build Coastguard Worker {
566*cfb92d14SAndroid Build Coastguard Worker PrintLinkMetricsValue(aMetricsValues);
567*cfb92d14SAndroid Build Coastguard Worker }
568*cfb92d14SAndroid Build Coastguard Worker }
569*cfb92d14SAndroid Build Coastguard Worker
LinkMetricsStatusToStr(otLinkMetricsStatus aStatus)570*cfb92d14SAndroid Build Coastguard Worker const char *LinkMetrics::LinkMetricsStatusToStr(otLinkMetricsStatus aStatus)
571*cfb92d14SAndroid Build Coastguard Worker {
572*cfb92d14SAndroid Build Coastguard Worker static const char *const kStatusStrings[] = {
573*cfb92d14SAndroid Build Coastguard Worker "Success", // (0) OT_LINK_METRICS_STATUS_SUCCESS
574*cfb92d14SAndroid Build Coastguard Worker "Cannot support new series", // (1) OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES
575*cfb92d14SAndroid Build Coastguard Worker "Series ID already registered", // (2) OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED
576*cfb92d14SAndroid Build Coastguard Worker "Series ID not recognized", // (3) OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED
577*cfb92d14SAndroid Build Coastguard Worker "No matching series ID", // (4) OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED
578*cfb92d14SAndroid Build Coastguard Worker };
579*cfb92d14SAndroid Build Coastguard Worker
580*cfb92d14SAndroid Build Coastguard Worker const char *str = "Unknown error";
581*cfb92d14SAndroid Build Coastguard Worker
582*cfb92d14SAndroid Build Coastguard Worker static_assert(0 == OT_LINK_METRICS_STATUS_SUCCESS, "STATUS_SUCCESS is incorrect");
583*cfb92d14SAndroid Build Coastguard Worker static_assert(1 == OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES, "CANNOT_SUPPORT_NEW_SERIES is incorrect");
584*cfb92d14SAndroid Build Coastguard Worker static_assert(2 == OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED, "SERIESID_ALREADY_REGISTERED is incorrect");
585*cfb92d14SAndroid Build Coastguard Worker static_assert(3 == OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED, "SERIESID_NOT_RECOGNIZED is incorrect");
586*cfb92d14SAndroid Build Coastguard Worker static_assert(4 == OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED, "NO_MATCHING_FRAMES_RECEIVED is incorrect");
587*cfb92d14SAndroid Build Coastguard Worker
588*cfb92d14SAndroid Build Coastguard Worker if (aStatus < OT_ARRAY_LENGTH(kStatusStrings))
589*cfb92d14SAndroid Build Coastguard Worker {
590*cfb92d14SAndroid Build Coastguard Worker str = kStatusStrings[aStatus];
591*cfb92d14SAndroid Build Coastguard Worker }
592*cfb92d14SAndroid Build Coastguard Worker else if (aStatus == OT_LINK_METRICS_STATUS_OTHER_ERROR)
593*cfb92d14SAndroid Build Coastguard Worker {
594*cfb92d14SAndroid Build Coastguard Worker str = "Other error";
595*cfb92d14SAndroid Build Coastguard Worker }
596*cfb92d14SAndroid Build Coastguard Worker
597*cfb92d14SAndroid Build Coastguard Worker return str;
598*cfb92d14SAndroid Build Coastguard Worker }
599*cfb92d14SAndroid Build Coastguard Worker
OutputResult(otError aError)600*cfb92d14SAndroid Build Coastguard Worker void LinkMetrics::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); }
601*cfb92d14SAndroid Build Coastguard Worker
602*cfb92d14SAndroid Build Coastguard Worker } // namespace Cli
603*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
604*cfb92d14SAndroid Build Coastguard Worker
605*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
606