1 /*
2 * Copyright (c) 2020, 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 radio apis on posix platform.
32 */
33
34 #include "platform-posix.h"
35
36 #include <string.h>
37
38 #include <openthread/logging.h>
39 #include <openthread/platform/diag.h>
40
41 #include "common/code_utils.hpp"
42 #include "common/new.hpp"
43 #include "posix/platform/radio.hpp"
44 #include "posix/platform/spinel_driver_getter.hpp"
45 #include "posix/platform/spinel_manager.hpp"
46 #include "utils/parse_cmdline.hpp"
47
48 #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
49 #include "configuration.hpp"
50 static ot::Posix::Configuration sConfig;
51 #endif
52
53 static ot::Posix::Radio sRadio;
54
55 namespace ot {
56 namespace Posix {
57
58 namespace {
platformRadioInit(const char * aUrl)59 extern "C" void platformRadioInit(const char *aUrl) { sRadio.Init(aUrl); }
60 } // namespace
61
62 const char Radio::kLogModuleName[] = "Radio";
63
Radio(void)64 Radio::Radio(void)
65 : mRadioUrl(nullptr)
66 , mRadioSpinel()
67 #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
68 , mRcpCapsDiag(mRadioSpinel)
69 #endif
70 {
71 }
72
Init(const char * aUrl)73 void Radio::Init(const char *aUrl)
74 {
75 bool resetRadio;
76 bool skipCompatibilityCheck;
77 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
78 bool aEnableRcpTimeSync = true;
79 #else
80 bool aEnableRcpTimeSync = false;
81 #endif
82 struct ot::Spinel::RadioSpinelCallbacks callbacks;
83
84 mRadioUrl.Init(aUrl);
85 VerifyOrDie(mRadioUrl.GetPath() != nullptr, OT_EXIT_INVALID_ARGUMENTS);
86
87 memset(&callbacks, 0, sizeof(callbacks));
88 #if OPENTHREAD_CONFIG_DIAG_ENABLE
89 callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
90 callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
91 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
92 callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
93 callbacks.mBusLatencyChanged = otPlatRadioBusLatencyChanged;
94 callbacks.mReceiveDone = otPlatRadioReceiveDone;
95 callbacks.mTransmitDone = otPlatRadioTxDone;
96 callbacks.mTxStarted = otPlatRadioTxStarted;
97
98 resetRadio = !mRadioUrl.HasParam("no-reset");
99 skipCompatibilityCheck = mRadioUrl.HasParam("skip-rcp-compatibility-check");
100
101 mRadioSpinel.SetCallbacks(callbacks);
102 mRadioSpinel.Init(skipCompatibilityCheck, resetRadio, &GetSpinelDriver(),
103 (skipCompatibilityCheck ? 0 : kRequiredRadioCaps), aEnableRcpTimeSync);
104
105 ProcessRadioUrl(mRadioUrl);
106 }
107
ProcessRadioUrl(const RadioUrl & aRadioUrl)108 void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl)
109 {
110 const char *region;
111 int8_t value;
112
113 if (aRadioUrl.HasParam("ncp-dataset"))
114 {
115 LogCrit("The argument \"ncp-dataset\" is no longer supported");
116 DieNow(OT_ERROR_FAILED);
117 }
118
119 if (aRadioUrl.HasParam("fem-lnagain"))
120 {
121 SuccessOrDie(aRadioUrl.ParseInt8("fem-lnagain", value));
122 SuccessOrDie(mRadioSpinel.SetFemLnaGain(value));
123 }
124
125 if (aRadioUrl.HasParam("cca-threshold"))
126 {
127 SuccessOrDie(aRadioUrl.ParseInt8("cca-threshold", value));
128 SuccessOrDie(mRadioSpinel.SetCcaEnergyDetectThreshold(value));
129 }
130
131 if ((region = aRadioUrl.GetValue("region")) != nullptr)
132 {
133 uint16_t regionCode;
134
135 VerifyOrDie(strnlen(region, 3) == 2, OT_EXIT_INVALID_ARGUMENTS);
136 regionCode = static_cast<uint16_t>(static_cast<uint16_t>(region[0]) << 8) + static_cast<uint16_t>(region[1]);
137 SuccessOrDie(otPlatRadioSetRegion(gInstance, regionCode));
138 }
139
140 if (aRadioUrl.HasParam("bus-latency"))
141 {
142 uint32_t busLatency;
143 SuccessOrDie(aRadioUrl.ParseUint32("bus-latency", busLatency));
144 mRadioSpinel.SetBusLatency(busLatency);
145 }
146
147 ProcessMaxPowerTable(aRadioUrl);
148
149 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
150 {
151 const char *enableCoex = aRadioUrl.GetValue("enable-coex");
152 if (enableCoex != nullptr)
153 {
154 SuccessOrDie(mRadioSpinel.SetCoexEnabled(enableCoex[0] != '0'));
155 }
156 }
157 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
158 }
159
ProcessMaxPowerTable(const RadioUrl & aRadioUrl)160 void Radio::ProcessMaxPowerTable(const RadioUrl &aRadioUrl)
161 {
162 OT_UNUSED_VARIABLE(aRadioUrl);
163
164 #if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
165 otError error;
166 constexpr int8_t kPowerDefault = 30; // Default power 1 watt (30 dBm).
167 const char *str = nullptr;
168 char *pSave = nullptr;
169 uint8_t channel = ot::Radio::kChannelMin;
170 int8_t power = kPowerDefault;
171 const char *maxPowerTable;
172
173 VerifyOrExit((maxPowerTable = aRadioUrl.GetValue("max-power-table")) != nullptr);
174
175 for (str = strtok_r(const_cast<char *>(maxPowerTable), ",", &pSave);
176 str != nullptr && channel <= ot::Radio::kChannelMax; str = strtok_r(nullptr, ",", &pSave))
177 {
178 power = static_cast<int8_t>(strtol(str, nullptr, 0));
179 error = mRadioSpinel.SetChannelMaxTransmitPower(channel, power);
180 VerifyOrDie((error == OT_ERROR_NONE) || (error == OT_ERROR_NOT_IMPLEMENTED), OT_EXIT_FAILURE);
181 if (error == OT_ERROR_NOT_IMPLEMENTED)
182 {
183 LogWarn("The RCP doesn't support setting the max transmit power");
184 }
185
186 ++channel;
187 }
188
189 // Use the last power if omitted.
190 while (channel <= ot::Radio::kChannelMax)
191 {
192 error = mRadioSpinel.SetChannelMaxTransmitPower(channel, power);
193 VerifyOrDie((error == OT_ERROR_NONE) || (error == OT_ERROR_NOT_IMPLEMENTED), OT_ERROR_FAILED);
194 if (error == OT_ERROR_NOT_IMPLEMENTED)
195 {
196 LogWarn("The RCP doesn't support setting the max transmit power");
197 }
198
199 ++channel;
200 }
201
202 VerifyOrDie(str == nullptr, OT_EXIT_INVALID_ARGUMENTS);
203
204 exit:
205 return;
206 #endif // OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
207 }
208
209 } // namespace Posix
210 } // namespace ot
211
GetRadioSpinel(void)212 ot::Spinel::RadioSpinel &GetRadioSpinel(void) { return sRadio.GetRadioSpinel(); }
213
214 #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
GetRcpCapsDiag(void)215 ot::Posix::RcpCapsDiag &GetRcpCapsDiag(void) { return sRadio.GetRcpCapsDiag(); }
216 #endif
217
platformRadioDeinit(void)218 void platformRadioDeinit(void) { GetRadioSpinel().Deinit(); }
219
platformRadioHandleStateChange(otInstance * aInstance,otChangedFlags aFlags)220 void platformRadioHandleStateChange(otInstance *aInstance, otChangedFlags aFlags)
221 {
222 if (OT_CHANGED_THREAD_NETIF_STATE & aFlags)
223 {
224 GetRadioSpinel().SetTimeSyncState(otIp6IsEnabled(aInstance));
225 }
226 }
227
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)228 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
229 {
230 OT_UNUSED_VARIABLE(aInstance);
231 SuccessOrDie(GetRadioSpinel().GetIeeeEui64(aIeeeEui64));
232 }
233
otPlatRadioSetPanId(otInstance * aInstance,uint16_t panid)234 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
235 {
236 OT_UNUSED_VARIABLE(aInstance);
237 SuccessOrDie(GetRadioSpinel().SetPanId(panid));
238 }
239
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aAddress)240 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
241 {
242 OT_UNUSED_VARIABLE(aInstance);
243 otExtAddress addr;
244
245 for (size_t i = 0; i < sizeof(addr); i++)
246 {
247 addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i];
248 }
249
250 SuccessOrDie(GetRadioSpinel().SetExtendedAddress(addr));
251 }
252
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aAddress)253 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
254 {
255 OT_UNUSED_VARIABLE(aInstance);
256 SuccessOrDie(GetRadioSpinel().SetShortAddress(aAddress));
257 }
258
otPlatRadioSetAlternateShortAddress(otInstance * aInstance,uint16_t aAddress)259 void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, uint16_t aAddress)
260 {
261 OT_UNUSED_VARIABLE(aInstance);
262 SuccessOrDie(GetRadioSpinel().SetAlternateShortAddress(aAddress));
263 }
264
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)265 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
266 {
267 OT_UNUSED_VARIABLE(aInstance);
268 SuccessOrDie(GetRadioSpinel().SetPromiscuous(aEnable));
269 }
270
otPlatRadioIsEnabled(otInstance * aInstance)271 bool otPlatRadioIsEnabled(otInstance *aInstance)
272 {
273 OT_UNUSED_VARIABLE(aInstance);
274 return GetRadioSpinel().IsEnabled();
275 }
276
otPlatRadioEnable(otInstance * aInstance)277 otError otPlatRadioEnable(otInstance *aInstance) { return GetRadioSpinel().Enable(aInstance); }
278
otPlatRadioDisable(otInstance * aInstance)279 otError otPlatRadioDisable(otInstance *aInstance)
280 {
281 OT_UNUSED_VARIABLE(aInstance);
282 return GetRadioSpinel().Disable();
283 }
284
otPlatRadioSleep(otInstance * aInstance)285 otError otPlatRadioSleep(otInstance *aInstance)
286 {
287 OT_UNUSED_VARIABLE(aInstance);
288 return GetRadioSpinel().Sleep();
289 }
290
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)291 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
292 {
293 OT_UNUSED_VARIABLE(aInstance);
294
295 otError error;
296
297 SuccessOrExit(error = GetRadioSpinel().Receive(aChannel));
298
299 exit:
300 return error;
301 }
302
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)303 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
304 {
305 OT_UNUSED_VARIABLE(aInstance);
306 return GetRadioSpinel().Transmit(*aFrame);
307 }
308
otPlatRadioGetTransmitBuffer(otInstance * aInstance)309 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
310 {
311 OT_UNUSED_VARIABLE(aInstance);
312 return &GetRadioSpinel().GetTransmitFrame();
313 }
314
otPlatRadioGetRssi(otInstance * aInstance)315 int8_t otPlatRadioGetRssi(otInstance *aInstance)
316 {
317 OT_UNUSED_VARIABLE(aInstance);
318 return GetRadioSpinel().GetRssi();
319 }
320
otPlatRadioGetCaps(otInstance * aInstance)321 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
322 {
323 OT_UNUSED_VARIABLE(aInstance);
324 return GetRadioSpinel().GetRadioCaps();
325 }
326
otPlatRadioGetVersionString(otInstance * aInstance)327 const char *otPlatRadioGetVersionString(otInstance *aInstance)
328 {
329 OT_UNUSED_VARIABLE(aInstance);
330 return GetRadioSpinel().GetVersion();
331 }
332
otPlatRadioGetPromiscuous(otInstance * aInstance)333 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
334 {
335 OT_UNUSED_VARIABLE(aInstance);
336 return GetRadioSpinel().IsPromiscuous();
337 }
338
platformRadioUpdateFdSet(otSysMainloopContext * aContext)339 void platformRadioUpdateFdSet(otSysMainloopContext *aContext)
340 {
341 uint64_t now = otPlatTimeGet();
342 uint64_t deadline = GetRadioSpinel().GetNextRadioTimeRecalcStart();
343
344 if (GetRadioSpinel().IsTransmitting())
345 {
346 uint64_t txRadioEndUs = GetRadioSpinel().GetTxRadioEndUs();
347
348 if (txRadioEndUs < deadline)
349 {
350 deadline = txRadioEndUs;
351 }
352 }
353
354 if (now < deadline)
355 {
356 uint64_t remain = deadline - now;
357
358 if (remain < (static_cast<uint64_t>(aContext->mTimeout.tv_sec) * OT_US_PER_S +
359 static_cast<uint64_t>(aContext->mTimeout.tv_usec)))
360 {
361 aContext->mTimeout.tv_sec = static_cast<time_t>(remain / OT_US_PER_S);
362 aContext->mTimeout.tv_usec = static_cast<suseconds_t>(remain % OT_US_PER_S);
363 }
364 }
365 else
366 {
367 aContext->mTimeout.tv_sec = 0;
368 aContext->mTimeout.tv_usec = 0;
369 }
370
371 if (GetRadioSpinel().IsTransmitDone())
372 {
373 aContext->mTimeout.tv_sec = 0;
374 aContext->mTimeout.tv_usec = 0;
375 }
376 }
377
378 #if OPENTHREAD_POSIX_VIRTUAL_TIME
virtualTimeRadioProcess(otInstance * aInstance,const struct VirtualTimeEvent * aEvent)379 void virtualTimeRadioProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent)
380 {
381 OT_UNUSED_VARIABLE(aInstance);
382 GetRadioSpinel().Process(aEvent);
383 }
384 #else
platformRadioProcess(otInstance * aInstance,const otSysMainloopContext * aContext)385 void platformRadioProcess(otInstance *aInstance, const otSysMainloopContext *aContext)
386 {
387 OT_UNUSED_VARIABLE(aInstance);
388
389 GetRadioSpinel().Process(aContext);
390 }
391 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
392
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)393 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
394 {
395 OT_UNUSED_VARIABLE(aInstance);
396 SuccessOrDie(GetRadioSpinel().EnableSrcMatch(aEnable));
397 }
398
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)399 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
400 {
401 OT_UNUSED_VARIABLE(aInstance);
402 return GetRadioSpinel().AddSrcMatchShortEntry(aShortAddress);
403 }
404
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)405 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
406 {
407 OT_UNUSED_VARIABLE(aInstance);
408 otExtAddress addr;
409
410 for (size_t i = 0; i < sizeof(addr); i++)
411 {
412 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
413 }
414
415 return GetRadioSpinel().AddSrcMatchExtEntry(addr);
416 }
417
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)418 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
419 {
420 OT_UNUSED_VARIABLE(aInstance);
421 return GetRadioSpinel().ClearSrcMatchShortEntry(aShortAddress);
422 }
423
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)424 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
425 {
426 OT_UNUSED_VARIABLE(aInstance);
427 otExtAddress addr;
428
429 for (size_t i = 0; i < sizeof(addr); i++)
430 {
431 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
432 }
433
434 return GetRadioSpinel().ClearSrcMatchExtEntry(addr);
435 }
436
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)437 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
438 {
439 OT_UNUSED_VARIABLE(aInstance);
440 SuccessOrDie(GetRadioSpinel().ClearSrcMatchShortEntries());
441 }
442
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)443 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
444 {
445 OT_UNUSED_VARIABLE(aInstance);
446 SuccessOrDie(GetRadioSpinel().ClearSrcMatchExtEntries());
447 }
448
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)449 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
450 {
451 OT_UNUSED_VARIABLE(aInstance);
452 return GetRadioSpinel().EnergyScan(aScanChannel, aScanDuration);
453 }
454
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)455 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
456 {
457 OT_UNUSED_VARIABLE(aInstance);
458 assert(aPower != nullptr);
459 return GetRadioSpinel().GetTransmitPower(*aPower);
460 }
461
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)462 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
463 {
464 OT_UNUSED_VARIABLE(aInstance);
465 return GetRadioSpinel().SetTransmitPower(aPower);
466 }
467
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)468 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
469 {
470 OT_UNUSED_VARIABLE(aInstance);
471 assert(aThreshold != nullptr);
472 return GetRadioSpinel().GetCcaEnergyDetectThreshold(*aThreshold);
473 }
474
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)475 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
476 {
477 OT_UNUSED_VARIABLE(aInstance);
478 return GetRadioSpinel().SetCcaEnergyDetectThreshold(aThreshold);
479 }
480
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)481 otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
482 {
483 OT_UNUSED_VARIABLE(aInstance);
484 assert(aGain != nullptr);
485 return GetRadioSpinel().GetFemLnaGain(*aGain);
486 }
487
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)488 otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
489 {
490 OT_UNUSED_VARIABLE(aInstance);
491 return GetRadioSpinel().SetFemLnaGain(aGain);
492 }
493
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)494 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
495 {
496 OT_UNUSED_VARIABLE(aInstance);
497 return GetRadioSpinel().GetReceiveSensitivity();
498 }
499
500 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)501 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
502 {
503 OT_UNUSED_VARIABLE(aInstance);
504 return GetRadioSpinel().SetCoexEnabled(aEnabled);
505 }
506
otPlatRadioIsCoexEnabled(otInstance * aInstance)507 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
508 {
509 OT_UNUSED_VARIABLE(aInstance);
510 return GetRadioSpinel().IsCoexEnabled();
511 }
512
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)513 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
514 {
515 OT_UNUSED_VARIABLE(aInstance);
516
517 otError error = OT_ERROR_NONE;
518
519 VerifyOrExit(aCoexMetrics != nullptr, error = OT_ERROR_INVALID_ARGS);
520
521 error = GetRadioSpinel().GetCoexMetrics(*aCoexMetrics);
522
523 exit:
524 return error;
525 }
526 #endif
527
528 #if OPENTHREAD_CONFIG_DIAG_ENABLE
529 static otPlatDiagOutputCallback sDiagOutputCallback = nullptr;
530 static void *sDiagCallbackContext = nullptr;
531 static char *sDiagOutput = nullptr;
532 static uint16_t sDiagOutputLen = 0;
533
handleDiagOutput(const char * aFormat,va_list aArguments,void * aContext)534 static void handleDiagOutput(const char *aFormat, va_list aArguments, void *aContext)
535 {
536 OT_UNUSED_VARIABLE(aContext);
537 int charsWritten;
538
539 VerifyOrExit((sDiagOutput != nullptr) && (sDiagOutputLen > 0));
540 charsWritten = vsnprintf(sDiagOutput, sDiagOutputLen, aFormat, aArguments);
541 VerifyOrExit(charsWritten > 0);
542 charsWritten = (sDiagOutputLen <= charsWritten) ? sDiagOutputLen : charsWritten;
543 sDiagOutput += charsWritten;
544 sDiagOutputLen -= charsWritten;
545
546 exit:
547 return;
548 }
549
setDiagOutput(char * aOutput,size_t aSize)550 static void setDiagOutput(char *aOutput, size_t aSize)
551 {
552 sDiagOutput = aOutput;
553 sDiagOutputLen = static_cast<uint16_t>(aSize);
554 GetRadioSpinel().SetDiagOutputCallback(handleDiagOutput, nullptr);
555 }
556
freeDiagOutput(void)557 static void freeDiagOutput(void)
558 {
559 sDiagOutput = nullptr;
560 sDiagOutputLen = 0;
561 GetRadioSpinel().SetDiagOutputCallback(sDiagOutputCallback, sDiagCallbackContext);
562 }
563
otPlatDiagSetOutputCallback(otInstance * aInstance,otPlatDiagOutputCallback aCallback,void * aContext)564 void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext)
565 {
566 OT_UNUSED_VARIABLE(aInstance);
567
568 sDiagOutputCallback = aCallback;
569 sDiagCallbackContext = aContext;
570
571 GetRadioSpinel().SetDiagOutputCallback(aCallback, aContext);
572 #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
573 GetRcpCapsDiag().SetDiagOutputCallback(aCallback, aContext);
574 #endif
575 }
576
otPlatDiagProcess(otInstance * aInstance,uint8_t aArgsLength,char * aArgs[])577 otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
578 {
579 OT_UNUSED_VARIABLE(aInstance);
580 otError error = OT_ERROR_NONE;
581 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
582 char *cur = cmd;
583 char *end = cmd + sizeof(cmd);
584
585 #if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
586 if (strcmp(aArgs[0], "rcpcaps") == 0)
587 {
588 error = GetRcpCapsDiag().DiagProcess(aArgs, aArgsLength);
589 ExitNow();
590 }
591 #endif
592
593 if (strcmp(aArgs[0], "radiospinel") == 0)
594 {
595 error = GetRadioSpinel().RadioSpinelDiagProcess(aArgs, aArgsLength);
596 ExitNow();
597 }
598
599 for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
600 {
601 cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
602 }
603
604 // deliver the platform specific diags commands to radio only ncp.
605 error = GetRadioSpinel().PlatDiagProcess(cmd);
606
607 exit:
608 return error;
609 }
610
otPlatDiagModeSet(bool aMode)611 void otPlatDiagModeSet(bool aMode)
612 {
613 SuccessOrExit(GetRadioSpinel().PlatDiagProcess(aMode ? "start" : "stop"));
614 GetRadioSpinel().SetDiagEnabled(aMode);
615
616 exit:
617 return;
618 }
619
otPlatDiagModeGet(void)620 bool otPlatDiagModeGet(void) { return GetRadioSpinel().IsDiagEnabled(); }
621
otPlatDiagTxPowerSet(int8_t aTxPower)622 void otPlatDiagTxPowerSet(int8_t aTxPower)
623 {
624 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
625
626 snprintf(cmd, sizeof(cmd), "power %d", aTxPower);
627 SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd));
628
629 exit:
630 return;
631 }
632
otPlatDiagChannelSet(uint8_t aChannel)633 void otPlatDiagChannelSet(uint8_t aChannel)
634 {
635 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
636
637 snprintf(cmd, sizeof(cmd), "channel %d", aChannel);
638 SuccessOrExit(GetRadioSpinel().PlatDiagProcess(cmd));
639
640 exit:
641 return;
642 }
643
otPlatDiagGpioSet(uint32_t aGpio,bool aValue)644 otError otPlatDiagGpioSet(uint32_t aGpio, bool aValue)
645 {
646 otError error;
647 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
648
649 snprintf(cmd, sizeof(cmd), "gpio set %d %d", aGpio, aValue);
650 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
651
652 exit:
653 return error;
654 }
655
otPlatDiagGpioGet(uint32_t aGpio,bool * aValue)656 otError otPlatDiagGpioGet(uint32_t aGpio, bool *aValue)
657 {
658 otError error;
659 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
660 char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE];
661 char *str;
662
663 setDiagOutput(output, sizeof(output));
664
665 snprintf(cmd, sizeof(cmd), "gpio get %d", aGpio);
666 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
667 VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED);
668 *aValue = static_cast<bool>(atoi(str));
669
670 exit:
671 freeDiagOutput();
672
673 return error;
674 }
675
otPlatDiagGpioSetMode(uint32_t aGpio,otGpioMode aMode)676 otError otPlatDiagGpioSetMode(uint32_t aGpio, otGpioMode aMode)
677 {
678 otError error;
679 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
680
681 snprintf(cmd, sizeof(cmd), "gpio mode %d %s", aGpio, aMode == OT_GPIO_MODE_INPUT ? "in" : "out");
682 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
683
684 exit:
685 return error;
686 }
687
otPlatDiagGpioGetMode(uint32_t aGpio,otGpioMode * aMode)688 otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode)
689 {
690 otError error;
691 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
692 char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE];
693 char *str;
694
695 setDiagOutput(output, sizeof(output));
696
697 snprintf(cmd, sizeof(cmd), "gpio mode %d", aGpio);
698 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
699 VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED);
700
701 if (strcmp(str, "in") == 0)
702 {
703 *aMode = OT_GPIO_MODE_INPUT;
704 }
705 else if (strcmp(str, "out") == 0)
706 {
707 *aMode = OT_GPIO_MODE_OUTPUT;
708 }
709 else
710 {
711 error = OT_ERROR_FAILED;
712 }
713
714 exit:
715 freeDiagOutput();
716
717 return error;
718 }
719
otPlatDiagRadioGetPowerSettings(otInstance * aInstance,uint8_t aChannel,int16_t * aTargetPower,int16_t * aActualPower,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)720 otError otPlatDiagRadioGetPowerSettings(otInstance *aInstance,
721 uint8_t aChannel,
722 int16_t *aTargetPower,
723 int16_t *aActualPower,
724 uint8_t *aRawPowerSetting,
725 uint16_t *aRawPowerSettingLength)
726 {
727 OT_UNUSED_VARIABLE(aInstance);
728 static constexpr uint16_t kRawPowerStringSize = OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE * 2 + 1;
729 static constexpr uint16_t kFmtStringSize = 100;
730
731 otError error;
732 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
733 char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE];
734 int targetPower;
735 int actualPower;
736 char rawPowerSetting[kRawPowerStringSize];
737 char fmt[kFmtStringSize];
738
739 assert((aTargetPower != nullptr) && (aActualPower != nullptr) && (aRawPowerSetting != nullptr) &&
740 (aRawPowerSettingLength != nullptr));
741
742 setDiagOutput(output, sizeof(output));
743
744 snprintf(cmd, sizeof(cmd), "powersettings %d", aChannel);
745 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
746 snprintf(fmt, sizeof(fmt), "TargetPower(0.01dBm): %%d\r\nActualPower(0.01dBm): %%d\r\nRawPowerSetting: %%%us\r\n",
747 kRawPowerStringSize);
748 VerifyOrExit(sscanf(output, fmt, &targetPower, &actualPower, rawPowerSetting) == 3, error = OT_ERROR_FAILED);
749 SuccessOrExit(
750 error = ot::Utils::CmdLineParser::ParseAsHexString(rawPowerSetting, *aRawPowerSettingLength, aRawPowerSetting));
751 *aTargetPower = static_cast<int16_t>(targetPower);
752 *aActualPower = static_cast<int16_t>(actualPower);
753
754 exit:
755 freeDiagOutput();
756
757 return error;
758 }
759
otPlatDiagRadioSetRawPowerSetting(otInstance * aInstance,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)760 otError otPlatDiagRadioSetRawPowerSetting(otInstance *aInstance,
761 const uint8_t *aRawPowerSetting,
762 uint16_t aRawPowerSettingLength)
763 {
764 OT_UNUSED_VARIABLE(aInstance);
765
766 otError error;
767 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
768 int nbytes;
769
770 assert(aRawPowerSetting != nullptr);
771
772 nbytes = snprintf(cmd, sizeof(cmd), "rawpowersetting ");
773
774 for (uint16_t i = 0; i < aRawPowerSettingLength; i++)
775 {
776 nbytes += snprintf(cmd + nbytes, sizeof(cmd) - static_cast<size_t>(nbytes), "%02x", aRawPowerSetting[i]);
777 VerifyOrExit(nbytes < static_cast<int>(sizeof(cmd)), error = OT_ERROR_INVALID_ARGS);
778 }
779
780 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
781
782 exit:
783 return error;
784 }
785
otPlatDiagRadioGetRawPowerSetting(otInstance * aInstance,uint8_t * aRawPowerSetting,uint16_t * aRawPowerSettingLength)786 otError otPlatDiagRadioGetRawPowerSetting(otInstance *aInstance,
787 uint8_t *aRawPowerSetting,
788 uint16_t *aRawPowerSettingLength)
789 {
790 OT_UNUSED_VARIABLE(aInstance);
791 otError error;
792 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
793 char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE];
794 char *str;
795
796 assert((aRawPowerSetting != nullptr) && (aRawPowerSettingLength != nullptr));
797
798 setDiagOutput(output, sizeof(output));
799
800 snprintf(cmd, sizeof(cmd), "rawpowersetting");
801 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
802 VerifyOrExit((str = strtok(output, "\r")) != nullptr, error = OT_ERROR_FAILED);
803 SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsHexString(str, *aRawPowerSettingLength, aRawPowerSetting));
804
805 exit:
806 freeDiagOutput();
807
808 return error;
809 }
810
otPlatDiagRadioRawPowerSettingEnable(otInstance * aInstance,bool aEnable)811 otError otPlatDiagRadioRawPowerSettingEnable(otInstance *aInstance, bool aEnable)
812 {
813 OT_UNUSED_VARIABLE(aInstance);
814
815 otError error;
816 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
817
818 snprintf(cmd, sizeof(cmd), "rawpowersetting %s", aEnable ? "enable" : "disable");
819 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
820
821 exit:
822 return error;
823 }
824
otPlatDiagRadioTransmitCarrier(otInstance * aInstance,bool aEnable)825 otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable)
826 {
827 OT_UNUSED_VARIABLE(aInstance);
828
829 otError error;
830 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
831
832 snprintf(cmd, sizeof(cmd), "cw %s", aEnable ? "start" : "stop");
833 SuccessOrExit(error = GetRadioSpinel().PlatDiagProcess(cmd));
834
835 exit:
836 return error;
837 }
838
otPlatDiagRadioTransmitStream(otInstance * aInstance,bool aEnable)839 otError otPlatDiagRadioTransmitStream(otInstance *aInstance, bool aEnable)
840 {
841 OT_UNUSED_VARIABLE(aInstance);
842
843 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
844
845 snprintf(cmd, sizeof(cmd), "stream %s", aEnable ? "start" : "stop");
846 return GetRadioSpinel().PlatDiagProcess(cmd);
847 }
848
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)849 void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
850 {
851 OT_UNUSED_VARIABLE(aInstance);
852 OT_UNUSED_VARIABLE(aFrame);
853 OT_UNUSED_VARIABLE(aError);
854 }
855
otPlatDiagAlarmCallback(otInstance * aInstance)856 void otPlatDiagAlarmCallback(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); }
857 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
858
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)859 uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
860 {
861 OT_UNUSED_VARIABLE(aInstance);
862
863 uint32_t channelMask;
864
865 #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
866 if (sConfig.IsValid())
867 {
868 channelMask = sConfig.GetSupportedChannelMask();
869 }
870 else
871 #endif
872 {
873 channelMask = GetRadioSpinel().GetRadioChannelMask(false);
874 }
875
876 return channelMask;
877 }
878
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)879 uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
880 {
881 OT_UNUSED_VARIABLE(aInstance);
882
883 uint32_t channelMask;
884
885 #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
886 if (sConfig.IsValid())
887 {
888 channelMask = sConfig.GetPreferredChannelMask();
889 }
890 else
891 #endif
892 {
893 channelMask = GetRadioSpinel().GetRadioChannelMask(true);
894 }
895
896 return channelMask;
897 }
898
otPlatRadioGetState(otInstance * aInstance)899 otRadioState otPlatRadioGetState(otInstance *aInstance)
900 {
901 OT_UNUSED_VARIABLE(aInstance);
902 return GetRadioSpinel().GetState();
903 }
904
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)905 void otPlatRadioSetMacKey(otInstance *aInstance,
906 uint8_t aKeyIdMode,
907 uint8_t aKeyId,
908 const otMacKeyMaterial *aPrevKey,
909 const otMacKeyMaterial *aCurrKey,
910 const otMacKeyMaterial *aNextKey,
911 otRadioKeyType aKeyType)
912 {
913 SuccessOrDie(GetRadioSpinel().SetMacKey(aKeyIdMode, aKeyId, aPrevKey, aCurrKey, aNextKey));
914 OT_UNUSED_VARIABLE(aInstance);
915 OT_UNUSED_VARIABLE(aKeyType);
916 }
917
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)918 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
919 {
920 SuccessOrDie(GetRadioSpinel().SetMacFrameCounter(aMacFrameCounter, /* aSetIfLarger */ false));
921 OT_UNUSED_VARIABLE(aInstance);
922 }
923
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)924 void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
925 {
926 SuccessOrDie(GetRadioSpinel().SetMacFrameCounter(aMacFrameCounter, /* aSetIfLarger */ true));
927 OT_UNUSED_VARIABLE(aInstance);
928 }
929
otPlatRadioGetNow(otInstance * aInstance)930 uint64_t otPlatRadioGetNow(otInstance *aInstance)
931 {
932 OT_UNUSED_VARIABLE(aInstance);
933 return GetRadioSpinel().GetNow();
934 }
935
otPlatRadioGetBusSpeed(otInstance * aInstance)936 uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
937 {
938 OT_UNUSED_VARIABLE(aInstance);
939 return GetRadioSpinel().GetBusSpeed();
940 }
941
otPlatRadioGetBusLatency(otInstance * aInstance)942 uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
943 {
944 OT_UNUSED_VARIABLE(aInstance);
945 return GetRadioSpinel().GetBusLatency();
946 }
947
948 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslAccuracy(otInstance * aInstance)949 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
950 {
951 OT_UNUSED_VARIABLE(aInstance);
952
953 return GetRadioSpinel().GetCslAccuracy();
954 }
955 #endif
956
957 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslUncertainty(otInstance * aInstance)958 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
959 {
960 OT_UNUSED_VARIABLE(aInstance);
961
962 return GetRadioSpinel().GetCslUncertainty();
963 }
964 #endif
965
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)966 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
967 {
968 OT_UNUSED_VARIABLE(aInstance);
969 return GetRadioSpinel().SetChannelMaxTransmitPower(aChannel, aMaxPower);
970 }
971
972 #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
otPlatRadioAddCalibratedPower(otInstance * aInstance,uint8_t aChannel,int16_t aActualPower,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)973 otError otPlatRadioAddCalibratedPower(otInstance *aInstance,
974 uint8_t aChannel,
975 int16_t aActualPower,
976 const uint8_t *aRawPowerSetting,
977 uint16_t aRawPowerSettingLength)
978 {
979 OT_UNUSED_VARIABLE(aInstance);
980 return GetRadioSpinel().AddCalibratedPower(aChannel, aActualPower, aRawPowerSetting, aRawPowerSettingLength);
981 }
982
otPlatRadioClearCalibratedPowers(otInstance * aInstance)983 otError otPlatRadioClearCalibratedPowers(otInstance *aInstance)
984 {
985 OT_UNUSED_VARIABLE(aInstance);
986 return GetRadioSpinel().ClearCalibratedPowers();
987 }
988
otPlatRadioSetChannelTargetPower(otInstance * aInstance,uint8_t aChannel,int16_t aTargetPower)989 otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower)
990 {
991 OT_UNUSED_VARIABLE(aInstance);
992 return GetRadioSpinel().SetChannelTargetPower(aChannel, aTargetPower);
993 }
994 #endif
995
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)996 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
997 {
998 OT_UNUSED_VARIABLE(aInstance);
999
1000 otError error;
1001
1002 #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
1003 if (sConfig.IsValid())
1004 {
1005 error = sConfig.SetRegion(aRegionCode);
1006 }
1007 else
1008 #endif
1009 {
1010 error = GetRadioSpinel().SetRadioRegion(aRegionCode);
1011 }
1012
1013 return error;
1014 }
1015
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)1016 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
1017 {
1018 OT_UNUSED_VARIABLE(aInstance);
1019
1020 otError error;
1021
1022 #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
1023 if (sConfig.IsValid())
1024 {
1025 *aRegionCode = sConfig.GetRegion();
1026 error = OT_ERROR_NONE;
1027 }
1028 else
1029 #endif
1030 {
1031 error = GetRadioSpinel().GetRadioRegion(aRegionCode);
1032 }
1033
1034 return error;
1035 }
1036
1037 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1038 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance,
1039 otLinkMetrics aLinkMetrics,
1040 const otShortAddress aShortAddress,
1041 const otExtAddress *aExtAddress)
1042 {
1043 OT_UNUSED_VARIABLE(aInstance);
1044
1045 return GetRadioSpinel().ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress);
1046 }
1047 #endif
1048
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)1049 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
1050 {
1051 OT_UNUSED_VARIABLE(aInstance);
1052 OT_UNUSED_VARIABLE(aChannel);
1053 OT_UNUSED_VARIABLE(aStart);
1054 OT_UNUSED_VARIABLE(aDuration);
1055 return OT_ERROR_NOT_IMPLEMENTED;
1056 }
1057
1058 #if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE
otPlatResetToBootloader(otInstance * aInstance)1059 otError otPlatResetToBootloader(otInstance *aInstance)
1060 {
1061 OT_UNUSED_VARIABLE(aInstance);
1062
1063 return GetRadioSpinel().SendReset(SPINEL_RESET_BOOTLOADER);
1064 }
1065 #endif
1066
otSysGetRadioSpinelMetrics(void)1067 const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) { return GetRadioSpinel().GetRadioSpinelMetrics(); }
1068
otSysGetRcpInterfaceMetrics(void)1069 const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
1070 {
1071 return sRadio.GetSpinelInterface().GetRcpInterfaceMetrics();
1072 }
1073
1074 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
otSysSetRcpRestorationEnabled(bool aEnabled)1075 void otSysSetRcpRestorationEnabled(bool aEnabled) { return GetRadioSpinel().SetRcpRestorationEnabled(aEnabled); }
1076 #endif
1077