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