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