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