xref: /aosp_15_r20/external/openthread/src/cli/cli_link_metrics.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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