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