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 "common/code_utils.hpp"
39 #include "common/new.hpp"
40 #include "lib/spinel/radio_spinel.hpp"
41 #include "posix/platform/radio.hpp"
42
43 #if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_UART
44 #include "hdlc_interface.hpp"
45
46 #if OPENTHREAD_POSIX_VIRTUAL_TIME
47 static ot::Spinel::RadioSpinel<ot::Posix::HdlcInterface, VirtualTimeEvent> sRadioSpinel;
48 #else
49 static ot::Spinel::RadioSpinel<ot::Posix::HdlcInterface, RadioProcessContext> sRadioSpinel;
50 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
51 #elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_SPI
52 #include "spi_interface.hpp"
53
54 static ot::Spinel::RadioSpinel<ot::Posix::SpiInterface, RadioProcessContext> sRadioSpinel;
55 #elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
56 #include "vendor_interface.hpp"
57
58 static ot::Spinel::RadioSpinel<ot::Posix::VendorInterface, RadioProcessContext> sRadioSpinel;
59 #else
60 #error "OPENTHREAD_POSIX_CONFIG_RCP_BUS only allows OT_POSIX_RCP_BUS_UART, OT_POSIX_RCP_BUS_SPI and " \
61 "OT_POSIX_RCP_BUS_VENDOR!"
62 #endif
63
64 namespace ot {
65 namespace Posix {
66
67 namespace {
68 alignas(alignof(ot::Posix::Radio)) char sRadioRaw[sizeof(ot::Posix::Radio)];
69
platformRadioInit(const char * aUrl)70 extern "C" void platformRadioInit(const char *aUrl)
71 {
72 Radio &radio = *(new (&sRadioRaw) Radio(aUrl));
73
74 radio.Init();
75 }
76 } // namespace
77
Radio(const char * aUrl)78 Radio::Radio(const char *aUrl)
79 : mRadioUrl(aUrl)
80 {
81 VerifyOrDie(mRadioUrl.GetPath() != nullptr, OT_EXIT_INVALID_ARGUMENTS);
82 }
83
Init(void)84 void Radio::Init(void)
85 {
86 bool resetRadio = (mRadioUrl.GetValue("no-reset") == nullptr);
87 bool restoreDataset = (mRadioUrl.GetValue("ncp-dataset") != nullptr);
88 bool skipCompatibilityCheck = (mRadioUrl.GetValue("skip-rcp-compatibility-check") != nullptr);
89 const char *parameterValue;
90 const char *region;
91 #if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
92 const char *maxPowerTable;
93 #endif
94
95 #if OPENTHREAD_POSIX_VIRTUAL_TIME
96 // The last argument must be the node id
97 {
98 const char *nodeId = nullptr;
99
100 for (const char *arg = nullptr; (arg = mRadioUrl.GetValue("forkpty-arg", arg)) != nullptr; nodeId = arg)
101 {
102 }
103
104 virtualTimeInit(static_cast<uint16_t>(atoi(nodeId)));
105 }
106 #endif
107
108 SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(mRadioUrl));
109 sRadioSpinel.Init(resetRadio, restoreDataset, skipCompatibilityCheck);
110
111 parameterValue = mRadioUrl.GetValue("fem-lnagain");
112 if (parameterValue != nullptr)
113 {
114 long femLnaGain = strtol(parameterValue, nullptr, 0);
115
116 VerifyOrDie(INT8_MIN <= femLnaGain && femLnaGain <= INT8_MAX, OT_EXIT_INVALID_ARGUMENTS);
117 SuccessOrDie(sRadioSpinel.SetFemLnaGain(static_cast<int8_t>(femLnaGain)));
118 }
119
120 parameterValue = mRadioUrl.GetValue("cca-threshold");
121 if (parameterValue != nullptr)
122 {
123 long ccaThreshold = strtol(parameterValue, nullptr, 0);
124
125 VerifyOrDie(INT8_MIN <= ccaThreshold && ccaThreshold <= INT8_MAX, OT_EXIT_INVALID_ARGUMENTS);
126 SuccessOrDie(sRadioSpinel.SetCcaEnergyDetectThreshold(static_cast<int8_t>(ccaThreshold)));
127 }
128
129 region = mRadioUrl.GetValue("region");
130 if (region != nullptr)
131 {
132 uint16_t regionCode;
133
134 VerifyOrDie(strnlen(region, 3) == 2, OT_EXIT_INVALID_ARGUMENTS);
135 regionCode = static_cast<uint16_t>(static_cast<uint16_t>(region[0]) << 8) + static_cast<uint16_t>(region[1]);
136 SuccessOrDie(sRadioSpinel.SetRadioRegion(regionCode));
137 }
138
139 #if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
140 maxPowerTable = mRadioUrl.GetValue("max-power-table");
141 if (maxPowerTable != nullptr)
142 {
143 constexpr int8_t kPowerDefault = 30; // Default power 1 watt (30 dBm).
144 const char * str = nullptr;
145 uint8_t channel = ot::Radio::kChannelMin;
146 int8_t power = kPowerDefault;
147 otError error;
148
149 for (str = strtok(const_cast<char *>(maxPowerTable), ","); str != nullptr && channel <= ot::Radio::kChannelMax;
150 str = strtok(nullptr, ","))
151 {
152 power = static_cast<int8_t>(strtol(str, nullptr, 0));
153 error = sRadioSpinel.SetChannelMaxTransmitPower(channel, power);
154 if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
155 {
156 DieNow(OT_ERROR_FAILED);
157 }
158 ++channel;
159 }
160
161 // Use the last power if omitted.
162 while (channel <= ot::Radio::kChannelMax)
163 {
164 error = sRadioSpinel.SetChannelMaxTransmitPower(channel, power);
165 if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
166 {
167 DieNow(OT_ERROR_FAILED);
168 }
169 ++channel;
170 }
171
172 VerifyOrDie(str == nullptr, OT_EXIT_INVALID_ARGUMENTS);
173 }
174 #endif // OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
175 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
176 {
177 const char *enableCoex = mRadioUrl.GetValue("enable-coex");
178 if (enableCoex != nullptr)
179 {
180 SuccessOrDie(sRadioSpinel.SetCoexEnabled(enableCoex[0] != '0'));
181 }
182 }
183 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
184 }
185
186 } // namespace Posix
187 } // namespace ot
188
platformRadioDeinit(void)189 void platformRadioDeinit(void)
190 {
191 sRadioSpinel.Deinit();
192 }
193
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)194 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
195 {
196 OT_UNUSED_VARIABLE(aInstance);
197 SuccessOrDie(sRadioSpinel.GetIeeeEui64(aIeeeEui64));
198 }
199
otPlatRadioSetPanId(otInstance * aInstance,uint16_t panid)200 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
201 {
202 OT_UNUSED_VARIABLE(aInstance);
203 SuccessOrDie(sRadioSpinel.SetPanId(panid));
204 }
205
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aAddress)206 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
207 {
208 OT_UNUSED_VARIABLE(aInstance);
209 otExtAddress addr;
210
211 for (size_t i = 0; i < sizeof(addr); i++)
212 {
213 addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i];
214 }
215
216 SuccessOrDie(sRadioSpinel.SetExtendedAddress(addr));
217 }
218
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aAddress)219 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
220 {
221 OT_UNUSED_VARIABLE(aInstance);
222 SuccessOrDie(sRadioSpinel.SetShortAddress(aAddress));
223 }
224
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)225 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
226 {
227 OT_UNUSED_VARIABLE(aInstance);
228 SuccessOrDie(sRadioSpinel.SetPromiscuous(aEnable));
229 }
230
otPlatRadioIsEnabled(otInstance * aInstance)231 bool otPlatRadioIsEnabled(otInstance *aInstance)
232 {
233 OT_UNUSED_VARIABLE(aInstance);
234 return sRadioSpinel.IsEnabled();
235 }
236
otPlatRadioEnable(otInstance * aInstance)237 otError otPlatRadioEnable(otInstance *aInstance)
238 {
239 return sRadioSpinel.Enable(aInstance);
240 }
241
otPlatRadioDisable(otInstance * aInstance)242 otError otPlatRadioDisable(otInstance *aInstance)
243 {
244 OT_UNUSED_VARIABLE(aInstance);
245 return sRadioSpinel.Disable();
246 }
247
otPlatRadioSleep(otInstance * aInstance)248 otError otPlatRadioSleep(otInstance *aInstance)
249 {
250 OT_UNUSED_VARIABLE(aInstance);
251 return sRadioSpinel.Sleep();
252 }
253
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)254 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
255 {
256 OT_UNUSED_VARIABLE(aInstance);
257
258 otError error;
259
260 SuccessOrExit(error = sRadioSpinel.Receive(aChannel));
261
262 exit:
263 return error;
264 }
265
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)266 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
267 {
268 OT_UNUSED_VARIABLE(aInstance);
269 return sRadioSpinel.Transmit(*aFrame);
270 }
271
otPlatRadioGetTransmitBuffer(otInstance * aInstance)272 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
273 {
274 OT_UNUSED_VARIABLE(aInstance);
275 return &sRadioSpinel.GetTransmitFrame();
276 }
277
otPlatRadioGetRssi(otInstance * aInstance)278 int8_t otPlatRadioGetRssi(otInstance *aInstance)
279 {
280 OT_UNUSED_VARIABLE(aInstance);
281 return sRadioSpinel.GetRssi();
282 }
283
otPlatRadioGetCaps(otInstance * aInstance)284 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
285 {
286 OT_UNUSED_VARIABLE(aInstance);
287 return sRadioSpinel.GetRadioCaps();
288 }
289
otPlatRadioGetVersionString(otInstance * aInstance)290 const char *otPlatRadioGetVersionString(otInstance *aInstance)
291 {
292 OT_UNUSED_VARIABLE(aInstance);
293 return sRadioSpinel.GetVersion();
294 }
295
otPlatRadioGetPromiscuous(otInstance * aInstance)296 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
297 {
298 OT_UNUSED_VARIABLE(aInstance);
299 return sRadioSpinel.IsPromiscuous();
300 }
301
platformRadioUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,int * aMaxFd,struct timeval * aTimeout)302 void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd, struct timeval *aTimeout)
303 {
304 uint64_t now = otPlatTimeGet();
305 uint64_t deadline = sRadioSpinel.GetNextRadioTimeRecalcStart();
306
307 if (sRadioSpinel.IsTransmitting())
308 {
309 uint64_t txRadioEndUs = sRadioSpinel.GetTxRadioEndUs();
310
311 if (txRadioEndUs < deadline)
312 {
313 deadline = txRadioEndUs;
314 }
315 }
316
317 if (now < deadline)
318 {
319 uint64_t remain = deadline - now;
320
321 if (remain < (static_cast<uint64_t>(aTimeout->tv_sec) * US_PER_S + static_cast<uint64_t>(aTimeout->tv_usec)))
322 {
323 aTimeout->tv_sec = static_cast<time_t>(remain / US_PER_S);
324 aTimeout->tv_usec = static_cast<suseconds_t>(remain % US_PER_S);
325 }
326 }
327 else
328 {
329 aTimeout->tv_sec = 0;
330 aTimeout->tv_usec = 0;
331 }
332
333 sRadioSpinel.GetSpinelInterface().UpdateFdSet(*aReadFdSet, *aWriteFdSet, *aMaxFd, *aTimeout);
334
335 if (sRadioSpinel.HasPendingFrame() || sRadioSpinel.IsTransmitDone())
336 {
337 aTimeout->tv_sec = 0;
338 aTimeout->tv_usec = 0;
339 }
340 }
341
342 #if OPENTHREAD_POSIX_VIRTUAL_TIME
virtualTimeRadioSpinelProcess(otInstance * aInstance,const struct VirtualTimeEvent * aEvent)343 void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent)
344 {
345 OT_UNUSED_VARIABLE(aInstance);
346 sRadioSpinel.Process(*aEvent);
347 }
348 #else
platformRadioProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)349 void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
350 {
351 OT_UNUSED_VARIABLE(aInstance);
352 RadioProcessContext context = {aReadFdSet, aWriteFdSet};
353
354 sRadioSpinel.Process(context);
355 }
356 #endif // OPENTHREAD_POSIX_VIRTUAL_TIME
357
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)358 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
359 {
360 OT_UNUSED_VARIABLE(aInstance);
361 SuccessOrDie(sRadioSpinel.EnableSrcMatch(aEnable));
362 }
363
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)364 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
365 {
366 OT_UNUSED_VARIABLE(aInstance);
367 return sRadioSpinel.AddSrcMatchShortEntry(aShortAddress);
368 }
369
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)370 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
371 {
372 OT_UNUSED_VARIABLE(aInstance);
373 otExtAddress addr;
374
375 for (size_t i = 0; i < sizeof(addr); i++)
376 {
377 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
378 }
379
380 return sRadioSpinel.AddSrcMatchExtEntry(addr);
381 }
382
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)383 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
384 {
385 OT_UNUSED_VARIABLE(aInstance);
386 return sRadioSpinel.ClearSrcMatchShortEntry(aShortAddress);
387 }
388
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)389 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
390 {
391 OT_UNUSED_VARIABLE(aInstance);
392 otExtAddress addr;
393
394 for (size_t i = 0; i < sizeof(addr); i++)
395 {
396 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
397 }
398
399 return sRadioSpinel.ClearSrcMatchExtEntry(addr);
400 }
401
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)402 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
403 {
404 OT_UNUSED_VARIABLE(aInstance);
405 SuccessOrDie(sRadioSpinel.ClearSrcMatchShortEntries());
406 }
407
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)408 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
409 {
410 OT_UNUSED_VARIABLE(aInstance);
411 SuccessOrDie(sRadioSpinel.ClearSrcMatchExtEntries());
412 }
413
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)414 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
415 {
416 OT_UNUSED_VARIABLE(aInstance);
417 return sRadioSpinel.EnergyScan(aScanChannel, aScanDuration);
418 }
419
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)420 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
421 {
422 OT_UNUSED_VARIABLE(aInstance);
423 assert(aPower != nullptr);
424 return sRadioSpinel.GetTransmitPower(*aPower);
425 }
426
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)427 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
428 {
429 OT_UNUSED_VARIABLE(aInstance);
430 return sRadioSpinel.SetTransmitPower(aPower);
431 }
432
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)433 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
434 {
435 OT_UNUSED_VARIABLE(aInstance);
436 assert(aThreshold != nullptr);
437 return sRadioSpinel.GetCcaEnergyDetectThreshold(*aThreshold);
438 }
439
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)440 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
441 {
442 OT_UNUSED_VARIABLE(aInstance);
443 return sRadioSpinel.SetCcaEnergyDetectThreshold(aThreshold);
444 }
445
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)446 otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
447 {
448 OT_UNUSED_VARIABLE(aInstance);
449 assert(aGain != nullptr);
450 return sRadioSpinel.GetFemLnaGain(*aGain);
451 }
452
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)453 otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
454 {
455 OT_UNUSED_VARIABLE(aInstance);
456 return sRadioSpinel.SetFemLnaGain(aGain);
457 }
458
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)459 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
460 {
461 OT_UNUSED_VARIABLE(aInstance);
462 return sRadioSpinel.GetReceiveSensitivity();
463 }
464
465 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)466 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
467 {
468 OT_UNUSED_VARIABLE(aInstance);
469 return sRadioSpinel.SetCoexEnabled(aEnabled);
470 }
471
otPlatRadioIsCoexEnabled(otInstance * aInstance)472 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
473 {
474 OT_UNUSED_VARIABLE(aInstance);
475 return sRadioSpinel.IsCoexEnabled();
476 }
477
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)478 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
479 {
480 OT_UNUSED_VARIABLE(aInstance);
481
482 otError error = OT_ERROR_NONE;
483
484 VerifyOrExit(aCoexMetrics != nullptr, error = OT_ERROR_INVALID_ARGS);
485
486 error = sRadioSpinel.GetCoexMetrics(*aCoexMetrics);
487
488 exit:
489 return error;
490 }
491 #endif
492
493 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagProcess(otInstance * aInstance,uint8_t aArgsLength,char * aArgs[],char * aOutput,size_t aOutputMaxLen)494 otError otPlatDiagProcess(otInstance *aInstance,
495 uint8_t aArgsLength,
496 char * aArgs[],
497 char * aOutput,
498 size_t aOutputMaxLen)
499 {
500 // deliver the platform specific diags commands to radio only ncp.
501 OT_UNUSED_VARIABLE(aInstance);
502 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
503 char *cur = cmd;
504 char *end = cmd + sizeof(cmd);
505
506 for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
507 {
508 cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
509 }
510
511 return sRadioSpinel.PlatDiagProcess(cmd, aOutput, aOutputMaxLen);
512 }
513
otPlatDiagModeSet(bool aMode)514 void otPlatDiagModeSet(bool aMode)
515 {
516 SuccessOrExit(sRadioSpinel.PlatDiagProcess(aMode ? "start" : "stop", nullptr, 0));
517 sRadioSpinel.SetDiagEnabled(aMode);
518
519 exit:
520 return;
521 }
522
otPlatDiagModeGet(void)523 bool otPlatDiagModeGet(void)
524 {
525 return sRadioSpinel.IsDiagEnabled();
526 }
527
otPlatDiagTxPowerSet(int8_t aTxPower)528 void otPlatDiagTxPowerSet(int8_t aTxPower)
529 {
530 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
531
532 snprintf(cmd, sizeof(cmd), "power %d", aTxPower);
533 SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, nullptr, 0));
534
535 exit:
536 return;
537 }
538
otPlatDiagChannelSet(uint8_t aChannel)539 void otPlatDiagChannelSet(uint8_t aChannel)
540 {
541 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
542
543 snprintf(cmd, sizeof(cmd), "channel %d", aChannel);
544 SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, nullptr, 0));
545
546 exit:
547 return;
548 }
549
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)550 void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
551 {
552 OT_UNUSED_VARIABLE(aInstance);
553 OT_UNUSED_VARIABLE(aFrame);
554 OT_UNUSED_VARIABLE(aError);
555 }
556
otPlatDiagAlarmCallback(otInstance * aInstance)557 void otPlatDiagAlarmCallback(otInstance *aInstance)
558 {
559 OT_UNUSED_VARIABLE(aInstance);
560 }
561 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
562
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)563 uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
564 {
565 OT_UNUSED_VARIABLE(aInstance);
566 return sRadioSpinel.GetRadioChannelMask(false);
567 }
568
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)569 uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
570 {
571 OT_UNUSED_VARIABLE(aInstance);
572 return sRadioSpinel.GetRadioChannelMask(true);
573 }
574
otPlatRadioGetState(otInstance * aInstance)575 otRadioState otPlatRadioGetState(otInstance *aInstance)
576 {
577 OT_UNUSED_VARIABLE(aInstance);
578 return sRadioSpinel.GetState();
579 }
580
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)581 void otPlatRadioSetMacKey(otInstance * aInstance,
582 uint8_t aKeyIdMode,
583 uint8_t aKeyId,
584 const otMacKeyMaterial *aPrevKey,
585 const otMacKeyMaterial *aCurrKey,
586 const otMacKeyMaterial *aNextKey,
587 otRadioKeyType aKeyType)
588 {
589 SuccessOrDie(sRadioSpinel.SetMacKey(aKeyIdMode, aKeyId, aPrevKey, aCurrKey, aNextKey));
590 OT_UNUSED_VARIABLE(aInstance);
591 OT_UNUSED_VARIABLE(aKeyType);
592 }
593
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)594 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
595 {
596 SuccessOrDie(sRadioSpinel.SetMacFrameCounter(aMacFrameCounter));
597 OT_UNUSED_VARIABLE(aInstance);
598 }
599
otPlatRadioGetNow(otInstance * aInstance)600 uint64_t otPlatRadioGetNow(otInstance *aInstance)
601 {
602 OT_UNUSED_VARIABLE(aInstance);
603 return sRadioSpinel.GetNow();
604 }
605
otPlatRadioGetBusSpeed(otInstance * aInstance)606 uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
607 {
608 OT_UNUSED_VARIABLE(aInstance);
609 return sRadioSpinel.GetBusSpeed();
610 }
611
612 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslAccuracy(otInstance * aInstance)613 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
614 {
615 OT_UNUSED_VARIABLE(aInstance);
616
617 return sRadioSpinel.GetCslAccuracy();
618 }
619 #endif
620
621 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslUncertainty(otInstance * aInstance)622 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
623 {
624 OT_UNUSED_VARIABLE(aInstance);
625
626 return sRadioSpinel.GetCslUncertainty();
627 }
628 #endif
629
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)630 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
631 {
632 OT_UNUSED_VARIABLE(aInstance);
633 return sRadioSpinel.SetChannelMaxTransmitPower(aChannel, aMaxPower);
634 }
635
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)636 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
637 {
638 OT_UNUSED_VARIABLE(aInstance);
639 return sRadioSpinel.SetRadioRegion(aRegionCode);
640 }
641
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)642 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
643 {
644 OT_UNUSED_VARIABLE(aInstance);
645 return sRadioSpinel.GetRadioRegion(aRegionCode);
646 }
647
648 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)649 otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,
650 otLinkMetrics aLinkMetrics,
651 const otShortAddress aShortAddress,
652 const otExtAddress * aExtAddress)
653 {
654 OT_UNUSED_VARIABLE(aInstance);
655
656 return sRadioSpinel.ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress);
657 }
658 #endif
659
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)660 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
661 {
662 OT_UNUSED_VARIABLE(aInstance);
663 OT_UNUSED_VARIABLE(aChannel);
664 OT_UNUSED_VARIABLE(aStart);
665 OT_UNUSED_VARIABLE(aDuration);
666 return OT_ERROR_NOT_IMPLEMENTED;
667 }
668
otSysGetRadioSpinelMetrics(void)669 const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void)
670 {
671 return sRadioSpinel.GetRadioSpinelMetrics();
672 }
673
otSysGetRcpInterfaceMetrics(void)674 const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
675 {
676 return sRadioSpinel.GetSpinelInterface().GetRcpInterfaceMetrics();
677 }
678