1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  Copyright (c) 2022-2025, 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 #include <stdalign.h>
50 #include <common/new.hpp>
51 
52 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
53 #include <openthread/nat64.h>
54 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
55 
56 #define PKT_IS_IPv4(_p) ((NET_IPV6_HDR(_p)->vtc & 0xf0) == 0x40)
57 
58 enum pending_events {
59 	PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send  */
60 	PENDING_EVENT_COUNT          /* Keep last */
61 };
62 
63 ATOMIC_DEFINE(pending_events, PENDING_EVENT_COUNT);
64 K_FIFO_DEFINE(tx_pkt_fifo);
65 
66 static ot::Spinel::RadioSpinel *psRadioSpinel;
67 static ot::Url::Url *psRadioUrl;
68 static ot::Hdlc::HdlcInterface *pSpinelInterface;
69 static ot::Spinel::SpinelDriver *psSpinelDriver;
70 
71 alignas(ot::Spinel::RadioSpinel) static uint8_t gRadioBuf[sizeof(ot::Spinel::RadioSpinel)];
72 alignas(ot::Url::Url) static uint8_t gUrlBuf[sizeof(ot::Url::Url)];
73 alignas(ot::Hdlc::HdlcInterface) static uint8_t gIfaceBuf[sizeof(ot::Hdlc::HdlcInterface)];
74 alignas(ot::Spinel::SpinelDriver) static uint8_t gDriverBuf[sizeof(ot::Spinel::SpinelDriver)];
75 
76 static const otRadioCaps sRequiredRadioCaps =
77 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
78 	OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING |
79 #endif
80 	OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF;
81 
is_pending_event_set(enum pending_events event)82 static inline bool is_pending_event_set(enum pending_events event)
83 {
84 	return atomic_test_bit(pending_events, event);
85 }
86 
set_pending_event(enum pending_events event)87 static void set_pending_event(enum pending_events event)
88 {
89 	atomic_set_bit(pending_events, event);
90 	otSysEventSignalPending();
91 }
92 
reset_pending_event(enum pending_events event)93 static void reset_pending_event(enum pending_events event)
94 {
95 	atomic_clear_bit(pending_events, event);
96 }
97 
openthread_handle_frame_to_send(otInstance * instance,struct net_pkt * pkt)98 static void openthread_handle_frame_to_send(otInstance *instance, struct net_pkt *pkt)
99 {
100 	struct net_buf *buf;
101 	otMessage *message;
102 	otMessageSettings settings;
103 	bool is_ip4 = PKT_IS_IPv4(pkt);
104 
105 	NET_DBG("Sending %s packet to ot stack", is_ip4 ? "IPv4" : "IPv6");
106 
107 	settings.mPriority = OT_MESSAGE_PRIORITY_NORMAL;
108 	settings.mLinkSecurityEnabled = true;
109 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
110 	if (is_ip4) {
111 		message = otIp4NewMessage(instance, &settings);
112 	} else {
113 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR*/
114 		message = otIp6NewMessage(instance, &settings);
115 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
116 	}
117 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
118 	if (message == NULL) {
119 		goto exit;
120 	}
121 
122 	for (buf = pkt->buffer; buf; buf = buf->frags) {
123 		if (otMessageAppend(message, buf->data, buf->len) != OT_ERROR_NONE) {
124 			NET_ERR("Error while appending to otMessage");
125 			otMessageFree(message);
126 			goto exit;
127 		}
128 	}
129 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
130 	if (is_ip4) {
131 		if (otNat64Send(instance, message) != OT_ERROR_NONE) {
132 			NET_ERR("Error while calling otNat64Send");
133 			goto exit;
134 		}
135 	} else {
136 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR*/
137 
138 		if (otIp6Send(instance, message) != OT_ERROR_NONE) {
139 			NET_ERR("Error while calling otIp6Send");
140 			goto exit;
141 		}
142 #if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR)
143 	}
144 #endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */
145 
146 exit:
147 	net_pkt_unref(pkt);
148 }
149 
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)150 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
151 {
152 	OT_UNUSED_VARIABLE(aInstance);
153 	SuccessOrDie(psRadioSpinel->GetIeeeEui64(aIeeeEui64));
154 }
155 
otPlatRadioSetPanId(otInstance * aInstance,uint16_t panid)156 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
157 {
158 	OT_UNUSED_VARIABLE(aInstance);
159 	SuccessOrDie(psRadioSpinel->SetPanId(panid));
160 }
161 
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aAddress)162 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
163 {
164 	OT_UNUSED_VARIABLE(aInstance);
165 	otExtAddress addr;
166 
167 	for (size_t i = 0; i < sizeof(addr); i++) {
168 		addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i];
169 	}
170 
171 	SuccessOrDie(psRadioSpinel->SetExtendedAddress(addr));
172 }
173 
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aAddress)174 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
175 {
176 	OT_UNUSED_VARIABLE(aInstance);
177 	SuccessOrDie(psRadioSpinel->SetShortAddress(aAddress));
178 }
179 
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)180 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
181 {
182 	OT_UNUSED_VARIABLE(aInstance);
183 	SuccessOrDie(psRadioSpinel->SetPromiscuous(aEnable));
184 }
185 
otPlatRadioIsEnabled(otInstance * aInstance)186 bool otPlatRadioIsEnabled(otInstance *aInstance)
187 {
188 	OT_UNUSED_VARIABLE(aInstance);
189 	return psRadioSpinel->IsEnabled();
190 }
191 
otPlatRadioEnable(otInstance * aInstance)192 otError otPlatRadioEnable(otInstance *aInstance)
193 {
194 	return psRadioSpinel->Enable(aInstance);
195 }
196 
otPlatRadioDisable(otInstance * aInstance)197 otError otPlatRadioDisable(otInstance *aInstance)
198 {
199 	OT_UNUSED_VARIABLE(aInstance);
200 	return psRadioSpinel->Disable();
201 }
202 
otPlatRadioSleep(otInstance * aInstance)203 otError otPlatRadioSleep(otInstance *aInstance)
204 {
205 	OT_UNUSED_VARIABLE(aInstance);
206 	return psRadioSpinel->Sleep();
207 }
208 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)209 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
210 {
211 	OT_UNUSED_VARIABLE(aInstance);
212 	return psRadioSpinel->Receive(aChannel);
213 }
214 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)215 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
216 {
217 	OT_UNUSED_VARIABLE(aInstance);
218 	return psRadioSpinel->Transmit(*aFrame);
219 }
220 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)221 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
222 {
223 	OT_UNUSED_VARIABLE(aInstance);
224 	return &psRadioSpinel->GetTransmitFrame();
225 }
226 
otPlatRadioGetRssi(otInstance * aInstance)227 int8_t otPlatRadioGetRssi(otInstance *aInstance)
228 {
229 	OT_UNUSED_VARIABLE(aInstance);
230 	return psRadioSpinel->GetRssi();
231 }
232 
otPlatRadioGetCaps(otInstance * aInstance)233 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
234 {
235 	OT_UNUSED_VARIABLE(aInstance);
236 	return psRadioSpinel->GetRadioCaps();
237 }
238 
otPlatRadioGetVersionString(otInstance * aInstance)239 const char *otPlatRadioGetVersionString(otInstance *aInstance)
240 {
241 	OT_UNUSED_VARIABLE(aInstance);
242 	return psRadioSpinel->GetVersion();
243 }
244 
otPlatRadioGetPromiscuous(otInstance * aInstance)245 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
246 {
247 	OT_UNUSED_VARIABLE(aInstance);
248 	return psRadioSpinel->IsPromiscuous();
249 }
250 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)251 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
252 {
253 	OT_UNUSED_VARIABLE(aInstance);
254 	SuccessOrDie(psRadioSpinel->EnableSrcMatch(aEnable));
255 }
256 
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)257 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
258 {
259 	OT_UNUSED_VARIABLE(aInstance);
260 	return psRadioSpinel->AddSrcMatchShortEntry(aShortAddress);
261 }
262 
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)263 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
264 {
265 	OT_UNUSED_VARIABLE(aInstance);
266 	otExtAddress addr;
267 
268 	for (size_t i = 0; i < sizeof(addr); i++) {
269 		addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
270 	}
271 
272 	return psRadioSpinel->AddSrcMatchExtEntry(addr);
273 }
274 
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)275 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
276 {
277 	OT_UNUSED_VARIABLE(aInstance);
278 	return psRadioSpinel->ClearSrcMatchShortEntry(aShortAddress);
279 }
280 
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)281 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
282 {
283 	OT_UNUSED_VARIABLE(aInstance);
284 	otExtAddress addr;
285 
286 	for (size_t i = 0; i < sizeof(addr); i++) {
287 		addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i];
288 	}
289 
290 	return psRadioSpinel->ClearSrcMatchExtEntry(addr);
291 }
292 
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)293 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
294 {
295 	OT_UNUSED_VARIABLE(aInstance);
296 	SuccessOrDie(psRadioSpinel->ClearSrcMatchShortEntries());
297 }
298 
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)299 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
300 {
301 	OT_UNUSED_VARIABLE(aInstance);
302 	SuccessOrDie(psRadioSpinel->ClearSrcMatchExtEntries());
303 }
304 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)305 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
306 {
307 	OT_UNUSED_VARIABLE(aInstance);
308 	return psRadioSpinel->EnergyScan(aScanChannel, aScanDuration);
309 }
310 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)311 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
312 {
313 	otError error;
314 
315 	OT_UNUSED_VARIABLE(aInstance);
316 	VerifyOrExit(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
317 	error = psRadioSpinel->GetTransmitPower(*aPower);
318 
319 exit:
320 	return error;
321 }
322 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)323 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
324 {
325 	OT_UNUSED_VARIABLE(aInstance);
326 	return psRadioSpinel->SetTransmitPower(aPower);
327 }
328 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)329 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
330 {
331 	otError error;
332 
333 	OT_UNUSED_VARIABLE(aInstance);
334 	VerifyOrExit(aThreshold != NULL, error = OT_ERROR_INVALID_ARGS);
335 	error = psRadioSpinel->GetCcaEnergyDetectThreshold(*aThreshold);
336 
337 exit:
338 	return error;
339 }
340 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)341 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
342 {
343 	OT_UNUSED_VARIABLE(aInstance);
344 	return psRadioSpinel->SetCcaEnergyDetectThreshold(aThreshold);
345 }
346 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)347 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
348 {
349 	OT_UNUSED_VARIABLE(aInstance);
350 	return psRadioSpinel->GetReceiveSensitivity();
351 }
352 
353 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)354 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
355 {
356 	OT_UNUSED_VARIABLE(aInstance);
357 	return psRadioSpinel->SetCoexEnabled(aEnabled);
358 }
359 
otPlatRadioIsCoexEnabled(otInstance * aInstance)360 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
361 {
362 	OT_UNUSED_VARIABLE(aInstance);
363 	return psRadioSpinel->IsCoexEnabled();
364 }
365 
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)366 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
367 {
368 	OT_UNUSED_VARIABLE(aInstance);
369 
370 	otError error = OT_ERROR_NONE;
371 
372 	VerifyOrExit(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS);
373 
374 	error = psRadioSpinel->GetCoexMetrics(*aCoexMetrics);
375 
376 exit:
377 	return error;
378 }
379 #endif
380 
381 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagSetOutputCallback(otInstance * aInstance,otPlatDiagOutputCallback aCallback,void * aContext)382 void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext)
383 {
384     OT_UNUSED_VARIABLE(aInstance);
385 
386     psRadioSpinel->SetDiagOutputCallback(aCallback, aContext);
387 }
388 
otPlatDiagProcess(otInstance * aInstance,int argc,char * argv[])389 otError otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[])
390 {
391 	/* Deliver the platform specific diags commands to radio only ncp */
392 	OT_UNUSED_VARIABLE(aInstance);
393 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
394 	char *cur = cmd;
395 	char *end = cmd + sizeof(cmd);
396 
397 	for (int index = 0; index < argc; index++) {
398 		cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", argv[index]);
399 	}
400 
401 	return psRadioSpinel->PlatDiagProcess(cmd);
402 }
403 
otPlatDiagModeSet(bool aMode)404 void otPlatDiagModeSet(bool aMode)
405 {
406 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(aMode ? "start" : "stop"));
407 	psRadioSpinel->SetDiagEnabled(aMode);
408 
409 exit:
410 	return;
411 }
412 
otPlatDiagModeGet(void)413 bool otPlatDiagModeGet(void)
414 {
415 	return psRadioSpinel->IsDiagEnabled();
416 }
417 
otPlatDiagTxPowerSet(int8_t aTxPower)418 void otPlatDiagTxPowerSet(int8_t aTxPower)
419 {
420 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
421 
422 	snprintf(cmd, sizeof(cmd), "power %d", aTxPower);
423 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd));
424 
425 exit:
426 	return;
427 }
428 
otPlatDiagChannelSet(uint8_t aChannel)429 void otPlatDiagChannelSet(uint8_t aChannel)
430 {
431 	char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
432 
433 	snprintf(cmd, sizeof(cmd), "channel %d", aChannel);
434 	SuccessOrExit(psRadioSpinel->PlatDiagProcess(cmd));
435 
436 exit:
437 	return;
438 }
439 
otPlatDiagRadioReceived(otInstance * aInstance,otRadioFrame * aFrame,otError aError)440 void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
441 {
442 	OT_UNUSED_VARIABLE(aInstance);
443 	OT_UNUSED_VARIABLE(aFrame);
444 	OT_UNUSED_VARIABLE(aError);
445 }
446 
otPlatDiagAlarmCallback(otInstance * aInstance)447 void otPlatDiagAlarmCallback(otInstance *aInstance)
448 {
449 	OT_UNUSED_VARIABLE(aInstance);
450 }
451 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
452 
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)453 uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
454 {
455 	OT_UNUSED_VARIABLE(aInstance);
456 	return psRadioSpinel->GetRadioChannelMask(false);
457 }
458 
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)459 uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
460 {
461 	OT_UNUSED_VARIABLE(aInstance);
462 	return psRadioSpinel->GetRadioChannelMask(true);
463 }
464 
otPlatRadioGetState(otInstance * aInstance)465 otRadioState otPlatRadioGetState(otInstance *aInstance)
466 {
467 	OT_UNUSED_VARIABLE(aInstance);
468 	return psRadioSpinel->GetState();
469 }
470 
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)471 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId,
472 			  const otMacKeyMaterial *aPrevKey, const otMacKeyMaterial *aCurrKey,
473 			  const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType)
474 {
475 	SuccessOrDie(psRadioSpinel->SetMacKey(aKeyIdMode, aKeyId, aPrevKey, aCurrKey, aNextKey));
476 	OT_UNUSED_VARIABLE(aInstance);
477 	OT_UNUSED_VARIABLE(aKeyType);
478 }
479 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)480 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
481 {
482 	SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, false));
483 	OT_UNUSED_VARIABLE(aInstance);
484 }
485 
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)486 void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
487 {
488 	SuccessOrDie(psRadioSpinel->SetMacFrameCounter(aMacFrameCounter, true));
489 	OT_UNUSED_VARIABLE(aInstance);
490 }
491 
otPlatRadioGetNow(otInstance * aInstance)492 uint64_t otPlatRadioGetNow(otInstance *aInstance)
493 {
494 	OT_UNUSED_VARIABLE(aInstance);
495 	return psRadioSpinel->GetNow();
496 }
497 
498 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslAccuracy(otInstance * aInstance)499 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
500 {
501 	OT_UNUSED_VARIABLE(aInstance);
502 
503 	return psRadioSpinel->GetCslAccuracy();
504 }
505 #endif
506 
507 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
otPlatRadioGetCslUncertainty(otInstance * aInstance)508 uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
509 {
510 	OT_UNUSED_VARIABLE(aInstance);
511 
512 	return psRadioSpinel->GetCslUncertainty();
513 }
514 #endif
515 
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)516 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel,
517 					      int8_t aMaxPower)
518 {
519 	OT_UNUSED_VARIABLE(aInstance);
520 	return psRadioSpinel->SetChannelMaxTransmitPower(aChannel, aMaxPower);
521 }
522 
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)523 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
524 {
525 	OT_UNUSED_VARIABLE(aInstance);
526 	return psRadioSpinel->SetRadioRegion(aRegionCode);
527 }
528 
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)529 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
530 {
531 	OT_UNUSED_VARIABLE(aInstance);
532 	return psRadioSpinel->GetRadioRegion(aRegionCode);
533 }
534 
535 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)536 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
537 					  const otShortAddress aShortAddress,
538 					  const otExtAddress *aExtAddress)
539 {
540 	OT_UNUSED_VARIABLE(aInstance);
541 
542 	return psRadioSpinel->ConfigureEnhAckProbing(aLinkMetrics, aShortAddress, *aExtAddress);
543 }
544 #endif
545 
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)546 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart,
547 			     uint32_t aDuration)
548 {
549 	OT_UNUSED_VARIABLE(aInstance);
550 	OT_UNUSED_VARIABLE(aChannel);
551 	OT_UNUSED_VARIABLE(aStart);
552 	OT_UNUSED_VARIABLE(aDuration);
553 	return OT_ERROR_NOT_IMPLEMENTED;
554 }
555 
platformRadioInit(void)556 extern "C" void platformRadioInit(void)
557 {
558 	spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
559 	struct ot::Spinel::RadioSpinelCallbacks callbacks;
560 
561 	iidList[0] = 0;
562 
563 	psRadioSpinel = new(gRadioBuf) ot::Spinel::RadioSpinel();
564 	psSpinelDriver = new(gDriverBuf) ot::Spinel::SpinelDriver();
565 
566 	psRadioUrl = new(gUrlBuf) ot::Url::Url();
567 	pSpinelInterface = new(gIfaceBuf) ot::Hdlc::HdlcInterface(*psRadioUrl);
568 
569 	OT_UNUSED_VARIABLE(psSpinelDriver->Init(*pSpinelInterface, true /* aSoftwareReset */,
570 						iidList, OT_ARRAY_LENGTH(iidList)));
571 
572 	memset(&callbacks, 0, sizeof(callbacks));
573 #if OPENTHREAD_CONFIG_DIAG_ENABLE
574 	callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
575 	callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
576 #endif /* OPENTHREAD_CONFIG_DIAG_ENABLE */
577 	callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
578 	callbacks.mReceiveDone = otPlatRadioReceiveDone;
579 	callbacks.mTransmitDone = otPlatRadioTxDone;
580 	callbacks.mTxStarted = otPlatRadioTxStarted;
581 
582 	psRadioSpinel->SetCallbacks(callbacks);
583 
584 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 &&                                   \
585 	OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
586 	bool aEnableRcpTimeSync = true;
587 #else
588 	bool aEnableRcpTimeSync = false;
589 #endif
590 	psRadioSpinel->Init(false /*aSkipRcpCompatibilityCheck*/, true /*aSoftwareReset*/,
591 			    psSpinelDriver, sRequiredRadioCaps, aEnableRcpTimeSync);
592 	psRadioSpinel->SetTimeSyncState(true);
593 }
594 
platformRadioDeinit(void)595 extern "C" void platformRadioDeinit(void)
596 {
597 	psRadioSpinel->Deinit();
598 	psSpinelDriver->Deinit();
599 }
600 
notify_new_rx_frame(struct net_pkt * pkt)601 extern "C" int notify_new_rx_frame(struct net_pkt *pkt)
602 {
603 	/* The RX frame is handled by Openthread stack */
604 	net_pkt_unref(pkt);
605 
606 	return 0;
607 }
608 
notify_new_tx_frame(struct net_pkt * pkt)609 extern "C" int notify_new_tx_frame(struct net_pkt *pkt)
610 {
611 	k_fifo_put(&tx_pkt_fifo, pkt);
612 	set_pending_event(PENDING_EVENT_FRAME_TO_SEND);
613 
614 	return 0;
615 }
616 
platformRadioProcess(otInstance * aInstance)617 extern "C" void platformRadioProcess(otInstance *aInstance)
618 {
619 	if (is_pending_event_set(PENDING_EVENT_FRAME_TO_SEND)) {
620 		struct net_pkt *evt_pkt;
621 
622 		reset_pending_event(PENDING_EVENT_FRAME_TO_SEND);
623 		while ((evt_pkt = (struct net_pkt *)k_fifo_get(&tx_pkt_fifo, K_NO_WAIT)) != NULL) {
624 			openthread_handle_frame_to_send(aInstance, evt_pkt);
625 		}
626 	}
627 
628 	psSpinelDriver->Process(aInstance);
629 	psRadioSpinel->Process(aInstance);
630 }
631