• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements the radio apis on posix platform.
32  */
33 
34 #include "platform-posix.h"
35 
36 #include <string.h>
37 
38 #include "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