1 /*
2 * Copyright (c) 2021, The OpenThread Authors.
3 * Copyright (c) 2022-2024, NXP.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holder nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * @file
33 * This file implements OpenThread platform driver API in openthread/platform/radio.h.
34 *
35 */
36
37 #include <openthread/platform/radio.h>
38 #include <lib/platform/exit_code.h>
39 #include <lib/spinel/radio_spinel.hpp>
40 #include <lib/spinel/spinel.h>
41 #include <lib/url/url.hpp>
42 #include "hdlc_interface.hpp"
43
44 #include <zephyr/logging/log.h>
45 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
46 #include <zephyr/kernel.h>
47 #include <zephyr/net/net_pkt.h>
48 #include <openthread-system.h>
49
50 enum pending_events {
51 PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send */
52 PENDING_EVENT_COUNT /* Keep last */
53 };
54
55 ATOMIC_DEFINE(pending_events, PENDING_EVENT_COUNT);
56 K_FIFO_DEFINE(tx_pkt_fifo);
57
58 static ot::Spinel::RadioSpinel *psRadioSpinel;
59 static ot::Url::Url *psRadioUrl;
60 static ot::Hdlc::HdlcInterface *pSpinelInterface;
61 static ot::Spinel::SpinelDriver *psSpinelDriver;
62
63 static const otRadioCaps sRequiredRadioCaps =
64 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
65 OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING |
66 #endif
67 OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF;
68
is_pending_event_set(enum pending_events event)69 static inline bool is_pending_event_set(enum pending_events event)
70 {
71 return atomic_test_bit(pending_events, event);
72 }
73
set_pending_event(enum pending_events event)74 static void set_pending_event(enum pending_events event)
75 {
76 atomic_set_bit(pending_events, event);
77 otSysEventSignalPending();
78 }
79
reset_pending_event(enum pending_events event)80 static void reset_pending_event(enum pending_events event)
81 {
82 atomic_clear_bit(pending_events, event);
83 }
84
openthread_handle_frame_to_send(otInstance * instance,struct net_pkt * pkt)85 static void openthread_handle_frame_to_send(otInstance *instance, struct net_pkt *pkt)
86 {
87 struct net_buf *buf;
88 otMessage *message;
89 otMessageSettings settings;
90
91 NET_DBG("Sending Ip6 packet to ot stack");
92
93 settings.mPriority = OT_MESSAGE_PRIORITY_NORMAL;
94 settings.mLinkSecurityEnabled = true;
95 message = otIp6NewMessage(instance, &settings);
96 if (message == NULL) {
97 goto exit;
98 }
99
100 for (buf = pkt->buffer; buf; buf = buf->frags) {
101 if (otMessageAppend(message, buf->data, buf->len) != OT_ERROR_NONE) {
102 NET_ERR("Error while appending to otMessage");
103 otMessageFree(message);
104 goto exit;
105 }
106 }
107
108 if (otIp6Send(instance, message) != OT_ERROR_NONE) {
109 NET_ERR("Error while calling otIp6Send");
110 goto exit;
111 }
112
113 exit:
114 net_pkt_unref(pkt);
115 }
116
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)117 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
118 {
119 OT_UNUSED_VARIABLE(aInstance);
120 SuccessOrDie(psRadioSpinel->GetIeeeEui64(aIeeeEui64));
121 }
122
otPlatRadioSetPanId(otInstance * aInstance,uint16_t panid)123 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
124 {
125 OT_UNUSED_VARIABLE(aInstance);
126 SuccessOrDie(psRadioSpinel->SetPanId(panid));
127 }
128
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aAddress)129 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
130 {
131 OT_UNUSED_VARIABLE(aInstance);
132 otExtAddress addr;
133
134 for (size_t i = 0; i < sizeof(addr); i++) {
135 addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i];
136 }
137
138 SuccessOrDie(psRadioSpinel->SetExtendedAddress(addr));
139 }
140
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aAddress)141 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
142 {
143 OT_UNUSED_VARIABLE(aInstance);
144 SuccessOrDie(psRadioSpinel->SetShortAddress(aAddress));
145 }
146
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)147 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
148 {
149 OT_UNUSED_VARIABLE(aInstance);
150 SuccessOrDie(psRadioSpinel->SetPromiscuous(aEnable));
151 }
152
otPlatRadioIsEnabled(otInstance * aInstance)153 bool otPlatRadioIsEnabled(otInstance *aInstance)
154 {
155 OT_UNUSED_VARIABLE(aInstance);
156 return psRadioSpinel->IsEnabled();
157 }
158
otPlatRadioEnable(otInstance * aInstance)159 otError otPlatRadioEnable(otInstance *aInstance)
160 {
161 return psRadioSpinel->Enable(aInstance);
162 }
163
otPlatRadioDisable(otInstance * aInstance)164 otError otPlatRadioDisable(otInstance *aInstance)
165 {
166 OT_UNUSED_VARIABLE(aInstance);
167 return psRadioSpinel->Disable();
168 }
169
otPlatRadioSleep(otInstance * aInstance)170 otError otPlatRadioSleep(otInstance *aInstance)
171 {
172 OT_UNUSED_VARIABLE(aInstance);
173 return psRadioSpinel->Sleep();
174 }
175
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)176 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
177 {
178 OT_UNUSED_VARIABLE(aInstance);
179 return psRadioSpinel->Receive(aChannel);
180 }
181
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)182 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
183 {
184 OT_UNUSED_VARIABLE(aInstance);
185 return psRadioSpinel->Transmit(*aFrame);
186 }
187
otPlatRadioGetTransmitBuffer(otInstance * aInstance)188 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
189 {
190 OT_UNUSED_VARIABLE(aInstance);
191 return &psRadioSpinel->GetTransmitFrame();
192 }
193
otPlatRadioGetRssi(otInstance * aInstance)194 int8_t otPlatRadioGetRssi(otInstance *aInstance)
195 {
196 OT_UNUSED_VARIABLE(aInstance);
197 return psRadioSpinel->GetRssi();
198 }
199
otPlatRadioGetCaps(otInstance * aInstance)200 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
201 {
202 OT_UNUSED_VARIABLE(aInstance);
203 return psRadioSpinel->GetRadioCaps();
204 }
205
otPlatRadioGetVersionString(otInstance * aInstance)206 const char *otPlatRadioGetVersionString(otInstance *aInstance)
207 {
208 OT_UNUSED_VARIABLE(aInstance);
209 return psRadioSpinel->GetVersion();
210 }
211
otPlatRadioGetPromiscuous(otInstance * aInstance)212 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
213 {
214 OT_UNUSED_VARIABLE(aInstance);
215 return psRadioSpinel->IsPromiscuous();
216 }
217
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)218 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
219 {
220 OT_UNUSED_VARIABLE(aInstance);
221 SuccessOrDie(psRadioSpinel->EnableSrcMatch(aEnable));
222 }
223
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)224 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
225 {
226 OT_UNUSED_VARIABLE(aInstance);
227 return psRadioSpinel->AddSrcMatchShortEntry(aShortAddress);
228 }
229
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)230 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
231 {
232 OT_UNUSED_VARIABLE(aInstance);
233 otExtAddress addr;
234
235 for (size_t i = 0; i < sizeof(addr); i++) {
236 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
237 }
238
239 return psRadioSpinel->AddSrcMatchExtEntry(addr);
240 }
241
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)242 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
243 {
244 OT_UNUSED_VARIABLE(aInstance);
245 return psRadioSpinel->ClearSrcMatchShortEntry(aShortAddress);
246 }
247
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)248 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
249 {
250 OT_UNUSED_VARIABLE(aInstance);
251 otExtAddress addr;
252
253 for (size_t i = 0; i < sizeof(addr); i++) {
254 addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
255 }
256
257 return psRadioSpinel->ClearSrcMatchExtEntry(addr);
258 }
259
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)260 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
261 {
262 OT_UNUSED_VARIABLE(aInstance);
263 SuccessOrDie(psRadioSpinel->ClearSrcMatchShortEntries());
264 }
265
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)266 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
267 {
268 OT_UNUSED_VARIABLE(aInstance);
269 SuccessOrDie(psRadioSpinel->ClearSrcMatchExtEntries());
270 }
271
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)272 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
273 {
274 OT_UNUSED_VARIABLE(aInstance);
275 return psRadioSpinel->EnergyScan(aScanChannel, aScanDuration);
276 }
277
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)278 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
279 {
280 otError error;
281
282 OT_UNUSED_VARIABLE(aInstance);
283 VerifyOrExit(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
284 error = psRadioSpinel->GetTransmitPower(*aPower);
285
286 exit:
287 return error;
288 }
289
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)290 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
291 {
292 OT_UNUSED_VARIABLE(aInstance);
293 return psRadioSpinel->SetTransmitPower(aPower);
294 }
295
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)296 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
297 {
298 otError error;
299
300 OT_UNUSED_VARIABLE(aInstance);
301 VerifyOrExit(aThreshold != NULL, error = OT_ERROR_INVALID_ARGS);
302 error = psRadioSpinel->GetCcaEnergyDetectThreshold(*aThreshold);
303
304 exit:
305 return error;
306 }
307
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)308 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
309 {
310 OT_UNUSED_VARIABLE(aInstance);
311 return psRadioSpinel->SetCcaEnergyDetectThreshold(aThreshold);
312 }
313
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)314 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
315 {
316 OT_UNUSED_VARIABLE(aInstance);
317 return psRadioSpinel->GetReceiveSensitivity();
318 }
319
320 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)321 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
322 {
323 OT_UNUSED_VARIABLE(aInstance);
324 return psRadioSpinel->SetCoexEnabled(aEnabled);
325 }
326
otPlatRadioIsCoexEnabled(otInstance * aInstance)327 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
328 {
329 OT_UNUSED_VARIABLE(aInstance);
330 return psRadioSpinel->IsCoexEnabled();
331 }
332
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)333 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
334 {
335 OT_UNUSED_VARIABLE(aInstance);
336
337 otError error = OT_ERROR_NONE;
338
339 VerifyOrExit(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS);
340
341 error = psRadioSpinel->GetCoexMetrics(*aCoexMetrics);
342
343 exit:
344 return error;
345 }
346 #endif
347
348 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagProcess(otInstance * aInstance,int argc,char * argv[],char * aOutput,size_t aOutputMaxLen)349 otError otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[], char *aOutput,
350 size_t aOutputMaxLen)
351 {
352 /* Deliver the platform specific diags commands to radio only ncp */
353 OT_UNUSED_VARIABLE(aInstance);
354 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
355 char *cur = cmd;
356 char *end = cmd + sizeof(cmd);
357
358 for (int index = 0; index < argc; index++) {
359 cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", argv[index]);
360 }
361
362 return psRadioSpinel->PlatDiagProcess(cmd, aOutput, aOutputMaxLen);
363 }
364
otPlatDiagModeSet(bool aMode)365 void otPlatDiagModeSet(bool aMode)
366 {
367 SuccessOrExit(psRadioSpinel->PlatDiagProcess(aMode ? "start" : "stop", NULL, 0));
368 psRadioSpinel->SetDiagEnabled(aMode);
369
370 exit:
371 return;
372 }
373
otPlatDiagModeGet(void)374 bool otPlatDiagModeGet(void)
375 {
376 return psRadioSpinel->IsDiagEnabled();
377 }
378
otPlatDiagTxPowerSet(int8_t aTxPower)379 void otPlatDiagTxPowerSet(int8_t aTxPower)
380 {
381 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
382
383 snprintf(cmd, sizeof(cmd), "power %d", aTxPower);
384 SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd, NULL, 0));
385
386 exit:
387 return;
388 }
389
otPlatDiagChannelSet(uint8_t aChannel)390 void otPlatDiagChannelSet(uint8_t aChannel)
391 {
392 char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
393
394 snprintf(cmd, sizeof(cmd), "channel %d", aChannel);
395 SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd, NULL, 0));
396
397 exit:
398 return;
399 }
400
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)401 void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
402 {
403 OT_UNUSED_VARIABLE(aInstance);
404 OT_UNUSED_VARIABLE(aFrame);
405 OT_UNUSED_VARIABLE(aError);
406 }
407
otPlatDiagAlarmCallback(otInstance * aInstance)408 void otPlatDiagAlarmCallback(otInstance *aInstance)
409 {
410 OT_UNUSED_VARIABLE(aInstance);
411 }
412 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
413
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)414 uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
415 {
416 OT_UNUSED_VARIABLE(aInstance);
417 return psRadioSpinel->GetRadioChannelMask(false);
418 }
419
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)420 uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
421 {
422 OT_UNUSED_VARIABLE(aInstance);
423 return psRadioSpinel->GetRadioChannelMask(true);
424 }
425
otPlatRadioGetState(otInstance * aInstance)426 otRadioState otPlatRadioGetState(otInstance *aInstance)
427 {
428 OT_UNUSED_VARIABLE(aInstance);
429 return psRadioSpinel->GetState();
430 }
431
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)432 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId,
433 const otMacKeyMaterial *aPrevKey, const otMacKeyMaterial *aCurrKey,
434 const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType)
435 {
436 SuccessOrDie(psRadioSpinel->SetMacKey(aKeyIdMode, aKeyId, aPrevKey, aCurrKey, aNextKey));
437 OT_UNUSED_VARIABLE(aInstance);
438 OT_UNUSED_VARIABLE(aKeyType);
439 }
440
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)441 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
442 {
443 SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, false));
444 OT_UNUSED_VARIABLE(aInstance);
445 }
446
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)447 void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
448 {
449 SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, true));
450 OT_UNUSED_VARIABLE(aInstance);
451 }
452
otPlatRadioGetNow(otInstance * aInstance)453 uint64_t otPlatRadioGetNow(otInstance *aInstance)
454 {
455 OT_UNUSED_VARIABLE(aInstance);
456 return psRadioSpinel->GetNow();
457 }
458
459 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslAccuracy(otInstance * aInstance)460 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
461 {
462 OT_UNUSED_VARIABLE(aInstance);
463
464 return psRadioSpinel->GetCslAccuracy();
465 }
466 #endif
467
468 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslUncertainty(otInstance * aInstance)469 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
470 {
471 OT_UNUSED_VARIABLE(aInstance);
472
473 return psRadioSpinel->GetCslUncertainty();
474 }
475 #endif
476
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)477 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel,
478 int8_t aMaxPower)
479 {
480 OT_UNUSED_VARIABLE(aInstance);
481 return psRadioSpinel->SetChannelMaxTransmitPower(aChannel, aMaxPower);
482 }
483
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)484 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
485 {
486 OT_UNUSED_VARIABLE(aInstance);
487 return psRadioSpinel->SetRadioRegion(aRegionCode);
488 }
489
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)490 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
491 {
492 OT_UNUSED_VARIABLE(aInstance);
493 return psRadioSpinel->GetRadioRegion(aRegionCode);
494 }
495
496 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)497 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
498 const otShortAddress aShortAddress,
499 const otExtAddress *aExtAddress)
500 {
501 OT_UNUSED_VARIABLE(aInstance);
502
503 return psRadioSpinel->ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress);
504 }
505 #endif
506
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)507 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart,
508 uint32_t aDuration)
509 {
510 OT_UNUSED_VARIABLE(aInstance);
511 OT_UNUSED_VARIABLE(aChannel);
512 OT_UNUSED_VARIABLE(aStart);
513 OT_UNUSED_VARIABLE(aDuration);
514 return OT_ERROR_NOT_IMPLEMENTED;
515 }
516
platformRadioInit(void)517 extern "C" void platformRadioInit(void)
518 {
519 spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
520 struct ot::Spinel::RadioSpinelCallbacks callbacks;
521
522 iidList[0] = 0;
523
524 psRadioSpinel = new ot::Spinel::RadioSpinel();
525 psSpinelDriver = new ot::Spinel::SpinelDriver();
526
527 psRadioUrl = new ot::Url::Url();
528 pSpinelInterface = new ot::Hdlc::HdlcInterface(*psRadioUrl);
529
530 OT_UNUSED_VARIABLE(psSpinelDriver->Init(*pSpinelInterface, true /* aSoftwareReset */,
531 iidList, OT_ARRAY_LENGTH(iidList)));
532
533 memset(&callbacks, 0, sizeof(callbacks));
534 #if OPENTHREAD_CONFIG_DIAG_ENABLE
535 callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
536 callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
537 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
538 callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
539 callbacks.mReceiveDone = otPlatRadioReceiveDone;
540 callbacks.mTransmitDone = otPlatRadioTxDone;
541 callbacks.mTxStarted = otPlatRadioTxStarted;
542
543 psRadioSpinel->SetCallbacks(callbacks);
544
545 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 && \
546 OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
547 bool aEnableRcpTimeSync = true;
548 #else
549 bool aEnableRcpTimeSync = false;
550 #endif
551 psRadioSpinel->Init(false /*aSkipRcpCompatibilityCheck*/, true /*aSoftwareReset*/,
552 psSpinelDriver, sRequiredRadioCaps, aEnableRcpTimeSync);
553 psRadioSpinel->SetTimeSyncState(true);
554 }
555
platformRadioDeinit(void)556 extern "C" void platformRadioDeinit(void)
557 {
558 psRadioSpinel->Deinit();
559 psSpinelDriver->Deinit();
560 }
561
notify_new_rx_frame(struct net_pkt * pkt)562 extern "C" int notify_new_rx_frame(struct net_pkt *pkt)
563 {
564 /* The RX frame is handled by Openthread stack */
565 net_pkt_unref(pkt);
566
567 return 0;
568 }
569
notify_new_tx_frame(struct net_pkt * pkt)570 extern "C" int notify_new_tx_frame(struct net_pkt *pkt)
571 {
572 k_fifo_put(&tx_pkt_fifo, pkt);
573 set_pending_event(PENDING_EVENT_FRAME_TO_SEND);
574
575 return 0;
576 }
577
platformRadioProcess(otInstance * aInstance)578 extern "C" void platformRadioProcess(otInstance *aInstance)
579 {
580 if (is_pending_event_set(PENDING_EVENT_FRAME_TO_SEND)) {
581 struct net_pkt *evt_pkt;
582
583 reset_pending_event(PENDING_EVENT_FRAME_TO_SEND);
584 while ((evt_pkt = (struct net_pkt *)k_fifo_get(&tx_pkt_fifo, K_NO_WAIT)) != NULL) {
585 openthread_handle_frame_to_send(aInstance, evt_pkt);
586 }
587 }
588
589 psSpinelDriver->Process(aInstance);
590 psRadioSpinel->Process(aInstance);
591 }
592