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