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