1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "logger.hpp"
30
31 #include "openthread-spinel-config.h"
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #include <openthread/error.h>
38 #include <openthread/logging.h>
39 #include <openthread/platform/radio.h>
40
41 #include "lib/spinel/spinel.h"
42 #include "lib/utils/math.hpp"
43 #include "lib/utils/utils.hpp"
44
45 namespace ot {
46 namespace Spinel {
47
48 using Lib::Utils::Min;
49 using Lib::Utils::ToUlong;
50
Logger(const char * aModuleName)51 Logger::Logger(const char *aModuleName)
52 : mModuleName(aModuleName)
53 {
54 }
55
LogIfFail(const char * aText,otError aError)56 void Logger::LogIfFail(const char *aText, otError aError)
57 {
58 OT_UNUSED_VARIABLE(aText);
59
60 if (aError != OT_ERROR_NONE && aError != OT_ERROR_NO_ACK)
61 {
62 LogWarn("%s: %s", aText, otThreadErrorToString(aError));
63 }
64 }
65
LogCrit(const char * aFormat,...)66 void Logger::LogCrit(const char *aFormat, ...)
67 {
68 va_list args;
69
70 va_start(args, aFormat);
71 otLogPlatArgs(OT_LOG_LEVEL_CRIT, mModuleName, aFormat, args);
72 va_end(args);
73 }
74
LogWarn(const char * aFormat,...)75 void Logger::LogWarn(const char *aFormat, ...)
76 {
77 va_list args;
78
79 va_start(args, aFormat);
80 otLogPlatArgs(OT_LOG_LEVEL_WARN, mModuleName, aFormat, args);
81 va_end(args);
82 }
83
LogNote(const char * aFormat,...)84 void Logger::LogNote(const char *aFormat, ...)
85 {
86 va_list args;
87
88 va_start(args, aFormat);
89 otLogPlatArgs(OT_LOG_LEVEL_NOTE, mModuleName, aFormat, args);
90 va_end(args);
91 }
92
LogInfo(const char * aFormat,...)93 void Logger::LogInfo(const char *aFormat, ...)
94 {
95 va_list args;
96
97 va_start(args, aFormat);
98 otLogPlatArgs(OT_LOG_LEVEL_INFO, mModuleName, aFormat, args);
99 va_end(args);
100 }
101
LogDebg(const char * aFormat,...)102 void Logger::LogDebg(const char *aFormat, ...)
103 {
104 va_list args;
105
106 va_start(args, aFormat);
107 otLogPlatArgs(OT_LOG_LEVEL_DEBG, mModuleName, aFormat, args);
108 va_end(args);
109 }
110
Snprintf(char * aDest,uint32_t aSize,const char * aFormat,...)111 uint32_t Logger::Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...)
112 {
113 int len;
114 va_list args;
115
116 va_start(args, aFormat);
117 len = vsnprintf(aDest, static_cast<size_t>(aSize), aFormat, args);
118 va_end(args);
119
120 return (len < 0) ? 0 : Min(static_cast<uint32_t>(len), aSize - 1);
121 }
122
LogSpinelFrame(const uint8_t * aFrame,uint16_t aLength,bool aTx)123 void Logger::LogSpinelFrame(const uint8_t *aFrame, uint16_t aLength, bool aTx)
124 {
125 otError error = OT_ERROR_NONE;
126 char buf[OPENTHREAD_LIB_SPINEL_LOG_MAX_SIZE] = {0};
127 spinel_ssize_t unpacked;
128 uint8_t header;
129 uint32_t cmd;
130 spinel_prop_key_t key;
131 uint8_t *data;
132 spinel_size_t len;
133 const char *prefix = nullptr;
134 char *start = buf;
135 char *end = buf + sizeof(buf);
136
137 EXPECT(otLoggingGetLevel() >= OT_LOG_LEVEL_DEBG, NO_ACTION);
138
139 prefix = aTx ? "Sent spinel frame" : "Received spinel frame";
140 unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
141 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
142
143 start += Snprintf(start, static_cast<uint32_t>(end - start), "%s, flg:0x%x, iid:%d, tid:%u, cmd:%s", prefix,
144 SPINEL_HEADER_GET_FLAG(header), SPINEL_HEADER_GET_IID(header), SPINEL_HEADER_GET_TID(header),
145 spinel_command_to_cstr(cmd));
146 EXPECT(cmd != SPINEL_CMD_RESET, NO_ACTION);
147
148 start += Snprintf(start, static_cast<uint32_t>(end - start), ", key:%s", spinel_prop_key_to_cstr(key));
149 EXPECT(cmd != SPINEL_CMD_PROP_VALUE_GET, NO_ACTION);
150
151 switch (key)
152 {
153 case SPINEL_PROP_LAST_STATUS:
154 {
155 spinel_status_t status;
156
157 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &status);
158 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
159 start += Snprintf(start, static_cast<uint32_t>(end - start), ", status:%s", spinel_status_to_cstr(status));
160 }
161 break;
162
163 case SPINEL_PROP_MAC_RAW_STREAM_ENABLED:
164 case SPINEL_PROP_MAC_SRC_MATCH_ENABLED:
165 case SPINEL_PROP_PHY_ENABLED:
166 case SPINEL_PROP_RADIO_COEX_ENABLE:
167 {
168 bool enabled;
169
170 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_BOOL_S, &enabled);
171 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
172 start += Snprintf(start, static_cast<uint32_t>(end - start), ", enabled:%u", enabled);
173 }
174 break;
175
176 case SPINEL_PROP_PHY_CCA_THRESHOLD:
177 case SPINEL_PROP_PHY_FEM_LNA_GAIN:
178 case SPINEL_PROP_PHY_RX_SENSITIVITY:
179 case SPINEL_PROP_PHY_RSSI:
180 case SPINEL_PROP_PHY_TX_POWER:
181 {
182 const char *name = nullptr;
183 int8_t value;
184
185 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_INT8_S, &value);
186 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
187
188 switch (key)
189 {
190 case SPINEL_PROP_PHY_TX_POWER:
191 name = "power";
192 break;
193 case SPINEL_PROP_PHY_CCA_THRESHOLD:
194 name = "threshold";
195 break;
196 case SPINEL_PROP_PHY_FEM_LNA_GAIN:
197 name = "gain";
198 break;
199 case SPINEL_PROP_PHY_RX_SENSITIVITY:
200 name = "sensitivity";
201 break;
202 case SPINEL_PROP_PHY_RSSI:
203 name = "rssi";
204 break;
205 }
206
207 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%d", name, value);
208 }
209 break;
210
211 case SPINEL_PROP_MAC_PROMISCUOUS_MODE:
212 case SPINEL_PROP_MAC_SCAN_STATE:
213 case SPINEL_PROP_PHY_CHAN:
214 case SPINEL_PROP_RCP_CSL_ACCURACY:
215 case SPINEL_PROP_RCP_CSL_UNCERTAINTY:
216 {
217 const char *name = nullptr;
218 uint8_t value;
219
220 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S, &value);
221 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
222
223 switch (key)
224 {
225 case SPINEL_PROP_MAC_SCAN_STATE:
226 name = "state";
227 break;
228 case SPINEL_PROP_RCP_CSL_ACCURACY:
229 name = "accuracy";
230 break;
231 case SPINEL_PROP_RCP_CSL_UNCERTAINTY:
232 name = "uncertainty";
233 break;
234 case SPINEL_PROP_MAC_PROMISCUOUS_MODE:
235 name = "mode";
236 break;
237 case SPINEL_PROP_PHY_CHAN:
238 name = "channel";
239 break;
240 }
241
242 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
243 }
244 break;
245
246 case SPINEL_PROP_MAC_15_4_PANID:
247 case SPINEL_PROP_MAC_15_4_SADDR:
248 case SPINEL_PROP_MAC_SCAN_PERIOD:
249 case SPINEL_PROP_PHY_REGION_CODE:
250 {
251 const char *name = nullptr;
252 uint16_t value;
253
254 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT16_S, &value);
255 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
256
257 switch (key)
258 {
259 case SPINEL_PROP_MAC_SCAN_PERIOD:
260 name = "period";
261 break;
262 case SPINEL_PROP_PHY_REGION_CODE:
263 name = "region";
264 break;
265 case SPINEL_PROP_MAC_15_4_SADDR:
266 name = "saddr";
267 break;
268 case SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES:
269 name = "saddr";
270 break;
271 case SPINEL_PROP_MAC_15_4_PANID:
272 name = "panid";
273 break;
274 }
275
276 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:0x%04x", name, value);
277 }
278 break;
279
280 case SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES:
281 {
282 uint16_t saddr;
283
284 start += Snprintf(start, static_cast<uint32_t>(end - start), ", saddr:");
285
286 if (len < sizeof(saddr))
287 {
288 start += Snprintf(start, static_cast<uint32_t>(end - start), "none");
289 }
290 else
291 {
292 while (len >= sizeof(saddr))
293 {
294 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT16_S, &saddr);
295 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
296 data += unpacked;
297 len -= static_cast<spinel_size_t>(unpacked);
298 start += Snprintf(start, static_cast<uint32_t>(end - start), "0x%04x ", saddr);
299 }
300 }
301 }
302 break;
303
304 case SPINEL_PROP_RCP_MAC_FRAME_COUNTER:
305 case SPINEL_PROP_RCP_TIMESTAMP:
306 {
307 const char *name;
308 uint32_t value;
309
310 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT32_S, &value);
311 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
312
313 name = (key == SPINEL_PROP_RCP_TIMESTAMP) ? "timestamp" : "counter";
314 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
315 }
316 break;
317
318 case SPINEL_PROP_RADIO_CAPS:
319 case SPINEL_PROP_RCP_API_VERSION:
320 case SPINEL_PROP_RCP_MIN_HOST_API_VERSION:
321 {
322 const char *name;
323 unsigned int value;
324
325 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &value);
326 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
327
328 switch (key)
329 {
330 case SPINEL_PROP_RADIO_CAPS:
331 name = "caps";
332 break;
333 case SPINEL_PROP_RCP_API_VERSION:
334 name = "version";
335 break;
336 case SPINEL_PROP_RCP_MIN_HOST_API_VERSION:
337 name = "min-host-version";
338 break;
339 default:
340 name = "";
341 break;
342 }
343
344 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%u", name, value);
345 }
346 break;
347
348 case SPINEL_PROP_RCP_LOG_CRASH_DUMP:
349 {
350 const char *name;
351 name = "log-crash-dump";
352
353 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s", name);
354 }
355 break;
356
357 case SPINEL_PROP_MAC_ENERGY_SCAN_RESULT:
358 case SPINEL_PROP_PHY_CHAN_MAX_POWER:
359 {
360 const char *name;
361 uint8_t channel;
362 int8_t value;
363
364 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S, &channel, &value);
365 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
366
367 name = (key == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT) ? "rssi" : "power";
368 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channel:%u, %s:%d", channel, name, value);
369 }
370 break;
371
372 case SPINEL_PROP_CAPS:
373 {
374 unsigned int capability;
375
376 start += Snprintf(start, static_cast<uint32_t>(end - start), ", caps:");
377
378 while (len > 0)
379 {
380 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S, &capability);
381 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
382 data += unpacked;
383 len -= static_cast<spinel_size_t>(unpacked);
384 start += Snprintf(start, static_cast<uint32_t>(end - start), "%s ", spinel_capability_to_cstr(capability));
385 }
386 }
387 break;
388
389 case SPINEL_PROP_PROTOCOL_VERSION:
390 {
391 unsigned int major;
392 unsigned int minor;
393
394 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S,
395 &major, &minor);
396 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
397 start += Snprintf(start, static_cast<uint32_t>(end - start), ", major:%u, minor:%u", major, minor);
398 }
399 break;
400
401 case SPINEL_PROP_PHY_CHAN_PREFERRED:
402 case SPINEL_PROP_PHY_CHAN_SUPPORTED:
403 {
404 uint8_t maskBuffer[kChannelMaskBufferSize];
405 uint32_t channelMask = 0;
406 const uint8_t *maskData = maskBuffer;
407 spinel_size_t maskLength = sizeof(maskBuffer);
408
409 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength);
410 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
411
412 while (maskLength > 0)
413 {
414 uint8_t channel;
415
416 unpacked = spinel_datatype_unpack(maskData, maskLength, SPINEL_DATATYPE_UINT8_S, &channel);
417 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
418 EXPECT(channel < kChannelMaskBufferSize, error = OT_ERROR_PARSE);
419 channelMask |= (1UL << channel);
420
421 maskData += unpacked;
422 maskLength -= static_cast<spinel_size_t>(unpacked);
423 }
424
425 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channelMask:0x%08x", channelMask);
426 }
427 break;
428
429 case SPINEL_PROP_NCP_VERSION:
430 {
431 const char *version;
432
433 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &version);
434 EXPECT(unpacked >= 0, error = OT_ERROR_PARSE);
435 start += Snprintf(start, static_cast<uint32_t>(end - start), ", version:%s", version);
436 }
437 break;
438
439 case SPINEL_PROP_STREAM_RAW:
440 {
441 otRadioFrame frame;
442
443 if (cmd == SPINEL_CMD_PROP_VALUE_IS)
444 {
445 uint16_t flags;
446 int8_t noiseFloor;
447 unsigned int receiveError;
448
449 unpacked = spinel_datatype_unpack(data, len,
450 SPINEL_DATATYPE_DATA_WLEN_S // Frame
451 SPINEL_DATATYPE_INT8_S // RSSI
452 SPINEL_DATATYPE_INT8_S // Noise Floor
453 SPINEL_DATATYPE_UINT16_S // Flags
454 SPINEL_DATATYPE_STRUCT_S( // PHY-data
455 SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
456 SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
457 SPINEL_DATATYPE_UINT64_S // Timestamp (us).
458 ) SPINEL_DATATYPE_STRUCT_S( // Vendor-data
459 SPINEL_DATATYPE_UINT_PACKED_S // Receive error
460 ),
461 &frame.mPsdu, &frame.mLength, &frame.mInfo.mRxInfo.mRssi, &noiseFloor,
462 &flags, &frame.mChannel, &frame.mInfo.mRxInfo.mLqi,
463 &frame.mInfo.mRxInfo.mTimestamp, &receiveError);
464 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
465 start += Snprintf(start, static_cast<uint32_t>(end - start), ", len:%u, rssi:%d ...", frame.mLength,
466 frame.mInfo.mRxInfo.mRssi);
467 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
468 LogDebg("%s", buf);
469
470 start = buf;
471 start += Snprintf(start, static_cast<uint32_t>(end - start),
472 "... noise:%d, flags:0x%04x, channel:%u, lqi:%u, timestamp:%lu, rxerr:%u", noiseFloor,
473 flags, frame.mChannel, frame.mInfo.mRxInfo.mLqi,
474 static_cast<unsigned long>(frame.mInfo.mRxInfo.mTimestamp), receiveError);
475 }
476 else if (cmd == SPINEL_CMD_PROP_VALUE_SET)
477 {
478 bool csmaCaEnabled;
479 bool isHeaderUpdated;
480 bool isARetx;
481 bool skipAes;
482
483 unpacked = spinel_datatype_unpack(
484 data, len,
485 SPINEL_DATATYPE_DATA_WLEN_S // Frame data
486 SPINEL_DATATYPE_UINT8_S // Channel
487 SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs
488 SPINEL_DATATYPE_UINT8_S // MaxFrameRetries
489 SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled
490 SPINEL_DATATYPE_BOOL_S // IsHeaderUpdated
491 SPINEL_DATATYPE_BOOL_S // IsARetx
492 SPINEL_DATATYPE_BOOL_S // SkipAes
493 SPINEL_DATATYPE_UINT32_S // TxDelay
494 SPINEL_DATATYPE_UINT32_S, // TxDelayBaseTime
495 &frame.mPsdu, &frame.mLength, &frame.mChannel, &frame.mInfo.mTxInfo.mMaxCsmaBackoffs,
496 &frame.mInfo.mTxInfo.mMaxFrameRetries, &csmaCaEnabled, &isHeaderUpdated, &isARetx, &skipAes,
497 &frame.mInfo.mTxInfo.mTxDelay, &frame.mInfo.mTxInfo.mTxDelayBaseTime);
498
499 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
500 start += Snprintf(start, static_cast<uint32_t>(end - start),
501 ", len:%u, channel:%u, maxbackoffs:%u, maxretries:%u ...", frame.mLength, frame.mChannel,
502 frame.mInfo.mTxInfo.mMaxCsmaBackoffs, frame.mInfo.mTxInfo.mMaxFrameRetries);
503 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
504 LogDebg("%s", buf);
505
506 start = buf;
507 start += Snprintf(start, static_cast<uint32_t>(end - start),
508 "... csmaCaEnabled:%u, isHeaderUpdated:%u, isARetx:%u, skipAes:%u"
509 ", txDelay:%u, txDelayBase:%u",
510 csmaCaEnabled, isHeaderUpdated, isARetx, skipAes, frame.mInfo.mTxInfo.mTxDelay,
511 frame.mInfo.mTxInfo.mTxDelayBaseTime);
512 }
513 }
514 break;
515
516 case SPINEL_PROP_STREAM_DEBUG:
517 {
518 char debugString[OPENTHREAD_LIB_SPINEL_NCP_LOG_MAX_SIZE + 1];
519 spinel_size_t stringLength = sizeof(debugString);
520
521 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_DATA_S, debugString, &stringLength);
522 assert(stringLength < sizeof(debugString));
523 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
524 debugString[stringLength] = '\0';
525 start += Snprintf(start, static_cast<uint32_t>(end - start), ", debug:%s", debugString);
526 }
527 break;
528
529 case SPINEL_PROP_STREAM_LOG:
530 {
531 const char *logString;
532 uint8_t logLevel;
533
534 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &logString);
535 EXPECT(unpacked >= 0, error = OT_ERROR_PARSE);
536 data += unpacked;
537 len -= static_cast<spinel_size_t>(unpacked);
538
539 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S, &logLevel);
540 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
541 start += Snprintf(start, static_cast<uint32_t>(end - start), ", level:%u, log:%s", logLevel, logString);
542 }
543 break;
544
545 case SPINEL_PROP_NEST_STREAM_MFG:
546 {
547 const char *output;
548 size_t outputLen;
549
550 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UTF8_S, &output, &outputLen);
551 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
552 start += Snprintf(start, static_cast<uint32_t>(end - start), ", diag:%s", output);
553 }
554 break;
555
556 case SPINEL_PROP_RCP_MAC_KEY:
557 {
558 uint8_t keyIdMode;
559 uint8_t keyId;
560 otMacKey prevKey;
561 unsigned int prevKeyLen = sizeof(otMacKey);
562 otMacKey currKey;
563 unsigned int currKeyLen = sizeof(otMacKey);
564 otMacKey nextKey;
565 unsigned int nextKeyLen = sizeof(otMacKey);
566
567 unpacked = spinel_datatype_unpack(data, len,
568 SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_DATA_WLEN_S
569 SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_DATA_WLEN_S,
570 &keyIdMode, &keyId, prevKey.m8, &prevKeyLen, currKey.m8, &currKeyLen,
571 nextKey.m8, &nextKeyLen);
572 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
573 start += Snprintf(start, static_cast<uint32_t>(end - start),
574 ", keyIdMode:%u, keyId:%u, prevKey:***, currKey:***, nextKey:***", keyIdMode, keyId);
575 }
576 break;
577
578 case SPINEL_PROP_HWADDR:
579 case SPINEL_PROP_MAC_15_4_LADDR:
580 {
581 const char *name = nullptr;
582 uint8_t m8[OT_EXT_ADDRESS_SIZE] = {0};
583
584 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_EUI64_S, &m8[0]);
585 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
586
587 name = (key == SPINEL_PROP_HWADDR) ? "eui64" : "laddr";
588 start += Snprintf(start, static_cast<uint32_t>(end - start), ", %s:%02x%02x%02x%02x%02x%02x%02x%02x", name,
589 m8[0], m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
590 }
591 break;
592
593 case SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES:
594 {
595 uint8_t m8[OT_EXT_ADDRESS_SIZE];
596
597 start += Snprintf(start, static_cast<uint32_t>(end - start), ", extaddr:");
598
599 if (len < sizeof(m8))
600 {
601 start += Snprintf(start, static_cast<uint32_t>(end - start), "none");
602 }
603 else
604 {
605 while (len >= sizeof(m8))
606 {
607 unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_EUI64_S, m8);
608 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
609 data += unpacked;
610 len -= static_cast<spinel_size_t>(unpacked);
611 start += Snprintf(start, static_cast<uint32_t>(end - start), "%02x%02x%02x%02x%02x%02x%02x%02x ", m8[0],
612 m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
613 }
614 }
615 }
616 break;
617
618 case SPINEL_PROP_RADIO_COEX_METRICS:
619 {
620 otRadioCoexMetrics metrics;
621 unpacked = spinel_datatype_unpack(
622 data, len,
623 SPINEL_DATATYPE_STRUCT_S( // Tx Coex Metrics Structure
624 SPINEL_DATATYPE_UINT32_S // NumTxRequest
625 SPINEL_DATATYPE_UINT32_S // NumTxGrantImmediate
626 SPINEL_DATATYPE_UINT32_S // NumTxGrantWait
627 SPINEL_DATATYPE_UINT32_S // NumTxGrantWaitActivated
628 SPINEL_DATATYPE_UINT32_S // NumTxGrantWaitTimeout
629 SPINEL_DATATYPE_UINT32_S // NumTxGrantDeactivatedDuringRequest
630 SPINEL_DATATYPE_UINT32_S // NumTxDelayedGrant
631 SPINEL_DATATYPE_UINT32_S // AvgTxRequestToGrantTime
632 ) SPINEL_DATATYPE_STRUCT_S( // Rx Coex Metrics Structure
633 SPINEL_DATATYPE_UINT32_S // NumRxRequest
634 SPINEL_DATATYPE_UINT32_S // NumRxGrantImmediate
635 SPINEL_DATATYPE_UINT32_S // NumRxGrantWait
636 SPINEL_DATATYPE_UINT32_S // NumRxGrantWaitActivated
637 SPINEL_DATATYPE_UINT32_S // NumRxGrantWaitTimeout
638 SPINEL_DATATYPE_UINT32_S // NumRxGrantDeactivatedDuringRequest
639 SPINEL_DATATYPE_UINT32_S // NumRxDelayedGrant
640 SPINEL_DATATYPE_UINT32_S // AvgRxRequestToGrantTime
641 SPINEL_DATATYPE_UINT32_S // NumRxGrantNone
642 ) SPINEL_DATATYPE_BOOL_S // Stopped
643 SPINEL_DATATYPE_UINT32_S, // NumGrantGlitch
644 &metrics.mNumTxRequest, &metrics.mNumTxGrantImmediate, &metrics.mNumTxGrantWait,
645 &metrics.mNumTxGrantWaitActivated, &metrics.mNumTxGrantWaitTimeout,
646 &metrics.mNumTxGrantDeactivatedDuringRequest, &metrics.mNumTxDelayedGrant,
647 &metrics.mAvgTxRequestToGrantTime, &metrics.mNumRxRequest, &metrics.mNumRxGrantImmediate,
648 &metrics.mNumRxGrantWait, &metrics.mNumRxGrantWaitActivated, &metrics.mNumRxGrantWaitTimeout,
649 &metrics.mNumRxGrantDeactivatedDuringRequest, &metrics.mNumRxDelayedGrant,
650 &metrics.mAvgRxRequestToGrantTime, &metrics.mNumRxGrantNone, &metrics.mStopped, &metrics.mNumGrantGlitch);
651
652 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
653
654 LogDebg("%s ...", buf);
655 LogDebg(" txRequest:%lu", ToUlong(metrics.mNumTxRequest));
656 LogDebg(" txGrantImmediate:%lu", ToUlong(metrics.mNumTxGrantImmediate));
657 LogDebg(" txGrantWait:%lu", ToUlong(metrics.mNumTxGrantWait));
658 LogDebg(" txGrantWaitActivated:%lu", ToUlong(metrics.mNumTxGrantWaitActivated));
659 LogDebg(" txGrantWaitTimeout:%lu", ToUlong(metrics.mNumTxGrantWaitTimeout));
660 LogDebg(" txGrantDeactivatedDuringRequest:%lu", ToUlong(metrics.mNumTxGrantDeactivatedDuringRequest));
661 LogDebg(" txDelayedGrant:%lu", ToUlong(metrics.mNumTxDelayedGrant));
662 LogDebg(" avgTxRequestToGrantTime:%lu", ToUlong(metrics.mAvgTxRequestToGrantTime));
663 LogDebg(" rxRequest:%lu", ToUlong(metrics.mNumRxRequest));
664 LogDebg(" rxGrantImmediate:%lu", ToUlong(metrics.mNumRxGrantImmediate));
665 LogDebg(" rxGrantWait:%lu", ToUlong(metrics.mNumRxGrantWait));
666 LogDebg(" rxGrantWaitActivated:%lu", ToUlong(metrics.mNumRxGrantWaitActivated));
667 LogDebg(" rxGrantWaitTimeout:%lu", ToUlong(metrics.mNumRxGrantWaitTimeout));
668 LogDebg(" rxGrantDeactivatedDuringRequest:%lu", ToUlong(metrics.mNumRxGrantDeactivatedDuringRequest));
669 LogDebg(" rxDelayedGrant:%lu", ToUlong(metrics.mNumRxDelayedGrant));
670 LogDebg(" avgRxRequestToGrantTime:%lu", ToUlong(metrics.mAvgRxRequestToGrantTime));
671 LogDebg(" rxGrantNone:%lu", ToUlong(metrics.mNumRxGrantNone));
672 LogDebg(" stopped:%u", metrics.mStopped);
673
674 start = buf;
675 start += Snprintf(start, static_cast<uint32_t>(end - start), " grantGlitch:%u", metrics.mNumGrantGlitch);
676 }
677 break;
678
679 case SPINEL_PROP_MAC_SCAN_MASK:
680 {
681 constexpr uint8_t kNumChannels = 16;
682 uint8_t channels[kNumChannels];
683 spinel_size_t size;
684
685 unpacked = spinel_datatype_unpack(data, len, SPINEL_DATATYPE_DATA_S, channels, &size);
686 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
687 start += Snprintf(start, static_cast<uint32_t>(end - start), ", channels:");
688
689 for (spinel_size_t i = 0; i < size; i++)
690 {
691 start += Snprintf(start, static_cast<uint32_t>(end - start), "%u ", channels[i]);
692 }
693 }
694 break;
695
696 case SPINEL_PROP_RCP_ENH_ACK_PROBING:
697 {
698 uint16_t saddr;
699 uint8_t m8[OT_EXT_ADDRESS_SIZE];
700 uint8_t flags;
701
702 unpacked = spinel_datatype_unpack(
703 data, len, SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_UINT8_S, &saddr, m8, &flags);
704
705 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
706 start += Snprintf(start, static_cast<uint32_t>(end - start),
707 ", saddr:%04x, extaddr:%02x%02x%02x%02x%02x%02x%02x%02x, flags:0x%02x", saddr, m8[0], m8[1],
708 m8[2], m8[3], m8[4], m8[5], m8[6], m8[7], flags);
709 }
710 break;
711
712 case SPINEL_PROP_PHY_CALIBRATED_POWER:
713 {
714 if (cmd == SPINEL_CMD_PROP_VALUE_INSERT)
715 {
716 uint8_t channel;
717 int16_t actualPower;
718 uint8_t *rawPowerSetting;
719 unsigned int rawPowerSettingLength;
720
721 unpacked = spinel_datatype_unpack(
722 data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_DATA_WLEN_S, &channel,
723 &actualPower, &rawPowerSetting, &rawPowerSettingLength);
724 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
725
726 start += Snprintf(start, static_cast<uint32_t>(end - start),
727 ", ch:%u, actualPower:%d, rawPowerSetting:", channel, actualPower);
728 for (unsigned int i = 0; i < rawPowerSettingLength; i++)
729 {
730 start += Snprintf(start, static_cast<uint32_t>(end - start), "%02x", rawPowerSetting[i]);
731 }
732 }
733 }
734 break;
735
736 case SPINEL_PROP_PHY_CHAN_TARGET_POWER:
737 {
738 uint8_t channel;
739 int16_t targetPower;
740
741 unpacked =
742 spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, &channel, &targetPower);
743 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
744 start += Snprintf(start, static_cast<uint32_t>(end - start), ", ch:%u, targetPower:%d", channel, targetPower);
745 }
746 break;
747 }
748
749 exit:
750 OT_UNUSED_VARIABLE(start); // Avoid static analysis error
751 if (error == OT_ERROR_NONE)
752 {
753 LogDebg("%s", buf);
754 }
755 else if (prefix != nullptr)
756 {
757 LogDebg("%s, failed to parse spinel frame !", prefix);
758 }
759 }
760
761 } // namespace Spinel
762 } // namespace ot
763