1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the diagnostics module.
32 */
33
34 #include "factory_diags.hpp"
35
36 #if OPENTHREAD_CONFIG_DIAG_ENABLE
37
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include <openthread/platform/alarm-milli.h>
42 #include <openthread/platform/diag.h>
43 #include <openthread/platform/radio.h>
44
45 #include "instance/instance.hpp"
46 #include "utils/parse_cmdline.hpp"
47
48 OT_TOOL_WEAK
otPlatDiagProcess(otInstance * aInstance,uint8_t aArgsLength,char * aArgs[])49 otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
50 {
51 OT_UNUSED_VARIABLE(aArgsLength);
52 OT_UNUSED_VARIABLE(aArgs);
53 OT_UNUSED_VARIABLE(aInstance);
54
55 return ot::kErrorInvalidCommand;
56 }
57
58 namespace ot {
59 namespace FactoryDiags {
60
61 #if OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI
62
63 const struct Diags::Command Diags::sCommands[] = {
64 {"channel", &Diags::ProcessChannel},
65 {"cw", &Diags::ProcessContinuousWave},
66 {"echo", &Diags::ProcessEcho},
67 {"gpio", &Diags::ProcessGpio},
68 {"power", &Diags::ProcessPower},
69 {"powersettings", &Diags::ProcessPowerSettings},
70 {"rawpowersetting", &Diags::ProcessRawPowerSetting},
71 {"start", &Diags::ProcessStart},
72 {"stop", &Diags::ProcessStop},
73 {"stream", &Diags::ProcessStream},
74 };
75
Diags(Instance & aInstance)76 Diags::Diags(Instance &aInstance)
77 : InstanceLocator(aInstance)
78 , mOutputCallback(nullptr)
79 , mOutputContext(nullptr)
80 {
81 }
82
ProcessChannel(uint8_t aArgsLength,char * aArgs[])83 Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[])
84 {
85 Error error = kErrorNone;
86 uint8_t channel;
87
88 VerifyOrExit(aArgsLength == 1, error = kErrorInvalidArgs);
89
90 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], channel));
91 VerifyOrExit(IsChannelValid(channel), error = kErrorInvalidArgs);
92
93 otPlatDiagChannelSet(channel);
94
95 exit:
96 return error;
97 }
98
ProcessPower(uint8_t aArgsLength,char * aArgs[])99 Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[])
100 {
101 Error error = kErrorNone;
102 int8_t power;
103
104 VerifyOrExit(aArgsLength == 1, error = kErrorInvalidArgs);
105
106 SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt8(aArgs[0], power));
107
108 otPlatDiagTxPowerSet(power);
109
110 exit:
111 return error;
112 }
113
ProcessEcho(uint8_t aArgsLength,char * aArgs[])114 Error Diags::ProcessEcho(uint8_t aArgsLength, char *aArgs[])
115 {
116 Error error = kErrorNone;
117
118 if (aArgsLength == 1)
119 {
120 Output("%s\r\n", aArgs[0]);
121 }
122 else if ((aArgsLength == 2) && StringMatch(aArgs[0], "-n"))
123 {
124 static constexpr uint8_t kReservedLen = 1; // 1 byte '\0'
125 static constexpr uint16_t kOutputLen = OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE;
126 static constexpr uint16_t kOutputMaxLen = kOutputLen - kReservedLen;
127 char output[kOutputLen];
128 uint32_t i;
129 uint32_t number;
130
131 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[1], number));
132 number = Min(number, static_cast<uint32_t>(kOutputMaxLen));
133
134 for (i = 0; i < number; i++)
135 {
136 output[i] = '0' + i % 10;
137 }
138
139 output[number] = '\0';
140
141 Output("%s\r\n", output);
142 }
143 else
144 {
145 error = kErrorInvalidArgs;
146 }
147
148 exit:
149 return error;
150 }
151
ProcessStart(uint8_t aArgsLength,char * aArgs[])152 Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[])
153 {
154 OT_UNUSED_VARIABLE(aArgsLength);
155 OT_UNUSED_VARIABLE(aArgs);
156
157 otPlatDiagModeSet(true);
158
159 return kErrorNone;
160 }
161
ProcessStop(uint8_t aArgsLength,char * aArgs[])162 Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[])
163 {
164 OT_UNUSED_VARIABLE(aArgsLength);
165 OT_UNUSED_VARIABLE(aArgs);
166
167 otPlatDiagModeSet(false);
168
169 return kErrorNone;
170 }
171
otPlatDiagAlarmFired(otInstance * aInstance)172 extern "C" void otPlatDiagAlarmFired(otInstance *aInstance) { otPlatDiagAlarmCallback(aInstance); }
173
174 #else // OPENTHREAD_RADIO && !OPENTHREAD_RADIO_CLI
175 // For OPENTHREAD_FTD, OPENTHREAD_MTD, OPENTHREAD_RADIO_CLI
176 const struct Diags::Command Diags::sCommands[] = {
177 {"channel", &Diags::ProcessChannel},
178 {"cw", &Diags::ProcessContinuousWave},
179 {"frame", &Diags::ProcessFrame},
180 {"gpio", &Diags::ProcessGpio},
181 {"power", &Diags::ProcessPower},
182 {"powersettings", &Diags::ProcessPowerSettings},
183 {"rawpowersetting", &Diags::ProcessRawPowerSetting},
184 {"radio", &Diags::ProcessRadio},
185 {"repeat", &Diags::ProcessRepeat},
186 {"send", &Diags::ProcessSend},
187 {"start", &Diags::ProcessStart},
188 {"stats", &Diags::ProcessStats},
189 {"stop", &Diags::ProcessStop},
190 {"stream", &Diags::ProcessStream},
191 };
192
193 Diags::Diags(Instance &aInstance)
194 : InstanceLocator(aInstance)
195 , mTxPacket(&Get<Radio>().GetTransmitBuffer())
196 , mTxPeriod(0)
197 , mTxPackets(0)
198 , mChannel(20)
199 , mTxPower(0)
200 , mTxLen(0)
201 , mIsTxPacketSet(false)
202 , mIsAsyncSend(false)
203 , mRepeatActive(false)
204 , mDiagSendOn(false)
205 , mOutputCallback(nullptr)
206 , mOutputContext(nullptr)
207 {
208 mStats.Clear();
209 }
210
211 void Diags::ResetTxPacket(void)
212 {
213 mIsHeaderUpdated = false;
214 mTxPacket->mInfo.mTxInfo.mTxDelayBaseTime = 0;
215 mTxPacket->mInfo.mTxInfo.mTxDelay = 0;
216 mTxPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = 0;
217 mTxPacket->mInfo.mTxInfo.mMaxFrameRetries = 0;
218 mTxPacket->mInfo.mTxInfo.mRxChannelAfterTxDone = mChannel;
219 mTxPacket->mInfo.mTxInfo.mTxPower = OT_RADIO_POWER_INVALID;
220 mTxPacket->mInfo.mTxInfo.mIsHeaderUpdated = false;
221 mTxPacket->mInfo.mTxInfo.mIsARetx = false;
222 mTxPacket->mInfo.mTxInfo.mCsmaCaEnabled = false;
223 mTxPacket->mInfo.mTxInfo.mCslPresent = false;
224 mTxPacket->mInfo.mTxInfo.mIsSecurityProcessed = false;
225 }
226
227 Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[])
228 {
229 Error error = kErrorNone;
230 uint16_t size = OT_RADIO_FRAME_MAX_SIZE;
231 bool securityProcessed = false;
232 bool csmaCaEnabled = false;
233 bool isHeaderUpdated = false;
234 int8_t txPower = OT_RADIO_POWER_INVALID;
235 uint8_t maxFrameRetries = 0;
236 uint8_t maxCsmaBackoffs = 0;
237 uint8_t rxChannelAfterTxDone = mChannel;
238 uint32_t txDelayBaseTime = 0;
239 uint32_t txDelay = 0;
240
241 while (aArgsLength > 1)
242 {
243 if (StringMatch(aArgs[0], "-b"))
244 {
245 aArgs++;
246 aArgsLength--;
247
248 VerifyOrExit(aArgsLength > 1, error = kErrorInvalidArgs);
249 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], maxCsmaBackoffs));
250 }
251 else if (StringMatch(aArgs[0], "-c"))
252 {
253 csmaCaEnabled = true;
254 }
255 else if (StringMatch(aArgs[0], "-C"))
256 {
257 aArgs++;
258 aArgsLength--;
259
260 VerifyOrExit(aArgsLength > 1, error = kErrorInvalidArgs);
261 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], rxChannelAfterTxDone));
262 VerifyOrExit(IsChannelValid(rxChannelAfterTxDone), error = kErrorInvalidArgs);
263 }
264 else if (StringMatch(aArgs[0], "-d"))
265 {
266 aArgs++;
267 aArgsLength--;
268
269 VerifyOrExit(aArgsLength > 1, error = kErrorInvalidArgs);
270 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[0], txDelay));
271 txDelayBaseTime = static_cast<uint32_t>(otPlatRadioGetNow(&GetInstance()));
272 }
273 else if (StringMatch(aArgs[0], "-p"))
274 {
275 aArgs++;
276 aArgsLength--;
277
278 VerifyOrExit(aArgsLength > 1, error = kErrorInvalidArgs);
279 SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt8(aArgs[0], txPower));
280 }
281 else if (StringMatch(aArgs[0], "-r"))
282 {
283 aArgs++;
284 aArgsLength--;
285
286 VerifyOrExit(aArgsLength > 1, error = kErrorInvalidArgs);
287 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], maxFrameRetries));
288 }
289 else if (StringMatch(aArgs[0], "-s"))
290 {
291 securityProcessed = true;
292 isHeaderUpdated = true;
293 }
294 else if (StringMatch(aArgs[0], "-u"))
295 {
296 isHeaderUpdated = true;
297 }
298 else
299 {
300 ExitNow(error = kErrorInvalidArgs);
301 }
302
303 aArgs++;
304 aArgsLength--;
305 }
306
307 VerifyOrExit(aArgsLength == 1, error = kErrorInvalidArgs);
308
309 SuccessOrExit(error = Utils::CmdLineParser::ParseAsHexString(aArgs[0], size, mTxPacket->mPsdu));
310 VerifyOrExit(size <= OT_RADIO_FRAME_MAX_SIZE, error = kErrorInvalidArgs);
311 VerifyOrExit(size >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs);
312
313 ResetTxPacket();
314 mTxPacket->mInfo.mTxInfo.mCsmaCaEnabled = csmaCaEnabled;
315 mTxPacket->mInfo.mTxInfo.mIsSecurityProcessed = securityProcessed;
316 mTxPacket->mInfo.mTxInfo.mTxPower = txPower;
317 mTxPacket->mInfo.mTxInfo.mTxDelayBaseTime = txDelayBaseTime;
318 mTxPacket->mInfo.mTxInfo.mTxDelay = txDelay;
319 mTxPacket->mInfo.mTxInfo.mMaxFrameRetries = maxFrameRetries;
320 mTxPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = maxCsmaBackoffs;
321 mTxPacket->mInfo.mTxInfo.mRxChannelAfterTxDone = rxChannelAfterTxDone;
322 mTxPacket->mLength = size;
323 mIsHeaderUpdated = isHeaderUpdated;
324 mIsTxPacketSet = true;
325
326 exit:
327 return error;
328 }
329
330 Error Diags::ProcessChannel(uint8_t aArgsLength, char *aArgs[])
331 {
332 Error error = kErrorNone;
333
334 if (aArgsLength == 0)
335 {
336 Output("%u\r\n", mChannel);
337 }
338 else
339 {
340 uint8_t channel;
341
342 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], channel));
343 VerifyOrExit(IsChannelValid(channel), error = kErrorInvalidArgs);
344
345 mChannel = channel;
346 IgnoreError(Get<Radio>().Receive(mChannel));
347 otPlatDiagChannelSet(mChannel);
348 }
349
350 exit:
351 return error;
352 }
353
354 Error Diags::ProcessPower(uint8_t aArgsLength, char *aArgs[])
355 {
356 Error error = kErrorNone;
357
358 if (aArgsLength == 0)
359 {
360 Output("%d\r\n", mTxPower);
361 }
362 else
363 {
364 int8_t txPower;
365
366 SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt8(aArgs[0], txPower));
367
368 mTxPower = txPower;
369 SuccessOrExit(error = Get<Radio>().SetTransmitPower(mTxPower));
370 otPlatDiagTxPowerSet(mTxPower);
371 }
372
373 exit:
374 return error;
375 }
376
377 Error Diags::ProcessRepeat(uint8_t aArgsLength, char *aArgs[])
378 {
379 Error error = kErrorNone;
380
381 VerifyOrExit(aArgsLength > 0, error = kErrorInvalidArgs);
382
383 if (StringMatch(aArgs[0], "stop"))
384 {
385 otPlatAlarmMilliStop(&GetInstance());
386 mRepeatActive = false;
387 }
388 else
389 {
390 uint32_t txPeriod;
391 uint8_t txLength;
392
393 VerifyOrExit(aArgsLength >= 1, error = kErrorInvalidArgs);
394
395 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[0], txPeriod));
396 mTxPeriod = txPeriod;
397
398 if (aArgsLength >= 2)
399 {
400 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[1], txLength));
401 mIsTxPacketSet = false;
402 }
403 else if (mIsTxPacketSet)
404 {
405 txLength = mTxPacket->mLength;
406 }
407 else
408 {
409 ExitNow(error = kErrorInvalidArgs);
410 }
411
412 VerifyOrExit((txLength >= OT_RADIO_FRAME_MIN_SIZE) && (txLength <= OT_RADIO_FRAME_MAX_SIZE),
413 error = kErrorInvalidArgs);
414 mTxLen = txLength;
415
416 mRepeatActive = true;
417 uint32_t now = otPlatAlarmMilliGetNow();
418 otPlatAlarmMilliStartAt(&GetInstance(), now, mTxPeriod);
419 }
420
421 exit:
422 return error;
423 }
424
425 Error Diags::ProcessSend(uint8_t aArgsLength, char *aArgs[])
426 {
427 Error error = kErrorNone;
428 uint32_t txPackets;
429 uint8_t txLength;
430
431 VerifyOrExit(aArgsLength >= 1, error = kErrorInvalidArgs);
432
433 if (StringMatch(aArgs[0], "async"))
434 {
435 aArgs++;
436 aArgsLength--;
437 VerifyOrExit(aArgsLength >= 1, error = kErrorInvalidArgs);
438 mIsAsyncSend = true;
439 }
440 else
441 {
442 mIsAsyncSend = false;
443 }
444
445 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[0], txPackets));
446 mTxPackets = txPackets;
447
448 if (aArgsLength >= 2)
449 {
450 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[1], txLength));
451 mIsTxPacketSet = false;
452 }
453 else if (mIsTxPacketSet)
454 {
455 txLength = mTxPacket->mLength;
456 }
457 else
458 {
459 ExitNow(error = kErrorInvalidArgs);
460 }
461
462 VerifyOrExit(txLength <= OT_RADIO_FRAME_MAX_SIZE, error = kErrorInvalidArgs);
463 VerifyOrExit(txLength >= OT_RADIO_FRAME_MIN_SIZE, error = kErrorInvalidArgs);
464 mTxLen = txLength;
465
466 SuccessOrExit(error = TransmitPacket());
467
468 if (!mIsAsyncSend)
469 {
470 error = kErrorPending;
471 }
472
473 exit:
474 return error;
475 }
476
477 Error Diags::ProcessStart(uint8_t aArgsLength, char *aArgs[])
478 {
479 OT_UNUSED_VARIABLE(aArgsLength);
480 OT_UNUSED_VARIABLE(aArgs);
481
482 Error error = kErrorNone;
483
484 #if OPENTHREAD_FTD || OPENTHREAD_MTD
485 VerifyOrExit(!Get<ThreadNetif>().IsUp(), error = kErrorInvalidState);
486 #endif
487
488 otPlatDiagChannelSet(mChannel);
489 otPlatDiagTxPowerSet(mTxPower);
490
491 IgnoreError(Get<Radio>().Enable());
492 Get<Radio>().SetPromiscuous(true);
493 Get<Mac::SubMac>().SetRxOnWhenIdle(true);
494 otPlatAlarmMilliStop(&GetInstance());
495 SuccessOrExit(error = Get<Radio>().Receive(mChannel));
496 SuccessOrExit(error = Get<Radio>().SetTransmitPower(mTxPower));
497 otPlatDiagModeSet(true);
498 mStats.Clear();
499
500 exit:
501 return error;
502 }
503
504 void Diags::OutputStats(void)
505 {
506 Output("received packets: %lu\r\n"
507 "sent success packets: %lu\r\n"
508 "sent error cca packets: %lu\r\n"
509 "sent error abort packets: %lu\r\n"
510 "sent error invalid state packets: %lu\r\n"
511 "sent error others packets: %lu\r\n"
512 "first received packet: rssi=%d, lqi=%u\r\n"
513 "last received packet: rssi=%d, lqi=%u\r\n",
514 ToUlong(mStats.mReceivedPackets), ToUlong(mStats.mSentSuccessPackets), ToUlong(mStats.mSentErrorCcaPackets),
515 ToUlong(mStats.mSentErrorAbortPackets), ToUlong(mStats.mSentErrorInvalidStatePackets),
516 ToUlong(mStats.mSentErrorOthersPackets), mStats.mFirstRssi, mStats.mFirstLqi, mStats.mLastRssi,
517 mStats.mLastLqi);
518 }
519
520 Error Diags::ProcessStats(uint8_t aArgsLength, char *aArgs[])
521 {
522 Error error = kErrorNone;
523
524 if ((aArgsLength == 1) && StringMatch(aArgs[0], "clear"))
525 {
526 mStats.Clear();
527 }
528 else
529 {
530 VerifyOrExit(aArgsLength == 0, error = kErrorInvalidArgs);
531 OutputStats();
532 }
533
534 exit:
535 return error;
536 }
537
538 Error Diags::ProcessStop(uint8_t aArgsLength, char *aArgs[])
539 {
540 OT_UNUSED_VARIABLE(aArgsLength);
541 OT_UNUSED_VARIABLE(aArgs);
542
543 otPlatAlarmMilliStop(&GetInstance());
544 otPlatDiagModeSet(false);
545 Get<Radio>().SetPromiscuous(false);
546 Get<Mac::SubMac>().SetRxOnWhenIdle(false);
547
548 return kErrorNone;
549 }
550
551 Error Diags::TransmitPacket(void)
552 {
553 Error error = kErrorNone;
554 mTxPacket->mChannel = mChannel;
555
556 if (mIsTxPacketSet)
557 {
558 // The `mInfo.mTxInfo.mIsHeaderUpdated` field may be updated by the radio driver after the frame is sent,
559 // set the `mInfo.mTxInfo.mIsHeaderUpdated` field before transmitting the frame.
560 mTxPacket->mInfo.mTxInfo.mIsHeaderUpdated = mIsHeaderUpdated;
561 }
562 else
563 {
564 ResetTxPacket();
565 mTxPacket->mLength = mTxLen;
566
567 for (uint8_t i = 0; i < mTxLen; i++)
568 {
569 mTxPacket->mPsdu[i] = i;
570 }
571 }
572
573 mDiagSendOn = true;
574 error = Get<Radio>().Transmit(*static_cast<Mac::TxFrame *>(mTxPacket));
575
576 if (error == kErrorInvalidState)
577 {
578 mStats.mSentErrorInvalidStatePackets++;
579 }
580
581 return error;
582 }
583
584 Error Diags::ParseReceiveConfigFormat(const char *aFormat, ReceiveConfig &aConfig)
585 {
586 Error error = kErrorNone;
587
588 VerifyOrExit(aFormat != nullptr, error = kErrorInvalidArgs);
589
590 for (const char *arg = aFormat; *arg != '\0'; arg++)
591 {
592 switch (*arg)
593 {
594 case 'r':
595 aConfig.mShowRssi = true;
596 break;
597
598 case 'l':
599 aConfig.mShowLqi = true;
600 break;
601
602 case 'p':
603 aConfig.mShowPsdu = true;
604 break;
605
606 default:
607 ExitNow(error = OT_ERROR_INVALID_ARGS);
608 }
609 }
610
611 exit:
612 return error;
613 }
614
615 Error Diags::RadioReceive(void)
616 {
617 Error error;
618
619 SuccessOrExit(error = Get<Radio>().Receive(mChannel));
620 SuccessOrExit(error = Get<Radio>().SetTransmitPower(mTxPower));
621 otPlatDiagChannelSet(mChannel);
622 otPlatDiagTxPowerSet(mTxPower);
623
624 exit:
625 return error;
626 }
627
628 Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[])
629 {
630 Error error = kErrorInvalidArgs;
631
632 VerifyOrExit(aArgsLength > 0, error = kErrorInvalidArgs);
633
634 if (StringMatch(aArgs[0], "sleep"))
635 {
636 SuccessOrExit(error = Get<Radio>().Sleep());
637 }
638 else if (StringMatch(aArgs[0], "receive"))
639 {
640 ReceiveConfig receiveConfig;
641
642 aArgs++;
643 aArgsLength--;
644
645 if (aArgsLength == 0)
646 {
647 SuccessOrExit(error = RadioReceive());
648 ExitNow();
649 }
650
651 if (StringMatch(aArgs[0], "filter"))
652 {
653 aArgs++;
654 aArgsLength--;
655
656 VerifyOrExit(aArgsLength > 0);
657
658 if (StringMatch(aArgs[0], "enable"))
659 {
660 mReceiveConfig.mIsFilterEnabled = true;
661 error = kErrorNone;
662 }
663 else if (StringMatch(aArgs[0], "disable"))
664 {
665 mReceiveConfig.mIsFilterEnabled = false;
666 error = kErrorNone;
667 }
668 else
669 {
670 Mac::Address dstAddress;
671
672 if (StringMatch(aArgs[0], "-"))
673 {
674 dstAddress.SetNone();
675 error = kErrorNone;
676 }
677 else if (strlen(aArgs[0]) == 2 * sizeof(Mac::ExtAddress))
678 {
679 Mac::ExtAddress extAddress;
680
681 SuccessOrExit(error = Utils::CmdLineParser::ParseAsHexString(aArgs[0], extAddress.m8));
682 mReceiveConfig.mFilterAddress.SetExtended(extAddress);
683 }
684 else
685 {
686 Mac::ShortAddress shortAddress;
687
688 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint16(aArgs[0], shortAddress));
689 mReceiveConfig.mFilterAddress.SetShort(shortAddress);
690 }
691 }
692
693 ExitNow();
694 }
695
696 if (StringMatch(aArgs[0], "async"))
697 {
698 aArgs++;
699 aArgsLength--;
700 receiveConfig.mIsAsyncCommand = true;
701 }
702
703 VerifyOrExit(aArgsLength > 0);
704 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint16(aArgs[0], receiveConfig.mNumFrames));
705 aArgs++;
706 aArgsLength--;
707
708 if (aArgsLength > 0)
709 {
710 SuccessOrExit(error = ParseReceiveConfigFormat(aArgs[0], receiveConfig));
711 }
712
713 SuccessOrExit(error = RadioReceive());
714
715 mReceiveConfig.mIsEnabled = true;
716 mReceiveConfig.mIsAsyncCommand = receiveConfig.mIsAsyncCommand;
717 mReceiveConfig.mShowRssi = receiveConfig.mShowRssi;
718 mReceiveConfig.mShowLqi = receiveConfig.mShowLqi;
719 mReceiveConfig.mShowPsdu = receiveConfig.mShowPsdu;
720 mReceiveConfig.mReceiveCount = receiveConfig.mReceiveCount;
721 mReceiveConfig.mNumFrames = receiveConfig.mNumFrames;
722
723 if (!mReceiveConfig.mIsAsyncCommand)
724 {
725 error = kErrorPending;
726 }
727 }
728 else if (StringMatch(aArgs[0], "state"))
729 {
730 otRadioState state = Get<Radio>().GetState();
731
732 error = kErrorNone;
733
734 switch (state)
735 {
736 case OT_RADIO_STATE_DISABLED:
737 Output("disabled\r\n");
738 break;
739
740 case OT_RADIO_STATE_SLEEP:
741 Output("sleep\r\n");
742 break;
743
744 case OT_RADIO_STATE_RECEIVE:
745 Output("receive\r\n");
746 break;
747
748 case OT_RADIO_STATE_TRANSMIT:
749 Output("transmit\r\n");
750 break;
751
752 default:
753 Output("invalid\r\n");
754 break;
755 }
756 }
757 else if (StringMatch(aArgs[0], "enable"))
758 {
759 SuccessOrExit(error = Get<Radio>().Enable());
760 }
761 else if (StringMatch(aArgs[0], "disable"))
762 {
763 SuccessOrExit(error = Get<Radio>().Disable());
764 }
765
766 exit:
767 return error;
768 }
769
770 extern "C" void otPlatDiagAlarmFired(otInstance *aInstance) { AsCoreType(aInstance).Get<Diags>().AlarmFired(); }
771
772 void Diags::AlarmFired(void)
773 {
774 if (mRepeatActive)
775 {
776 uint32_t now = otPlatAlarmMilliGetNow();
777
778 IgnoreError(TransmitPacket());
779 otPlatAlarmMilliStartAt(&GetInstance(), now, mTxPeriod);
780 }
781 else
782 {
783 otPlatDiagAlarmCallback(&GetInstance());
784 }
785 }
786
787 void Diags::OutputReceivedFrame(const otRadioFrame *aFrame)
788 {
789 VerifyOrExit(mReceiveConfig.mIsEnabled && (aFrame != nullptr));
790
791 Output("%u", mReceiveConfig.mReceiveCount++);
792
793 if (mReceiveConfig.mShowRssi)
794 {
795 Output(", rssi:%d", aFrame->mInfo.mRxInfo.mRssi);
796 }
797
798 if (mReceiveConfig.mShowLqi)
799 {
800 Output(", lqi:%u", aFrame->mInfo.mRxInfo.mLqi);
801 }
802
803 if (mReceiveConfig.mShowPsdu)
804 {
805 static constexpr uint16_t kBufSize = 255;
806 char buf[kBufSize];
807 StringWriter writer(buf, sizeof(buf));
808
809 writer.AppendHexBytes(aFrame->mPsdu, aFrame->mLength);
810 Output(", len:%u, psdu:%s", aFrame->mLength, buf);
811 }
812
813 Output("\r\n");
814
815 if (mReceiveConfig.mReceiveCount >= mReceiveConfig.mNumFrames)
816 {
817 mReceiveConfig.mIsEnabled = false;
818
819 if (!mReceiveConfig.mIsAsyncCommand)
820 {
821 Output("OT_ERROR_NONE");
822 }
823 }
824
825 exit:
826 return;
827 }
828
829 void Diags::ReceiveDone(otRadioFrame *aFrame, Error aError)
830 {
831 if (aError == kErrorNone)
832 {
833 if (mReceiveConfig.mIsFilterEnabled)
834 {
835 VerifyOrExit(ShouldHandleReceivedFrame(*aFrame));
836 }
837
838 OutputReceivedFrame(aFrame);
839
840 // for sensitivity test, only record the rssi and lqi for the first and last packet
841 if (mStats.mReceivedPackets == 0)
842 {
843 mStats.mFirstRssi = aFrame->mInfo.mRxInfo.mRssi;
844 mStats.mFirstLqi = aFrame->mInfo.mRxInfo.mLqi;
845 }
846
847 mStats.mLastRssi = aFrame->mInfo.mRxInfo.mRssi;
848 mStats.mLastLqi = aFrame->mInfo.mRxInfo.mLqi;
849
850 mStats.mReceivedPackets++;
851 }
852
853 otPlatDiagRadioReceived(&GetInstance(), aFrame, aError);
854
855 exit:
856 return;
857 }
858
859 void Diags::TransmitDone(Error aError)
860 {
861 VerifyOrExit(mDiagSendOn);
862 mDiagSendOn = false;
863
864 switch (aError)
865 {
866 case kErrorNone:
867 mStats.mSentSuccessPackets++;
868 break;
869
870 case kErrorChannelAccessFailure:
871 mStats.mSentErrorCcaPackets++;
872 break;
873
874 case kErrorAbort:
875 mStats.mSentErrorAbortPackets++;
876 break;
877
878 default:
879 mStats.mSentErrorOthersPackets++;
880 break;
881 }
882
883 VerifyOrExit(!mRepeatActive && (mTxPackets > 0));
884
885 if (mTxPackets > 1)
886 {
887 mTxPackets--;
888 IgnoreError(TransmitPacket());
889 }
890 else
891 {
892 mTxPackets = 0;
893
894 if (!mIsAsyncSend)
895 {
896 Output("OT_ERROR_NONE");
897 }
898 }
899
900 exit:
901 return;
902 }
903
904 bool Diags::ShouldHandleReceivedFrame(const otRadioFrame &aFrame) const
905 {
906 bool ret = false;
907 const Mac::RxFrame &frame = static_cast<const Mac::RxFrame &>(aFrame);
908 Mac::Address dstAddress;
909
910 VerifyOrExit(frame.GetDstAddr(dstAddress) == kErrorNone);
911 VerifyOrExit(dstAddress == mReceiveConfig.mFilterAddress);
912 ret = true;
913
914 exit:
915 return ret;
916 }
917
918 #endif // OPENTHREAD_RADIO
919
ProcessContinuousWave(uint8_t aArgsLength,char * aArgs[])920 Error Diags::ProcessContinuousWave(uint8_t aArgsLength, char *aArgs[])
921 {
922 Error error = kErrorInvalidArgs;
923
924 VerifyOrExit(aArgsLength > 0, error = kErrorInvalidArgs);
925
926 if (StringMatch(aArgs[0], "start"))
927 {
928 SuccessOrExit(error = otPlatDiagRadioTransmitCarrier(&GetInstance(), true));
929 }
930 else if (StringMatch(aArgs[0], "stop"))
931 {
932 SuccessOrExit(error = otPlatDiagRadioTransmitCarrier(&GetInstance(), false));
933 }
934
935 exit:
936 return error;
937 }
938
ProcessStream(uint8_t aArgsLength,char * aArgs[])939 Error Diags::ProcessStream(uint8_t aArgsLength, char *aArgs[])
940 {
941 Error error = kErrorInvalidArgs;
942
943 VerifyOrExit(aArgsLength > 0, error = kErrorInvalidArgs);
944
945 if (StringMatch(aArgs[0], "start"))
946 {
947 error = otPlatDiagRadioTransmitStream(&GetInstance(), true);
948 }
949 else if (StringMatch(aArgs[0], "stop"))
950 {
951 error = otPlatDiagRadioTransmitStream(&GetInstance(), false);
952 }
953
954 exit:
955 return error;
956 }
957
GetPowerSettings(uint8_t aChannel,PowerSettings & aPowerSettings)958 Error Diags::GetPowerSettings(uint8_t aChannel, PowerSettings &aPowerSettings)
959 {
960 aPowerSettings.mRawPowerSetting.mLength = RawPowerSetting::kMaxDataSize;
961 return otPlatDiagRadioGetPowerSettings(&GetInstance(), aChannel, &aPowerSettings.mTargetPower,
962 &aPowerSettings.mActualPower, aPowerSettings.mRawPowerSetting.mData,
963 &aPowerSettings.mRawPowerSetting.mLength);
964 }
965
ProcessPowerSettings(uint8_t aArgsLength,char * aArgs[])966 Error Diags::ProcessPowerSettings(uint8_t aArgsLength, char *aArgs[])
967 {
968 Error error = kErrorInvalidArgs;
969 uint8_t channel;
970 PowerSettings powerSettings;
971
972 if (aArgsLength == 0)
973 {
974 bool isPrePowerSettingsValid = false;
975 uint8_t preChannel = 0;
976 PowerSettings prePowerSettings;
977
978 Output("| StartCh | EndCh | TargetPower | ActualPower | RawPowerSetting |\r\n"
979 "+---------+-------+-------------+-------------+-----------------+\r\n");
980
981 for (channel = Radio::kChannelMin; channel <= Radio::kChannelMax + 1; channel++)
982 {
983 error = (channel == Radio::kChannelMax + 1) ? kErrorNotFound : GetPowerSettings(channel, powerSettings);
984
985 if (isPrePowerSettingsValid && ((powerSettings != prePowerSettings) || (error != kErrorNone)))
986 {
987 Output("| %7u | %5u | %11d | %11d | %15s |\r\n", preChannel, channel - 1, prePowerSettings.mTargetPower,
988 prePowerSettings.mActualPower, prePowerSettings.mRawPowerSetting.ToString().AsCString());
989 isPrePowerSettingsValid = false;
990 }
991
992 if ((error == kErrorNone) && (!isPrePowerSettingsValid))
993 {
994 preChannel = channel;
995 prePowerSettings = powerSettings;
996 isPrePowerSettingsValid = true;
997 }
998 }
999
1000 error = kErrorNone;
1001 }
1002 else if (aArgsLength == 1)
1003 {
1004 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(aArgs[0], channel));
1005 VerifyOrExit(IsChannelValid(channel), error = kErrorInvalidArgs);
1006
1007 SuccessOrExit(error = GetPowerSettings(channel, powerSettings));
1008 Output("TargetPower(0.01dBm): %d\r\nActualPower(0.01dBm): %d\r\nRawPowerSetting: %s\r\n",
1009 powerSettings.mTargetPower, powerSettings.mActualPower,
1010 powerSettings.mRawPowerSetting.ToString().AsCString());
1011 }
1012
1013 exit:
1014 return error;
1015 }
1016
GetRawPowerSetting(RawPowerSetting & aRawPowerSetting)1017 Error Diags::GetRawPowerSetting(RawPowerSetting &aRawPowerSetting)
1018 {
1019 aRawPowerSetting.mLength = RawPowerSetting::kMaxDataSize;
1020 return otPlatDiagRadioGetRawPowerSetting(&GetInstance(), aRawPowerSetting.mData, &aRawPowerSetting.mLength);
1021 }
1022
ProcessRawPowerSetting(uint8_t aArgsLength,char * aArgs[])1023 Error Diags::ProcessRawPowerSetting(uint8_t aArgsLength, char *aArgs[])
1024 {
1025 Error error = kErrorInvalidArgs;
1026 RawPowerSetting setting;
1027
1028 if (aArgsLength == 0)
1029 {
1030 SuccessOrExit(error = GetRawPowerSetting(setting));
1031 Output("%s\r\n", setting.ToString().AsCString());
1032 }
1033 else if (StringMatch(aArgs[0], "enable"))
1034 {
1035 SuccessOrExit(error = otPlatDiagRadioRawPowerSettingEnable(&GetInstance(), true));
1036 }
1037 else if (StringMatch(aArgs[0], "disable"))
1038 {
1039 SuccessOrExit(error = otPlatDiagRadioRawPowerSettingEnable(&GetInstance(), false));
1040 }
1041 else
1042 {
1043 setting.mLength = RawPowerSetting::kMaxDataSize;
1044 SuccessOrExit(error = Utils::CmdLineParser::ParseAsHexString(aArgs[0], setting.mLength, setting.mData));
1045 SuccessOrExit(error = otPlatDiagRadioSetRawPowerSetting(&GetInstance(), setting.mData, setting.mLength));
1046 }
1047
1048 exit:
1049 return error;
1050 }
1051
ProcessGpio(uint8_t aArgsLength,char * aArgs[])1052 Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[])
1053 {
1054 Error error = kErrorInvalidArgs;
1055 uint32_t gpio;
1056 bool level;
1057 otGpioMode mode;
1058
1059 if ((aArgsLength == 2) && StringMatch(aArgs[0], "get"))
1060 {
1061 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[1], gpio));
1062 SuccessOrExit(error = otPlatDiagGpioGet(gpio, &level));
1063 Output("%d\r\n", level);
1064 }
1065 else if ((aArgsLength == 3) && StringMatch(aArgs[0], "set"))
1066 {
1067 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[1], gpio));
1068 SuccessOrExit(error = Utils::CmdLineParser::ParseAsBool(aArgs[2], level));
1069 SuccessOrExit(error = otPlatDiagGpioSet(gpio, level));
1070 }
1071 else if ((aArgsLength >= 2) && StringMatch(aArgs[0], "mode"))
1072 {
1073 SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(aArgs[1], gpio));
1074
1075 if (aArgsLength == 2)
1076 {
1077 SuccessOrExit(error = otPlatDiagGpioGetMode(gpio, &mode));
1078 if (mode == OT_GPIO_MODE_INPUT)
1079 {
1080 Output("in\r\n");
1081 }
1082 else if (mode == OT_GPIO_MODE_OUTPUT)
1083 {
1084 Output("out\r\n");
1085 }
1086 }
1087 else if ((aArgsLength == 3) && StringMatch(aArgs[2], "in"))
1088 {
1089 SuccessOrExit(error = otPlatDiagGpioSetMode(gpio, OT_GPIO_MODE_INPUT));
1090 }
1091 else if ((aArgsLength == 3) && StringMatch(aArgs[2], "out"))
1092 {
1093 SuccessOrExit(error = otPlatDiagGpioSetMode(gpio, OT_GPIO_MODE_OUTPUT));
1094 }
1095 }
1096
1097 exit:
1098 return error;
1099 }
1100
IsChannelValid(uint8_t aChannel)1101 bool Diags::IsChannelValid(uint8_t aChannel)
1102 {
1103 return (aChannel >= Radio::kChannelMin && aChannel <= Radio::kChannelMax);
1104 }
1105
ParseCmd(char * aString,uint8_t & aArgsLength,char * aArgs[])1106 Error Diags::ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[])
1107 {
1108 Error error;
1109 Utils::CmdLineParser::Arg args[kMaxArgs + 1];
1110
1111 SuccessOrExit(error = Utils::CmdLineParser::ParseCmd(aString, args));
1112 aArgsLength = Utils::CmdLineParser::Arg::GetArgsLength(args);
1113 Utils::CmdLineParser::Arg::CopyArgsToStringArray(args, aArgs);
1114
1115 exit:
1116 return error;
1117 }
1118
ProcessLine(const char * aString)1119 Error Diags::ProcessLine(const char *aString)
1120 {
1121 constexpr uint16_t kMaxCommandBuffer = OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE;
1122
1123 Error error = kErrorNone;
1124 char buffer[kMaxCommandBuffer];
1125 char *args[kMaxArgs];
1126 uint8_t argCount = 0;
1127
1128 VerifyOrExit(StringLength(aString, kMaxCommandBuffer) < kMaxCommandBuffer, error = kErrorNoBufs);
1129
1130 strcpy(buffer, aString);
1131 error = ParseCmd(buffer, argCount, args);
1132
1133 exit:
1134
1135 switch (error)
1136 {
1137 case kErrorNone:
1138 error = ProcessCmd(argCount, &args[0]);
1139 break;
1140
1141 case kErrorNoBufs:
1142 Output("failed: command string too long\r\n");
1143 break;
1144
1145 case kErrorInvalidArgs:
1146 Output("failed: command string contains too many arguments\r\n");
1147 break;
1148
1149 default:
1150 Output("failed to parse command string\r\n");
1151 break;
1152 }
1153
1154 return error;
1155 }
1156
ProcessCmd(uint8_t aArgsLength,char * aArgs[])1157 Error Diags::ProcessCmd(uint8_t aArgsLength, char *aArgs[])
1158 {
1159 Error error = kErrorNone;
1160
1161 // This `rcp` command is for debugging and testing only, building only when NDEBUG is not defined
1162 // so that it will be excluded from release build.
1163 #if OPENTHREAD_RADIO && !defined(NDEBUG)
1164 if (aArgsLength > 0 && StringMatch(aArgs[0], "rcp"))
1165 {
1166 aArgs++;
1167 aArgsLength--;
1168 }
1169 #endif
1170
1171 if (aArgsLength == 0)
1172 {
1173 Output("diagnostics mode is %s\r\n", otPlatDiagModeGet() ? "enabled" : "disabled");
1174 ExitNow();
1175 }
1176
1177 if (!otPlatDiagModeGet() && !StringMatch(aArgs[0], "start"))
1178 {
1179 Output("diagnostics mode is disabled\r\n");
1180 ExitNow(error = kErrorInvalidState);
1181 }
1182
1183 for (const Command &command : sCommands)
1184 {
1185 if (StringMatch(aArgs[0], command.mName))
1186 {
1187 error = (this->*command.mCommand)(aArgsLength - 1, (aArgsLength > 1) ? &aArgs[1] : nullptr);
1188 ExitNow();
1189 }
1190 }
1191
1192 // more platform specific features will be processed under platform layer
1193 error = otPlatDiagProcess(&GetInstance(), aArgsLength, aArgs);
1194
1195 exit:
1196 // Add more platform specific diagnostics features here.
1197 if (error == kErrorInvalidCommand && aArgsLength > 1)
1198 {
1199 Output("diag feature '%s' is not supported\r\n", aArgs[0]);
1200 }
1201
1202 return error;
1203 }
1204
SetOutputCallback(otDiagOutputCallback aCallback,void * aContext)1205 void Diags::SetOutputCallback(otDiagOutputCallback aCallback, void *aContext)
1206 {
1207 mOutputCallback = aCallback;
1208 mOutputContext = aContext;
1209
1210 otPlatDiagSetOutputCallback(&GetInstance(), aCallback, aContext);
1211 }
1212
Output(const char * aFormat,...)1213 void Diags::Output(const char *aFormat, ...)
1214 {
1215 va_list args;
1216
1217 va_start(args, aFormat);
1218
1219 if (mOutputCallback != nullptr)
1220 {
1221 mOutputCallback(aFormat, args, mOutputContext);
1222 }
1223
1224 va_end(args);
1225 }
1226
IsEnabled(void)1227 bool Diags::IsEnabled(void) { return otPlatDiagModeGet(); }
1228
1229 } // namespace FactoryDiags
1230 } // namespace ot
1231
otPlatDiagGpioSet(uint32_t aGpio,bool aValue)1232 OT_TOOL_WEAK otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
1233 {
1234 OT_UNUSED_VARIABLE(aGpio);
1235 OT_UNUSED_VARIABLE(aValue);
1236
1237 return OT_ERROR_NOT_IMPLEMENTED;
1238 }
1239
otPlatDiagGpioGet(uint32_t aGpio,bool * aValue)1240 OT_TOOL_WEAK otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
1241 {
1242 OT_UNUSED_VARIABLE(aGpio);
1243 OT_UNUSED_VARIABLE(aValue);
1244
1245 return OT_ERROR_NOT_IMPLEMENTED;
1246 }
1247
otPlatDiagGpioSetMode(uint32_t aGpio,otGpioMode aMode)1248 OT_TOOL_WEAK otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode)
1249 {
1250 OT_UNUSED_VARIABLE(aGpio);
1251 OT_UNUSED_VARIABLE(aMode);
1252
1253 return OT_ERROR_NOT_IMPLEMENTED;
1254 }
1255
otPlatDiagGpioGetMode(uint32_t aGpio,otGpioMode * aMode)1256 OT_TOOL_WEAK otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode)
1257 {
1258 OT_UNUSED_VARIABLE(aGpio);
1259 OT_UNUSED_VARIABLE(aMode);
1260
1261 return OT_ERROR_NOT_IMPLEMENTED;
1262 }
1263
otPlatDiagRadioSetRawPowerSetting(otInstance * aInstance,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)1264 OT_TOOL_WEAK otError otPlatDiagRadioSetRawPowerSetting(otInstance *aInstance,
1265 const uint8_t *aRawPowerSetting,
1266 uint16_t aRawPowerSettingLength)
1267 {
1268 OT_UNUSED_VARIABLE(aInstance);
1269 OT_UNUSED_VARIABLE(aRawPowerSetting);
1270 OT_UNUSED_VARIABLE(aRawPowerSettingLength);
1271
1272 return OT_ERROR_NOT_IMPLEMENTED;
1273 }
1274
otPlatDiagRadioGetRawPowerSetting(otInstance * aInstance,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)1275 OT_TOOL_WEAK otError otPlatDiagRadioGetRawPowerSetting(otInstance *aInstance,
1276 uint8_t *aRawPowerSetting,
1277 uint16_t *aRawPowerSettingLength)
1278 {
1279 OT_UNUSED_VARIABLE(aInstance);
1280 OT_UNUSED_VARIABLE(aRawPowerSetting);
1281 OT_UNUSED_VARIABLE(aRawPowerSettingLength);
1282
1283 return OT_ERROR_NOT_IMPLEMENTED;
1284 }
1285
otPlatDiagRadioRawPowerSettingEnable(otInstance * aInstance,bool aEnable)1286 OT_TOOL_WEAK otError otPlatDiagRadioRawPowerSettingEnable(otInstance *aInstance, bool aEnable)
1287 {
1288 OT_UNUSED_VARIABLE(aInstance);
1289 OT_UNUSED_VARIABLE(aEnable);
1290
1291 return OT_ERROR_NOT_IMPLEMENTED;
1292 }
1293
otPlatDiagRadioTransmitCarrier(otInstance * aInstance,bool aEnable)1294 OT_TOOL_WEAK otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable)
1295 {
1296 OT_UNUSED_VARIABLE(aInstance);
1297 OT_UNUSED_VARIABLE(aEnable);
1298
1299 return OT_ERROR_NOT_IMPLEMENTED;
1300 }
1301
otPlatDiagRadioTransmitStream(otInstance * aInstance,bool aEnable)1302 OT_TOOL_WEAK otError otPlatDiagRadioTransmitStream(otInstance *aInstance, bool aEnable)
1303 {
1304 OT_UNUSED_VARIABLE(aInstance);
1305 OT_UNUSED_VARIABLE(aEnable);
1306
1307 return OT_ERROR_NOT_IMPLEMENTED;
1308 }
1309
otPlatDiagRadioGetPowerSettings(otInstance * aInstance,uint8_t aChannel,int16_t * aTargetPower,int16_t * aActualPower,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)1310 OT_TOOL_WEAK otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance,
1311 uint8_t aChannel,
1312 int16_t *aTargetPower,
1313 int16_t *aActualPower,
1314 uint8_t *aRawPowerSetting,
1315 uint16_t *aRawPowerSettingLength)
1316 {
1317 OT_UNUSED_VARIABLE(aInstance);
1318 OT_UNUSED_VARIABLE(aChannel);
1319 OT_UNUSED_VARIABLE(aTargetPower);
1320 OT_UNUSED_VARIABLE(aActualPower);
1321 OT_UNUSED_VARIABLE(aRawPowerSetting);
1322 OT_UNUSED_VARIABLE(aRawPowerSettingLength);
1323
1324 return OT_ERROR_NOT_IMPLEMENTED;
1325 }
1326
1327 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
1328