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_PLATFORM_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
otPlatDiagSetOutputCallback(otInstance * aInstance,otPlatDiagOutputCallback aCallback,void * aContext)349 void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext)
350 {
351     OT_UNUSED_VARIABLE(aInstance);
352 
353     psRadioSpinel->SetDiagOutputCallback(aCallback, aContext);
354 }
355 
otPlatDiagProcess(otInstance * aInstance,int argc,char * argv[])356 otError otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[])
357 {
358 	/* Deliver the platform specific diags commands to radio only ncp */
359 	OT_UNUSED_VARIABLE(aInstance);
360 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
361 	char *cur = cmd;
362 	char *end = cmd + sizeof(cmd);
363 
364 	for (int index = 0; index < argc; index++) {
365 		cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", argv[index]);
366 	}
367 
368 	return psRadioSpinel->PlatDiagProcess(cmd);
369 }
370 
otPlatDiagModeSet(bool aMode)371 void otPlatDiagModeSet(bool aMode)
372 {
373 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(aMode ? "start" : "stop"));
374 	psRadioSpinel->SetDiagEnabled(aMode);
375 
376 exit:
377 	return;
378 }
379 
otPlatDiagModeGet(void)380 bool otPlatDiagModeGet(void)
381 {
382 	return psRadioSpinel->IsDiagEnabled();
383 }
384 
otPlatDiagTxPowerSet(int8_t aTxPower)385 void otPlatDiagTxPowerSet(int8_t aTxPower)
386 {
387 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
388 
389 	snprintf(cmd, sizeof(cmd), "power %d", aTxPower);
390 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd));
391 
392 exit:
393 	return;
394 }
395 
otPlatDiagChannelSet(uint8_t aChannel)396 void otPlatDiagChannelSet(uint8_t aChannel)
397 {
398 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
399 
400 	snprintf(cmd, sizeof(cmd), "channel %d", aChannel);
401 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd));
402 
403 exit:
404 	return;
405 }
406 
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)407 void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
408 {
409 	OT_UNUSED_VARIABLE(aInstance);
410 	OT_UNUSED_VARIABLE(aFrame);
411 	OT_UNUSED_VARIABLE(aError);
412 }
413 
otPlatDiagAlarmCallback(otInstance * aInstance)414 void otPlatDiagAlarmCallback(otInstance *aInstance)
415 {
416 	OT_UNUSED_VARIABLE(aInstance);
417 }
418 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
419 
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)420 uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
421 {
422 	OT_UNUSED_VARIABLE(aInstance);
423 	return psRadioSpinel->GetRadioChannelMask(false);
424 }
425 
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)426 uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
427 {
428 	OT_UNUSED_VARIABLE(aInstance);
429 	return psRadioSpinel->GetRadioChannelMask(true);
430 }
431 
otPlatRadioGetState(otInstance * aInstance)432 otRadioState otPlatRadioGetState(otInstance *aInstance)
433 {
434 	OT_UNUSED_VARIABLE(aInstance);
435 	return psRadioSpinel->GetState();
436 }
437 
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)438 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId,
439 			  const otMacKeyMaterial *aPrevKey, const otMacKeyMaterial *aCurrKey,
440 			  const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType)
441 {
442 	SuccessOrDie(psRadioSpinel->SetMacKey(aKeyIdMode, aKeyId, aPrevKey, aCurrKey, aNextKey));
443 	OT_UNUSED_VARIABLE(aInstance);
444 	OT_UNUSED_VARIABLE(aKeyType);
445 }
446 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)447 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
448 {
449 	SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, false));
450 	OT_UNUSED_VARIABLE(aInstance);
451 }
452 
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)453 void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
454 {
455 	SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, true));
456 	OT_UNUSED_VARIABLE(aInstance);
457 }
458 
otPlatRadioGetNow(otInstance * aInstance)459 uint64_t otPlatRadioGetNow(otInstance *aInstance)
460 {
461 	OT_UNUSED_VARIABLE(aInstance);
462 	return psRadioSpinel->GetNow();
463 }
464 
465 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslAccuracy(otInstance * aInstance)466 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
467 {
468 	OT_UNUSED_VARIABLE(aInstance);
469 
470 	return psRadioSpinel->GetCslAccuracy();
471 }
472 #endif
473 
474 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslUncertainty(otInstance * aInstance)475 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
476 {
477 	OT_UNUSED_VARIABLE(aInstance);
478 
479 	return psRadioSpinel->GetCslUncertainty();
480 }
481 #endif
482 
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)483 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel,
484 					      int8_t aMaxPower)
485 {
486 	OT_UNUSED_VARIABLE(aInstance);
487 	return psRadioSpinel->SetChannelMaxTransmitPower(aChannel, aMaxPower);
488 }
489 
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)490 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
491 {
492 	OT_UNUSED_VARIABLE(aInstance);
493 	return psRadioSpinel->SetRadioRegion(aRegionCode);
494 }
495 
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)496 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
497 {
498 	OT_UNUSED_VARIABLE(aInstance);
499 	return psRadioSpinel->GetRadioRegion(aRegionCode);
500 }
501 
502 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)503 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
504 					  const otShortAddress aShortAddress,
505 					  const otExtAddress *aExtAddress)
506 {
507 	OT_UNUSED_VARIABLE(aInstance);
508 
509 	return psRadioSpinel->ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress);
510 }
511 #endif
512 
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)513 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart,
514 			     uint32_t aDuration)
515 {
516 	OT_UNUSED_VARIABLE(aInstance);
517 	OT_UNUSED_VARIABLE(aChannel);
518 	OT_UNUSED_VARIABLE(aStart);
519 	OT_UNUSED_VARIABLE(aDuration);
520 	return OT_ERROR_NOT_IMPLEMENTED;
521 }
522 
platformRadioInit(void)523 extern "C" void platformRadioInit(void)
524 {
525 	spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
526 	struct ot::Spinel::RadioSpinelCallbacks callbacks;
527 
528 	iidList[0] = 0;
529 
530 	psRadioSpinel = new ot::Spinel::RadioSpinel();
531 	psSpinelDriver = new ot::Spinel::SpinelDriver();
532 
533 	psRadioUrl = new ot::Url::Url();
534 	pSpinelInterface = new ot::Hdlc::HdlcInterface(*psRadioUrl);
535 
536 	OT_UNUSED_VARIABLE(psSpinelDriver->Init(*pSpinelInterface, true /* aSoftwareReset */,
537 						iidList, OT_ARRAY_LENGTH(iidList)));
538 
539 	memset(&callbacks, 0, sizeof(callbacks));
540 #if OPENTHREAD_CONFIG_DIAG_ENABLE
541 	callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
542 	callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
543 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
544 	callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
545 	callbacks.mReceiveDone = otPlatRadioReceiveDone;
546 	callbacks.mTransmitDone = otPlatRadioTxDone;
547 	callbacks.mTxStarted = otPlatRadioTxStarted;
548 
549 	psRadioSpinel->SetCallbacks(callbacks);
550 
551 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 &&                                   \
552 	OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
553 	bool aEnableRcpTimeSync = true;
554 #else
555 	bool aEnableRcpTimeSync = false;
556 #endif
557 	psRadioSpinel->Init(false /*aSkipRcpCompatibilityCheck*/, true /*aSoftwareReset*/,
558 			    psSpinelDriver, sRequiredRadioCaps, aEnableRcpTimeSync);
559 	psRadioSpinel->SetTimeSyncState(true);
560 }
561 
platformRadioDeinit(void)562 extern "C" void platformRadioDeinit(void)
563 {
564 	psRadioSpinel->Deinit();
565 	psSpinelDriver->Deinit();
566 }
567 
notify_new_rx_frame(struct net_pkt * pkt)568 extern "C" int notify_new_rx_frame(struct net_pkt *pkt)
569 {
570 	/* The RX frame is handled by Openthread stack */
571 	net_pkt_unref(pkt);
572 
573 	return 0;
574 }
575 
notify_new_tx_frame(struct net_pkt * pkt)576 extern "C" int notify_new_tx_frame(struct net_pkt *pkt)
577 {
578 	k_fifo_put(&tx_pkt_fifo, pkt);
579 	set_pending_event(PENDING_EVENT_FRAME_TO_SEND);
580 
581 	return 0;
582 }
583 
platformRadioProcess(otInstance * aInstance)584 extern "C" void platformRadioProcess(otInstance *aInstance)
585 {
586 	if (is_pending_event_set(PENDING_EVENT_FRAME_TO_SEND)) {
587 		struct net_pkt *evt_pkt;
588 
589 		reset_pending_event(PENDING_EVENT_FRAME_TO_SEND);
590 		while ((evt_pkt = (struct net_pkt *)k_fifo_get(&tx_pkt_fifo, K_NO_WAIT)) != NULL) {
591 			openthread_handle_frame_to_send(aInstance, evt_pkt);
592 		}
593 	}
594 
595 	psSpinelDriver->Process(aInstance);
596 	psRadioSpinel->Process(aInstance);
597 }
598