1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  *   This file implements the OpenThread platform abstraction
10  *   for radio communication.
11  *
12  */
13 
14 #define LOG_MODULE_NAME net_otPlat_radio
15 
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
18 
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #include <kernel.h>
25 #include <device.h>
26 #include <net/ieee802154_radio.h>
27 #include <net/net_pkt.h>
28 #include <sys/__assert.h>
29 
30 #include <openthread/ip6.h>
31 #include <openthread-system.h>
32 #include <openthread/instance.h>
33 #include <openthread/platform/radio.h>
34 #include <openthread/platform/diag.h>
35 #include <openthread/message.h>
36 
37 #include "platform-zephyr.h"
38 
39 #define SHORT_ADDRESS_SIZE 2
40 
41 #define FCS_SIZE 2
42 #if defined(CONFIG_IEEE802154_2015)
43 #define ACK_PKT_LENGTH 127
44 #else
45 #define ACK_PKT_LENGTH 5
46 #endif
47 
48 #define FRAME_TYPE_MASK 0x07
49 #define FRAME_TYPE_ACK 0x02
50 
51 #if IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE)
52 #define OT_WORKER_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY)
53 #else
54 #define OT_WORKER_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY)
55 #endif
56 
57 enum pending_events {
58 	PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send  */
59 	PENDING_EVENT_FRAME_RECEIVED, /* Radio has received new frame */
60 	PENDING_EVENT_RX_FAILED, /* The RX failed */
61 	PENDING_EVENT_TX_STARTED, /* Radio has started transmitting */
62 	PENDING_EVENT_TX_DONE, /* Radio transmission finished */
63 	PENDING_EVENT_DETECT_ENERGY, /* Requested to start Energy Detection procedure */
64 	PENDING_EVENT_DETECT_ENERGY_DONE, /* Energy Detection finished */
65 	PENDING_EVENT_SLEEP, /* Sleep if idle */
66 	PENDING_EVENT_COUNT /* Keep last */
67 };
68 
69 K_SEM_DEFINE(radio_sem, 0, 1);
70 
71 static otRadioState sState = OT_RADIO_STATE_DISABLED;
72 
73 static otRadioFrame sTransmitFrame;
74 static otRadioFrame ack_frame;
75 static uint8_t ack_psdu[ACK_PKT_LENGTH];
76 
77 static struct net_pkt *tx_pkt;
78 static struct net_buf *tx_payload;
79 
80 static const struct device *radio_dev;
81 static struct ieee802154_radio_api *radio_api;
82 
83 static int8_t tx_power;
84 static uint16_t channel;
85 static bool promiscuous;
86 
87 static uint16_t energy_detection_time;
88 static uint8_t energy_detection_channel;
89 static int16_t energy_detected_value;
90 
91 ATOMIC_DEFINE(pending_events, PENDING_EVENT_COUNT);
92 K_KERNEL_STACK_DEFINE(ot_task_stack,
93 		      CONFIG_OPENTHREAD_RADIO_WORKQUEUE_STACK_SIZE);
94 static struct k_work_q ot_work_q;
95 static otError rx_result;
96 static otError tx_result;
97 
98 K_FIFO_DEFINE(rx_pkt_fifo);
99 K_FIFO_DEFINE(tx_pkt_fifo);
100 
is_pending_event_set(enum pending_events event)101 static inline bool is_pending_event_set(enum pending_events event)
102 {
103 	return atomic_test_bit(pending_events, event);
104 }
105 
set_pending_event(enum pending_events event)106 static void set_pending_event(enum pending_events event)
107 {
108 	atomic_set_bit(pending_events, event);
109 	otSysEventSignalPending();
110 }
111 
reset_pending_event(enum pending_events event)112 static void reset_pending_event(enum pending_events event)
113 {
114 	atomic_clear_bit(pending_events, event);
115 }
116 
clear_pending_events(void)117 static inline void clear_pending_events(void)
118 {
119 	atomic_clear(pending_events);
120 }
121 
energy_detected(const struct device * dev,int16_t max_ed)122 void energy_detected(const struct device *dev, int16_t max_ed)
123 {
124 	if (dev == radio_dev) {
125 		energy_detected_value = max_ed;
126 		set_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
127 	}
128 }
129 
ieee802154_radio_handle_ack(struct net_if * iface,struct net_pkt * pkt)130 enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface,
131 					     struct net_pkt *pkt)
132 {
133 	ARG_UNUSED(iface);
134 
135 	size_t ack_len = net_pkt_get_len(pkt);
136 
137 	if (ack_len > ACK_PKT_LENGTH) {
138 		return NET_CONTINUE;
139 	}
140 
141 	if ((*net_pkt_data(pkt) & FRAME_TYPE_MASK) != FRAME_TYPE_ACK) {
142 		return NET_CONTINUE;
143 	}
144 
145 	if (ack_frame.mLength != 0) {
146 		LOG_ERR("Overwriting unhandled ACK frame.");
147 	}
148 
149 	if (net_pkt_read(pkt, ack_psdu, ack_len) < 0) {
150 		LOG_ERR("Failed to read ACK frame.");
151 		return NET_CONTINUE;
152 	}
153 
154 	ack_frame.mPsdu = ack_psdu;
155 	ack_frame.mLength = ack_len;
156 	ack_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt);
157 	ack_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi(pkt);
158 
159 #if defined(CONFIG_NET_PKT_TIMESTAMP)
160 	struct net_ptp_time *pkt_time = net_pkt_timestamp(pkt);
161 
162 	ack_frame.mInfo.mRxInfo.mTimestamp =
163 		pkt_time->second * USEC_PER_SEC + pkt_time->nanosecond / NSEC_PER_USEC;
164 #endif
165 
166 	return NET_OK;
167 }
168 
handle_radio_event(const struct device * dev,enum ieee802154_event evt,void * event_params)169 void handle_radio_event(const struct device *dev, enum ieee802154_event evt,
170 			void *event_params)
171 {
172 	ARG_UNUSED(event_params);
173 
174 	switch (evt) {
175 	case IEEE802154_EVENT_TX_STARTED:
176 		if (sState == OT_RADIO_STATE_TRANSMIT) {
177 			set_pending_event(PENDING_EVENT_TX_STARTED);
178 		}
179 		break;
180 	case IEEE802154_EVENT_RX_FAILED:
181 		if (sState == OT_RADIO_STATE_RECEIVE) {
182 			switch (*(enum ieee802154_rx_fail_reason *) event_params) {
183 			case IEEE802154_RX_FAIL_NOT_RECEIVED:
184 				rx_result = OT_ERROR_NO_FRAME_RECEIVED;
185 				break;
186 
187 			case IEEE802154_RX_FAIL_INVALID_FCS:
188 				rx_result = OT_ERROR_FCS;
189 				break;
190 
191 			case IEEE802154_RX_FAIL_ADDR_FILTERED:
192 				rx_result = OT_ERROR_DESTINATION_ADDRESS_FILTERED;
193 				break;
194 
195 			case IEEE802154_RX_FAIL_OTHER:
196 			default:
197 				rx_result = OT_ERROR_FAILED;
198 				break;
199 			}
200 			set_pending_event(PENDING_EVENT_RX_FAILED);
201 		}
202 		break;
203 	case IEEE802154_EVENT_SLEEP:
204 		set_pending_event(PENDING_EVENT_SLEEP);
205 		break;
206 	default:
207 		/* do nothing - ignore event */
208 		break;
209 	}
210 }
211 
dataInit(void)212 static void dataInit(void)
213 {
214 	tx_pkt = net_pkt_alloc(K_NO_WAIT);
215 	__ASSERT_NO_MSG(tx_pkt != NULL);
216 
217 	tx_payload = net_pkt_get_reserve_tx_data(K_NO_WAIT);
218 	__ASSERT_NO_MSG(tx_payload != NULL);
219 
220 	net_pkt_append_buffer(tx_pkt, tx_payload);
221 
222 	sTransmitFrame.mPsdu = tx_payload->data;
223 }
224 
platformRadioInit(void)225 void platformRadioInit(void)
226 {
227 	struct ieee802154_config cfg;
228 
229 	dataInit();
230 
231 	radio_dev = device_get_binding(CONFIG_NET_CONFIG_IEEE802154_DEV_NAME);
232 	__ASSERT_NO_MSG(radio_dev != NULL);
233 
234 	radio_api = (struct ieee802154_radio_api *)radio_dev->api;
235 	if (!radio_api) {
236 		return;
237 	}
238 
239 	k_work_queue_start(&ot_work_q, ot_task_stack,
240 			   K_KERNEL_STACK_SIZEOF(ot_task_stack),
241 			   OT_WORKER_PRIORITY, NULL);
242 	k_thread_name_set(&ot_work_q.thread, "ot_radio_workq");
243 
244 	if ((radio_api->get_capabilities(radio_dev) &
245 	     IEEE802154_HW_TX_RX_ACK) != IEEE802154_HW_TX_RX_ACK) {
246 		LOG_ERR("Only radios with automatic ack handling "
247 			"are currently supported");
248 		k_panic();
249 	}
250 
251 	cfg.event_handler = handle_radio_event;
252 	radio_api->configure(radio_dev, IEEE802154_CONFIG_EVENT_HANDLER, &cfg);
253 }
254 
transmit_message(struct k_work * tx_job)255 void transmit_message(struct k_work *tx_job)
256 {
257 	int tx_err;
258 
259 	ARG_UNUSED(tx_job);
260 
261 	/*
262 	 * The payload is already in tx_payload->data,
263 	 * but we need to set the length field
264 	 * according to sTransmitFrame.length.
265 	 * We subtract the FCS size as radio driver
266 	 * adds CRC and increases frame length on its own.
267 	 */
268 	tx_payload->len = sTransmitFrame.mLength - FCS_SIZE;
269 
270 	channel = sTransmitFrame.mChannel;
271 
272 	radio_api->set_channel(radio_dev, sTransmitFrame.mChannel);
273 	radio_api->set_txpower(radio_dev, tx_power);
274 
275 	net_pkt_set_ieee802154_frame_secured(tx_pkt,
276 					     sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed);
277 	net_pkt_set_ieee802154_mac_hdr_rdy(tx_pkt, sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated);
278 
279 	if ((radio_api->get_capabilities(radio_dev) & IEEE802154_HW_TXTIME) &&
280 	    (sTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)) {
281 		uint64_t tx_at = sTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime +
282 				 sTransmitFrame.mInfo.mTxInfo.mTxDelay;
283 		net_pkt_set_txtime(tx_pkt, NSEC_PER_USEC * tx_at);
284 		tx_err =
285 			radio_api->tx(radio_dev, IEEE802154_TX_MODE_TXTIME_CCA, tx_pkt, tx_payload);
286 	} else if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) {
287 		if (radio_api->get_capabilities(radio_dev) & IEEE802154_HW_CSMA) {
288 			tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_CSMA_CA, tx_pkt,
289 					       tx_payload);
290 		} else {
291 			tx_err = radio_api->cca(radio_dev);
292 			if (tx_err == 0) {
293 				tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, tx_pkt,
294 						       tx_payload);
295 			}
296 		}
297 	} else {
298 		tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_DIRECT, tx_pkt, tx_payload);
299 	}
300 
301 	/*
302 	 * OpenThread handles the following errors:
303 	 * - OT_ERROR_NONE
304 	 * - OT_ERROR_NO_ACK
305 	 * - OT_ERROR_CHANNEL_ACCESS_FAILURE
306 	 * - OT_ERROR_ABORT
307 	 * Any other error passed to `otPlatRadioTxDone` will result in assertion.
308 	 */
309 	switch (tx_err) {
310 	case 0:
311 		tx_result = OT_ERROR_NONE;
312 		break;
313 	case -ENOMSG:
314 		tx_result = OT_ERROR_NO_ACK;
315 		break;
316 	case -EBUSY:
317 		tx_result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
318 		break;
319 	case -EIO:
320 		tx_result = OT_ERROR_ABORT;
321 		break;
322 	default:
323 		tx_result = OT_ERROR_CHANNEL_ACCESS_FAILURE;
324 		break;
325 	}
326 
327 	set_pending_event(PENDING_EVENT_TX_DONE);
328 }
329 
handle_tx_done(otInstance * aInstance)330 static inline void handle_tx_done(otInstance *aInstance)
331 {
332 	sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed =
333 		net_pkt_ieee802154_frame_secured(tx_pkt);
334 	sTransmitFrame.mInfo.mTxInfo.mIsHeaderUpdated = net_pkt_ieee802154_mac_hdr_rdy(tx_pkt);
335 
336 	if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
337 		otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, tx_result);
338 	} else {
339 		if (sTransmitFrame.mPsdu[0] & IEEE802154_AR_FLAG_SET) {
340 			if (ack_frame.mLength == 0) {
341 				LOG_DBG("No ACK received.");
342 				otPlatRadioTxDone(aInstance, &sTransmitFrame,
343 						  NULL, OT_ERROR_NO_ACK);
344 			} else {
345 				otPlatRadioTxDone(aInstance, &sTransmitFrame,
346 						  &ack_frame, tx_result);
347 			}
348 		} else {
349 			otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, tx_result);
350 		}
351 		ack_frame.mLength = 0;
352 	}
353 }
354 
openthread_handle_received_frame(otInstance * instance,struct net_pkt * pkt)355 static void openthread_handle_received_frame(otInstance *instance,
356 					     struct net_pkt *pkt)
357 {
358 	otRadioFrame recv_frame;
359 
360 	recv_frame.mPsdu = net_buf_frag_last(pkt->buffer)->data;
361 	/* Length inc. CRC. */
362 	recv_frame.mLength = net_buf_frags_len(pkt->buffer);
363 	recv_frame.mChannel = platformRadioChannelGet(instance);
364 	recv_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt);
365 	recv_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi(pkt);
366 	recv_frame.mInfo.mRxInfo.mAckedWithFramePending = net_pkt_ieee802154_ack_fpb(pkt);
367 
368 #if defined(CONFIG_NET_PKT_TIMESTAMP)
369 	struct net_ptp_time *pkt_time = net_pkt_timestamp(pkt);
370 
371 	recv_frame.mInfo.mRxInfo.mTimestamp =
372 		pkt_time->second * USEC_PER_SEC + pkt_time->nanosecond / NSEC_PER_USEC;
373 #endif
374 
375 #if defined(CONFIG_IEEE802154_2015)
376 	if (net_pkt_ieee802154_arb(pkt) && net_pkt_ieee802154_fv2015(pkt)) {
377 		recv_frame.mInfo.mRxInfo.mAckedWithSecEnhAck =
378 			net_pkt_ieee802154_ack_seb(pkt);
379 		recv_frame.mInfo.mRxInfo.mAckFrameCounter =
380 			net_pkt_ieee802154_ack_fc(pkt);
381 		recv_frame.mInfo.mRxInfo.mAckKeyId =
382 			net_pkt_ieee802154_ack_keyid(pkt);
383 	}
384 #endif
385 
386 	if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
387 		otPlatDiagRadioReceiveDone(instance, &recv_frame, OT_ERROR_NONE);
388 	} else {
389 		otPlatRadioReceiveDone(instance, &recv_frame, OT_ERROR_NONE);
390 	}
391 
392 	net_pkt_unref(pkt);
393 }
394 
openthread_handle_frame_to_send(otInstance * instance,struct net_pkt * pkt)395 static void openthread_handle_frame_to_send(otInstance *instance,
396 					    struct net_pkt *pkt)
397 {
398 	struct net_buf *buf;
399 	otMessage *message;
400 	otMessageSettings settings;
401 
402 	NET_DBG("Sending Ip6 packet to ot stack");
403 
404 	settings.mPriority = OT_MESSAGE_PRIORITY_NORMAL;
405 	settings.mLinkSecurityEnabled = true;
406 	message = otIp6NewMessage(instance, &settings);
407 	if (message == NULL) {
408 		goto exit;
409 	}
410 
411 	for (buf = pkt->buffer; buf; buf = buf->frags) {
412 		if (otMessageAppend(message, buf->data, buf->len) != OT_ERROR_NONE) {
413 			NET_ERR("Error while appending to otMessage");
414 			otMessageFree(message);
415 			goto exit;
416 		}
417 	}
418 
419 	if (otIp6Send(instance, message) != OT_ERROR_NONE) {
420 		NET_ERR("Error while calling otIp6Send");
421 		goto exit;
422 	}
423 
424 exit:
425 	net_pkt_unref(pkt);
426 }
427 
notify_new_rx_frame(struct net_pkt * pkt)428 int notify_new_rx_frame(struct net_pkt *pkt)
429 {
430 	k_fifo_put(&rx_pkt_fifo, pkt);
431 	set_pending_event(PENDING_EVENT_FRAME_RECEIVED);
432 
433 	return 0;
434 }
435 
notify_new_tx_frame(struct net_pkt * pkt)436 int notify_new_tx_frame(struct net_pkt *pkt)
437 {
438 	k_fifo_put(&tx_pkt_fifo, pkt);
439 	set_pending_event(PENDING_EVENT_FRAME_TO_SEND);
440 
441 	return 0;
442 }
443 
run_tx_task(otInstance * aInstance)444 static int run_tx_task(otInstance *aInstance)
445 {
446 	static K_WORK_DEFINE(tx_job, transmit_message);
447 
448 	ARG_UNUSED(aInstance);
449 
450 	if (!k_work_is_pending(&tx_job)) {
451 		sState = OT_RADIO_STATE_TRANSMIT;
452 
453 		k_work_submit_to_queue(&ot_work_q, &tx_job);
454 		return 0;
455 	} else {
456 		return -EBUSY;
457 	}
458 }
459 
platformRadioProcess(otInstance * aInstance)460 void platformRadioProcess(otInstance *aInstance)
461 {
462 	bool event_pending = false;
463 
464 	if (is_pending_event_set(PENDING_EVENT_FRAME_TO_SEND)) {
465 		struct net_pkt *tx_pkt;
466 
467 		reset_pending_event(PENDING_EVENT_FRAME_TO_SEND);
468 		while ((tx_pkt = (struct net_pkt *) k_fifo_get(&tx_pkt_fifo, K_NO_WAIT)) != NULL) {
469 			if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR_RCP)) {
470 				net_pkt_unref(tx_pkt);
471 			} else {
472 				openthread_handle_frame_to_send(aInstance, tx_pkt);
473 			}
474 		}
475 	}
476 
477 	if (is_pending_event_set(PENDING_EVENT_FRAME_RECEIVED)) {
478 		struct net_pkt *rx_pkt;
479 
480 		reset_pending_event(PENDING_EVENT_FRAME_RECEIVED);
481 		while ((rx_pkt = (struct net_pkt *) k_fifo_get(&rx_pkt_fifo, K_NO_WAIT)) != NULL) {
482 			openthread_handle_received_frame(aInstance, rx_pkt);
483 		}
484 	}
485 
486 	if (is_pending_event_set(PENDING_EVENT_RX_FAILED)) {
487 		reset_pending_event(PENDING_EVENT_RX_FAILED);
488 		if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) {
489 			otPlatDiagRadioReceiveDone(aInstance, NULL, rx_result);
490 		} else {
491 			otPlatRadioReceiveDone(aInstance, NULL, rx_result);
492 		}
493 	}
494 
495 	if (is_pending_event_set(PENDING_EVENT_TX_STARTED)) {
496 		reset_pending_event(PENDING_EVENT_TX_STARTED);
497 		otPlatRadioTxStarted(aInstance, &sTransmitFrame);
498 	}
499 
500 	if (is_pending_event_set(PENDING_EVENT_TX_DONE)) {
501 		reset_pending_event(PENDING_EVENT_TX_DONE);
502 
503 		if (sState == OT_RADIO_STATE_TRANSMIT) {
504 			sState = OT_RADIO_STATE_RECEIVE;
505 			handle_tx_done(aInstance);
506 		}
507 	}
508 
509 	if (is_pending_event_set(PENDING_EVENT_SLEEP)) {
510 		reset_pending_event(PENDING_EVENT_SLEEP);
511 		ARG_UNUSED(otPlatRadioSleep(aInstance));
512 	}
513 
514 	/* handle events that can't run during transmission */
515 	if (sState != OT_RADIO_STATE_TRANSMIT) {
516 		if (is_pending_event_set(PENDING_EVENT_DETECT_ENERGY)) {
517 			radio_api->set_channel(radio_dev,
518 					       energy_detection_channel);
519 
520 			if (!radio_api->ed_scan(radio_dev,
521 						energy_detection_time,
522 						energy_detected)) {
523 				reset_pending_event(
524 					PENDING_EVENT_DETECT_ENERGY);
525 			} else {
526 				event_pending = true;
527 			}
528 		}
529 
530 		if (is_pending_event_set(PENDING_EVENT_DETECT_ENERGY_DONE)) {
531 			otPlatRadioEnergyScanDone(aInstance, (int8_t) energy_detected_value);
532 			reset_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
533 		}
534 	}
535 
536 	if (event_pending) {
537 		otSysEventSignalPending();
538 	}
539 }
540 
platformRadioChannelGet(otInstance * aInstance)541 uint16_t platformRadioChannelGet(otInstance *aInstance)
542 {
543 	ARG_UNUSED(aInstance);
544 
545 	return channel;
546 }
547 
otPlatRadioSetPanId(otInstance * aInstance,uint16_t aPanId)548 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
549 {
550 	ARG_UNUSED(aInstance);
551 
552 	radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_PAN_ID,
553 			  (struct ieee802154_filter *) &aPanId);
554 }
555 
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aExtAddress)556 void otPlatRadioSetExtendedAddress(otInstance *aInstance,
557 				   const otExtAddress *aExtAddress)
558 {
559 	ARG_UNUSED(aInstance);
560 
561 	radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_IEEE_ADDR,
562 			  (struct ieee802154_filter *) &aExtAddress);
563 }
564 
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aShortAddress)565 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddress)
566 {
567 	ARG_UNUSED(aInstance);
568 
569 	radio_api->filter(radio_dev, true, IEEE802154_FILTER_TYPE_SHORT_ADDR,
570 			  (struct ieee802154_filter *) &aShortAddress);
571 }
572 
otPlatRadioIsEnabled(otInstance * aInstance)573 bool otPlatRadioIsEnabled(otInstance *aInstance)
574 {
575 	ARG_UNUSED(aInstance);
576 
577 	return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
578 }
579 
otPlatRadioEnable(otInstance * aInstance)580 otError otPlatRadioEnable(otInstance *aInstance)
581 {
582 	if (!otPlatRadioIsEnabled(aInstance)) {
583 		sState = OT_RADIO_STATE_SLEEP;
584 	}
585 
586 	return OT_ERROR_NONE;
587 }
588 
otPlatRadioDisable(otInstance * aInstance)589 otError otPlatRadioDisable(otInstance *aInstance)
590 {
591 	if (otPlatRadioIsEnabled(aInstance)) {
592 		sState = OT_RADIO_STATE_DISABLED;
593 	}
594 
595 	return OT_ERROR_NONE;
596 }
597 
otPlatRadioSleep(otInstance * aInstance)598 otError otPlatRadioSleep(otInstance *aInstance)
599 {
600 	ARG_UNUSED(aInstance);
601 
602 	otError error = OT_ERROR_INVALID_STATE;
603 
604 	if (sState == OT_RADIO_STATE_SLEEP ||
605 	    sState == OT_RADIO_STATE_RECEIVE ||
606 	    sState == OT_RADIO_STATE_TRANSMIT) {
607 		error = OT_ERROR_NONE;
608 		if (radio_api->stop(radio_dev)) {
609 			sState = OT_RADIO_STATE_SLEEP;
610 		}
611 	}
612 
613 	return error;
614 }
615 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)616 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
617 {
618 	ARG_UNUSED(aInstance);
619 
620 	channel = aChannel;
621 
622 	radio_api->set_channel(radio_dev, aChannel);
623 	radio_api->set_txpower(radio_dev, tx_power);
624 	radio_api->start(radio_dev);
625 	sState = OT_RADIO_STATE_RECEIVE;
626 
627 	return OT_ERROR_NONE;
628 }
629 
630 #if defined(CONFIG_OPENTHREAD_CSL_RECEIVER)
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)631 otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel,
632 			     uint32_t aStart, uint32_t aDuration)
633 {
634 	int result;
635 
636 	ARG_UNUSED(aInstance);
637 
638 	struct ieee802154_config config = {
639 		.rx_slot.channel = aChannel,
640 		.rx_slot.start = aStart,
641 		.rx_slot.duration = aDuration,
642 	};
643 
644 	result = radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_SLOT,
645 				      &config);
646 
647 	return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
648 }
649 #endif
650 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aPacket)651 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aPacket)
652 {
653 	otError error = OT_ERROR_INVALID_STATE;
654 
655 	ARG_UNUSED(aInstance);
656 	ARG_UNUSED(aPacket);
657 
658 	__ASSERT_NO_MSG(aPacket == &sTransmitFrame);
659 
660 	enum ieee802154_hw_caps radio_caps;
661 
662 	radio_caps = radio_api->get_capabilities(radio_dev);
663 
664 	if ((sState == OT_RADIO_STATE_RECEIVE) || (radio_caps & IEEE802154_HW_SLEEP_TO_TX)) {
665 		if (run_tx_task(aInstance) == 0) {
666 			error = OT_ERROR_NONE;
667 		}
668 	}
669 
670 	return error;
671 }
672 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)673 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
674 {
675 	ARG_UNUSED(aInstance);
676 
677 	return &sTransmitFrame;
678 }
679 
get_rssi_energy_detected(const struct device * dev,int16_t max_ed)680 static void get_rssi_energy_detected(const struct device *dev, int16_t max_ed)
681 {
682 	ARG_UNUSED(dev);
683 	energy_detected_value = max_ed;
684 	k_sem_give(&radio_sem);
685 }
686 
otPlatRadioGetRssi(otInstance * aInstance)687 int8_t otPlatRadioGetRssi(otInstance *aInstance)
688 {
689 	int8_t ret_rssi = INT8_MAX;
690 	int error = 0;
691 	const uint16_t energy_detection_time = 1;
692 	enum ieee802154_hw_caps radio_caps;
693 	ARG_UNUSED(aInstance);
694 
695 	radio_caps = radio_api->get_capabilities(radio_dev);
696 
697 	if (!(radio_caps & IEEE802154_HW_ENERGY_SCAN)) {
698 		/*
699 		 * TODO: No API in Zephyr to get the RSSI
700 		 * when IEEE802154_HW_ENERGY_SCAN is not available
701 		 */
702 		ret_rssi = 0;
703 	} else {
704 		/*
705 		 * Blocking implementation of get RSSI
706 		 * using no-blocking ed_scan
707 		 */
708 		error = radio_api->ed_scan(radio_dev, energy_detection_time,
709 					   get_rssi_energy_detected);
710 
711 		if (error == 0) {
712 			k_sem_take(&radio_sem, K_FOREVER);
713 
714 			ret_rssi = (int8_t)energy_detected_value;
715 		}
716 	}
717 
718 	return ret_rssi;
719 }
720 
otPlatRadioGetCaps(otInstance * aInstance)721 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
722 {
723 	otRadioCaps caps = OT_RADIO_CAPS_NONE;
724 
725 	enum ieee802154_hw_caps radio_caps;
726 	ARG_UNUSED(aInstance);
727 	__ASSERT(radio_api,
728 	    "platformRadioInit needs to be called prior to otPlatRadioGetCaps");
729 
730 	radio_caps = radio_api->get_capabilities(radio_dev);
731 
732 	if (radio_caps & IEEE802154_HW_ENERGY_SCAN) {
733 		caps |= OT_RADIO_CAPS_ENERGY_SCAN;
734 	}
735 
736 	if (radio_caps & IEEE802154_HW_CSMA) {
737 		caps |= OT_RADIO_CAPS_CSMA_BACKOFF;
738 	}
739 
740 	if (radio_caps & IEEE802154_HW_TX_RX_ACK) {
741 		caps |= OT_RADIO_CAPS_ACK_TIMEOUT;
742 	}
743 
744 	if (radio_caps & IEEE802154_HW_SLEEP_TO_TX) {
745 		caps |= OT_RADIO_CAPS_SLEEP_TO_TX;
746 	}
747 
748 #if defined(CONFIG_IEEE802154_2015)
749 	if (radio_caps & IEEE802154_HW_TX_SEC) {
750 		caps |= OT_RADIO_CAPS_TRANSMIT_SEC;
751 	}
752 #endif
753 
754 #if defined(CONFIG_NET_PKT_TXTIME)
755 	if (radio_caps & IEEE802154_HW_TXTIME) {
756 		caps |= OT_RADIO_CAPS_TRANSMIT_TIMING;
757 	}
758 #endif
759 
760 	if (radio_caps & IEEE802154_HW_RXTIME) {
761 		caps |= OT_RADIO_CAPS_RECEIVE_TIMING;
762 	}
763 
764 	return caps;
765 }
766 
otPlatRadioGetPromiscuous(otInstance * aInstance)767 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
768 {
769 	ARG_UNUSED(aInstance);
770 
771 	LOG_DBG("PromiscuousMode=%d", promiscuous ? 1 : 0);
772 
773 	return promiscuous;
774 }
775 
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)776 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
777 {
778 	struct ieee802154_config config = {
779 		.promiscuous = aEnable
780 	};
781 
782 	ARG_UNUSED(aInstance);
783 
784 	LOG_DBG("PromiscuousMode=%d", aEnable ? 1 : 0);
785 
786 	promiscuous = aEnable;
787 	radio_api->configure(radio_dev, IEEE802154_CONFIG_PROMISCUOUS, &config);
788 }
789 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)790 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel,
791 			      uint16_t aScanDuration)
792 {
793 	energy_detection_time    = aScanDuration;
794 	energy_detection_channel = aScanChannel;
795 
796 	if (radio_api->ed_scan == NULL) {
797 		return OT_ERROR_NOT_IMPLEMENTED;
798 	}
799 
800 	reset_pending_event(PENDING_EVENT_DETECT_ENERGY);
801 	reset_pending_event(PENDING_EVENT_DETECT_ENERGY_DONE);
802 
803 	radio_api->set_channel(radio_dev, aScanChannel);
804 
805 	if (radio_api->ed_scan(radio_dev, energy_detection_time, energy_detected) != 0) {
806 		/*
807 		 * OpenThread API does not accept failure of this function,
808 		 * it can return 'No Error' or 'Not Implemented' error only.
809 		 * If ed_scan start failed event is set to schedule the scan at
810 		 * later time.
811 		 */
812 		LOG_ERR("Failed do start energy scan, scheduling for later");
813 		set_pending_event(PENDING_EVENT_DETECT_ENERGY);
814 	}
815 
816 	return OT_ERROR_NONE;
817 }
818 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)819 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance,
820 					       int8_t *aThreshold)
821 {
822 	OT_UNUSED_VARIABLE(aInstance);
823 	OT_UNUSED_VARIABLE(aThreshold);
824 
825 	return OT_ERROR_NOT_IMPLEMENTED;
826 }
827 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)828 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance,
829 					       int8_t aThreshold)
830 {
831 	OT_UNUSED_VARIABLE(aInstance);
832 	OT_UNUSED_VARIABLE(aThreshold);
833 
834 	return OT_ERROR_NOT_IMPLEMENTED;
835 }
836 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)837 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
838 {
839 	ARG_UNUSED(aInstance);
840 
841 	struct ieee802154_config config = {
842 		.auto_ack_fpb.enabled = aEnable,
843 		.auto_ack_fpb.mode = IEEE802154_FPB_ADDR_MATCH_THREAD,
844 	};
845 
846 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_AUTO_ACK_FPB,
847 				   &config);
848 }
849 
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,const uint16_t aShortAddress)850 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance,
851 					 const uint16_t aShortAddress)
852 {
853 	ARG_UNUSED(aInstance);
854 
855 	uint8_t short_address[SHORT_ADDRESS_SIZE];
856 	struct ieee802154_config config = {
857 		.ack_fpb.enabled = true,
858 		.ack_fpb.addr = short_address,
859 		.ack_fpb.extended = false
860 	};
861 
862 	sys_put_le16(aShortAddress, short_address);
863 
864 	if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
865 				 &config) != 0) {
866 		return OT_ERROR_NO_BUFS;
867 	}
868 
869 	return OT_ERROR_NONE;
870 }
871 
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)872 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance,
873 				       const otExtAddress *aExtAddress)
874 {
875 	ARG_UNUSED(aInstance);
876 
877 	struct ieee802154_config config = {
878 		.ack_fpb.enabled = true,
879 		.ack_fpb.addr = (uint8_t *)aExtAddress->m8,
880 		.ack_fpb.extended = true
881 	};
882 
883 	if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
884 				 &config) != 0) {
885 		return OT_ERROR_NO_BUFS;
886 	}
887 
888 	return OT_ERROR_NONE;
889 }
890 
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,const uint16_t aShortAddress)891 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance,
892 					   const uint16_t aShortAddress)
893 {
894 	ARG_UNUSED(aInstance);
895 
896 	uint8_t short_address[SHORT_ADDRESS_SIZE];
897 	struct ieee802154_config config = {
898 		.ack_fpb.enabled = false,
899 		.ack_fpb.addr = short_address,
900 		.ack_fpb.extended = false
901 	};
902 
903 	sys_put_le16(aShortAddress, short_address);
904 
905 	if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
906 				 &config) != 0) {
907 		return OT_ERROR_NO_BUFS;
908 	}
909 
910 	return OT_ERROR_NONE;
911 }
912 
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)913 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance,
914 					 const otExtAddress *aExtAddress)
915 {
916 	ARG_UNUSED(aInstance);
917 
918 	struct ieee802154_config config = {
919 		.ack_fpb.enabled = false,
920 		.ack_fpb.addr = (uint8_t *)aExtAddress->m8,
921 		.ack_fpb.extended = true
922 	};
923 
924 	if (radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
925 				 &config) != 0) {
926 		return OT_ERROR_NO_BUFS;
927 	}
928 
929 	return OT_ERROR_NONE;
930 }
931 
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)932 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
933 {
934 	ARG_UNUSED(aInstance);
935 
936 	struct ieee802154_config config = {
937 		.ack_fpb.enabled = false,
938 		.ack_fpb.addr = NULL,
939 		.ack_fpb.extended = false
940 	};
941 
942 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
943 				   &config);
944 }
945 
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)946 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
947 {
948 	ARG_UNUSED(aInstance);
949 
950 	struct ieee802154_config config = {
951 		.ack_fpb.enabled = false,
952 		.ack_fpb.addr = NULL,
953 		.ack_fpb.extended = true
954 	};
955 
956 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_ACK_FPB,
957 				   &config);
958 }
959 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)960 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
961 {
962 	ARG_UNUSED(aInstance);
963 
964 	return -100;
965 }
966 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)967 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
968 {
969 	ARG_UNUSED(aInstance);
970 
971 	if (aPower == NULL) {
972 		return OT_ERROR_INVALID_ARGS;
973 	}
974 
975 	*aPower = tx_power;
976 
977 	return OT_ERROR_NONE;
978 }
979 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)980 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
981 {
982 	ARG_UNUSED(aInstance);
983 
984 	tx_power = aPower;
985 
986 	return OT_ERROR_NONE;
987 }
988 
otPlatTimeGet(void)989 uint64_t otPlatTimeGet(void)
990 {
991 	if (radio_api == NULL || radio_api->get_time == NULL) {
992 		return k_ticks_to_us_floor64(k_uptime_ticks());
993 	} else {
994 		return radio_api->get_time(radio_dev);
995 	}
996 }
997 
998 #if defined(CONFIG_NET_PKT_TXTIME)
otPlatRadioGetNow(otInstance * aInstance)999 uint64_t otPlatRadioGetNow(otInstance *aInstance)
1000 {
1001 	ARG_UNUSED(aInstance);
1002 
1003 	return otPlatTimeGet();
1004 }
1005 #endif
1006 
1007 #if defined(CONFIG_IEEE802154_2015)
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKey * aPrevKey,const otMacKey * aCurrKey,const otMacKey * aNextKey)1008 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode,
1009 			  uint8_t aKeyId, const otMacKey *aPrevKey,
1010 			  const otMacKey *aCurrKey, const otMacKey *aNextKey)
1011 {
1012 	ARG_UNUSED(aInstance);
1013 	__ASSERT_NO_MSG(aPrevKey != NULL && aCurrKey != NULL &&
1014 			aNextKey != NULL);
1015 
1016 	uint8_t key_id_mode = aKeyIdMode >> 3;
1017 
1018 	struct ieee802154_key keys[] = {
1019 		{
1020 			.key_id_mode = key_id_mode,
1021 			.key_index = aKeyId == 1 ? 0x80 : aKeyId - 1,
1022 			.key_value = (uint8_t *)aPrevKey->m8,
1023 			.frame_counter_per_key = false,
1024 		},
1025 		{
1026 			.key_id_mode = key_id_mode,
1027 			.key_index = aKeyId,
1028 			.key_value = (uint8_t *)aCurrKey->m8,
1029 			.frame_counter_per_key = false,
1030 		},
1031 		{
1032 			.key_id_mode = key_id_mode,
1033 			.key_index = aKeyId == 0x80 ? 1 : aKeyId + 1,
1034 			.key_value = (uint8_t *)aNextKey->m8,
1035 			.frame_counter_per_key = false,
1036 		},
1037 		{
1038 			.key_value = NULL,
1039 		},
1040 	};
1041 
1042 	struct ieee802154_config config = {
1043 		.mac_keys = keys
1044 	};
1045 
1046 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_MAC_KEYS,
1047 				   &config);
1048 }
1049 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)1050 void otPlatRadioSetMacFrameCounter(otInstance *aInstance,
1051 				   uint32_t aMacFrameCounter)
1052 {
1053 	ARG_UNUSED(aInstance);
1054 
1055 	struct ieee802154_config config = { .frame_counter = aMacFrameCounter };
1056 
1057 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_FRAME_COUNTER,
1058 				   &config);
1059 }
1060 #endif
1061 
1062 #if defined(CONFIG_OPENTHREAD_CSL_RECEIVER)
otPlatRadioEnableCsl(otInstance * aInstance,uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1063 otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr,
1064 			     const otExtAddress *aExtAddr)
1065 {
1066 	int result;
1067 	uint8_t ie_header[OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE];
1068 	struct ieee802154_config config;
1069 
1070 	ARG_UNUSED(aInstance);
1071 
1072 	ie_header[0] = CSL_IE_HEADER_BYTES_LO;
1073 	ie_header[1] = CSL_IE_HEADER_BYTES_HI;
1074 	/* Leave CSL Phase empty intentionally */
1075 	sys_put_le16(aCslPeriod, &ie_header[OT_IE_HEADER_SIZE + 2]);
1076 	config.ack_ie.data = ie_header;
1077 	config.ack_ie.short_addr = aShortAddr;
1078 	config.ack_ie.ext_addr = aExtAddr->m8;
1079 
1080 	if (aCslPeriod > 0) {
1081 		config.ack_ie.data_len = OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE;
1082 	} else {
1083 		config.ack_ie.data_len = 0;
1084 	}
1085 	result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1086 
1087 	config.csl_period = aCslPeriod;
1088 	result += radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_PERIOD, &config);
1089 
1090 	return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1091 }
1092 
otPlatRadioUpdateCslSampleTime(otInstance * aInstance,uint32_t aCslSampleTime)1093 void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
1094 {
1095 	ARG_UNUSED(aInstance);
1096 
1097 	struct ieee802154_config config = { .csl_rx_time = aCslSampleTime };
1098 
1099 	(void)radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_RX_TIME, &config);
1100 }
1101 #endif /* CONFIG_OPENTHREAD_CSL_RECEIVER */
1102 
otPlatRadioGetCslAccuracy(otInstance * aInstance)1103 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
1104 {
1105 	ARG_UNUSED(aInstance);
1106 
1107 	return radio_api->get_sch_acc(radio_dev);
1108 }
1109 
1110 #if defined(CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT)
1111 /**
1112  * Header IE format - IEEE Std. 802.15.4-2015, 7.4.2.1 && 7.4.2.2
1113  *
1114  * +---------------------------------+----------------------+
1115  * | Length    | Element ID | Type=0 |      Vendor OUI      |
1116  * +-----------+------------+--------+----------------------+
1117  * |           Bytes: 0-1            |          2-4         |
1118  * +-----------+---------------------+----------------------+
1119  * | Bits: 0-6 |    7-14    |   15   | IE_VENDOR_THREAD_OUI |
1120  * +-----------+------------+--------+----------------------|
1121  *
1122  * Thread v1.2.1 Spec., 4.11.3.4.4.6
1123  * +---------------------------------+-------------------+------------------+
1124  * |                  Vendor Specific Information                           |
1125  * +---------------------------------+-------------------+------------------+
1126  * |                5                |         6         |   7 (optional)   |
1127  * +---------------------------------+-------------------+------------------+
1128  * | IE_VENDOR_THREAD_ACK_PROBING_ID | LINK_METRIC_TOKEN | LINK_METRIC_TOKEN|
1129  * |---------------------------------|-------------------|------------------|
1130  */
set_vendor_ie_header_lm(bool lqi,bool link_margin,bool rssi,uint8_t * ie_header)1131 static uint8_t set_vendor_ie_header_lm(bool lqi, bool link_margin, bool rssi, uint8_t *ie_header)
1132 {
1133 	/* Vendor-specific IE identifier */
1134 	const uint8_t ie_vendor_id = 0x00;
1135 	/* Thread Vendor-specific ACK Probing IE subtype ID */
1136 	const uint8_t ie_vendor_thread_ack_probing_id = 0x00;
1137 	/* Thread Vendor-specific IE OUI */
1138 	const uint32_t ie_vendor_thread_oui = 0xeab89b;
1139 	/* Thread Vendor-specific ACK Probing IE RSSI value placeholder */
1140 	const uint8_t ie_vendor_thread_rssi_token = 0x01;
1141 	/* Thread Vendor-specific ACK Probing IE Link margin value placeholder */
1142 	const uint8_t ie_vendor_thread_margin_token = 0x02;
1143 	/* Thread Vendor-specific ACK Probing IE LQI value placeholder */
1144 	const uint8_t ie_vendor_thread_lqi_token = 0x03;
1145 	const uint8_t ie_header_size = 2;
1146 	const uint8_t oui_size = 3;
1147 	const uint8_t sub_type = 1;
1148 	const uint8_t id_offset = 7;
1149 	const uint16_t id_mask = 0x00ff << id_offset;
1150 	const uint8_t type = 0x00;
1151 	const uint8_t type_offset = 7;
1152 	const uint8_t type_mask = 0x01 << type_offset;
1153 	const uint8_t length_mask = 0x7f;
1154 	uint8_t content_len;
1155 	uint16_t element_id = 0x0000;
1156 	uint8_t link_metrics_idx = 6;
1157 	uint8_t link_metrics_data_len = (uint8_t)lqi + (uint8_t)link_margin + (uint8_t)rssi;
1158 
1159 	__ASSERT(link_metrics_data_len <= 2, "Thread limits to 2 metrics at most");
1160 	__ASSERT(ie_header, "Invalid argument");
1161 
1162 	if (link_metrics_data_len == 0) {
1163 		return 0;
1164 	}
1165 
1166 	/* Set Element ID */
1167 	element_id = (((uint16_t)ie_vendor_id) << id_offset) & id_mask;
1168 	sys_put_le16(element_id, &ie_header[0]);
1169 
1170 	/* Set Length - number of octets in content field. */
1171 	content_len = oui_size + sub_type + link_metrics_data_len;
1172 	ie_header[0] = (ie_header[0] & ~length_mask) | (content_len & length_mask);
1173 
1174 	/* Set Type */
1175 	ie_header[1] = (ie_header[1] & ~type_mask) | (type & type_mask);
1176 
1177 	/* Set Vendor Oui */
1178 	sys_put_le24(ie_vendor_thread_oui, &ie_header[2]);
1179 
1180 	/* Set SubType */
1181 	ie_header[5] = ie_vendor_thread_ack_probing_id;
1182 
1183 	/* Set Link Metrics Tokens
1184 	 * TODO: Thread requires the order of requested metrics by the Link Metrics Initiator
1185 	 *       to be kept by the Link Metrics Subject in the ACKs.
1186 	 */
1187 	if (lqi) {
1188 		ie_header[link_metrics_idx++] = ie_vendor_thread_lqi_token;
1189 	}
1190 
1191 	if (link_margin) {
1192 		ie_header[link_metrics_idx++] = ie_vendor_thread_margin_token;
1193 	}
1194 
1195 	if (rssi) {
1196 		ie_header[link_metrics_idx++] = ie_vendor_thread_rssi_token;
1197 	}
1198 
1199 	return ie_header_size + content_len;
1200 }
1201 
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1202 otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
1203 					  const otShortAddress aShortAddress,
1204 					  const otExtAddress *aExtAddress)
1205 {
1206 	int result;
1207 	uint8_t ie_header[OT_ACK_IE_MAX_SIZE];
1208 	uint16_t ie_header_len;
1209 	struct ieee802154_config config = {
1210 		.ack_ie.short_addr = aShortAddress,
1211 		.ack_ie.ext_addr = aExtAddress->m8,
1212 	};
1213 
1214 	ARG_UNUSED(aInstance);
1215 
1216 	ie_header_len = set_vendor_ie_header_lm(aLinkMetrics.mLqi, aLinkMetrics.mLinkMargin,
1217 						aLinkMetrics.mRssi, ie_header);
1218 	config.ack_ie.data = ie_header;
1219 	config.ack_ie.data_len = ie_header_len;
1220 	result = radio_api->configure(radio_dev, IEEE802154_CONFIG_ENH_ACK_HEADER_IE, &config);
1221 
1222 	return result ? OT_ERROR_FAILED : OT_ERROR_NONE;
1223 }
1224 
1225 #endif /* CONFIG_OPENTHREAD_LINK_METRICS_SUBJECT */
1226