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