1 /*
2 * Copyright (c) 2017 - 2023, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
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 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35 /**
36 * @file
37 * This file implements notifications triggered by the nrf 802.15.4 radio driver via SWI.
38 *
39 */
40
41 #define NRF_802154_MODULE_ID NRF_802154_DRV_MODULE_ID_NOTIFICATION
42
43 #include "nrf_802154_notification.h"
44
45 #include <assert.h>
46 #include <stdbool.h>
47 #include <stddef.h>
48 #include <stdint.h>
49
50 #include "nrf_802154.h"
51 #include "nrf_802154_config.h"
52 #include "nrf_802154_debug.h"
53 #include "nrf_802154_queue.h"
54 #include "nrf_802154_swi.h"
55 #include "nrf_802154_tx_work_buffer.h"
56 #include "nrf_802154_utils.h"
57 #include "hal/nrf_egu.h"
58 #include "rsch/nrf_802154_rsch.h"
59
60 #define RAW_PAYLOAD_OFFSET 1
61 #define RAW_LENGTH_OFFSET 0
62
63 /** @brief Size of pool of slots for notifications that must not be lost.
64 *
65 * The pool needs to contain slots for:
66 * - immediate operation result notification
67 * ~ transmission
68 * ~ energy detection
69 * ~ standalone CCA
70 * - CSMA-CA result notification
71 * - DTX result notification
72 * - DRX timeout notifications
73 * - frame received notifications for each receive buffer.
74 */
75 #define NTF_PRIMARY_POOL_SIZE \
76 (NRF_802154_RX_BUFFERS + NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS + 3)
77
78 /**
79 * The implementation uses 8-bit integers to address slots with the oldest bit
80 * indicating pool. That leaves 7 bits for addressing slots within a fixed pool.
81 * If the pool's size exceeds that width, throw an error.
82 */
83 #if NTF_PRIMARY_POOL_SIZE > 0x7FU
84 #error NTF_PRIMARY_POOL_SIZE exceeds its bit width
85 #endif
86
87 /** @brief Size of pool of slots for notifications that can be ignored.
88 *
89 * The pool needs to contain slots for failed receptions. Its size is chosen arbitrarily.
90 */
91 #define NTF_SECONDARY_POOL_SIZE 4
92
93 /** @brief Bitmask that represents slot pool used.
94 */
95 #define NTF_POOL_ID_MASK (1U << 7)
96
97 /** @brief Bitmask that indicates a given slot comes from the primary pool.
98 */
99 #define NTF_PRIMARY_POOL_ID_MASK (1U << 7)
100
101 /** @brief Bitmask that indicates a given slot comes from the secondary pool.
102 */
103 #define NTF_SECONDARY_POOL_ID_MASK 0U
104
105 /** @brief Identifier of an invalid slot.
106 */
107 #define NTF_INVALID_SLOT_ID UINT8_MAX
108
109 /** @brief Size of notification queue.
110 *
111 * One slot is lost due to simplified queue implementation.
112 */
113 #define NTF_QUEUE_SIZE (NTF_PRIMARY_POOL_SIZE + NTF_SECONDARY_POOL_SIZE + 1)
114
115 #define NTF_INT NRF_EGU_INT_TRIGGERED0 ///< Label of notification interrupt.
116 #define NTF_TASK NRF_EGU_TASK_TRIGGER0 ///< Label of notification task.
117 #define NTF_EVENT NRF_EGU_EVENT_TRIGGERED0 ///< Label of notification event.
118
119 /// Types of notifications in notification queue.
120 typedef enum
121 {
122 NTF_TYPE_RECEIVED, ///< Frame received
123 NTF_TYPE_RECEIVE_FAILED, ///< Frame reception failed
124 NTF_TYPE_TRANSMITTED, ///< Frame transmitted
125 NTF_TYPE_TRANSMIT_FAILED, ///< Frame transmission failure
126 NTF_TYPE_ENERGY_DETECTED, ///< Energy detection procedure ended
127 NTF_TYPE_ENERGY_DETECTION_FAILED, ///< Energy detection procedure failed
128 NTF_TYPE_CCA, ///< CCA procedure ended
129 NTF_TYPE_CCA_FAILED, ///< CCA procedure failed
130 } nrf_802154_ntf_type_t;
131
132 /// Notification data in the notification queue.
133 typedef struct
134 {
135 volatile uint8_t taken; ///< Indicates if the slot is available.
136 nrf_802154_ntf_type_t type; ///< Notification type.
137
138 union
139 {
140 struct
141 {
142 uint8_t * p_data; ///< Pointer to a buffer containing PHR and PSDU of the received frame.
143 int8_t power; ///< RSSI of received frame.
144 uint8_t lqi; ///< LQI of received frame.
145 } received; ///< Received frame details.
146
147 struct
148 {
149 nrf_802154_rx_error_t error; ///< An error code that indicates reason of the failure.
150 uint32_t id; ///< Identifier of reception window the error occured in.
151 } receive_failed;
152
153 struct
154 {
155 uint8_t * p_frame; ///< Pointer to frame that was transmitted.
156 nrf_802154_transmit_done_metadata_t metadata; ///< Metadata structure describing @ref p_frame.
157 } transmitted; ///< Transmitted frame details.
158
159 struct
160 {
161 uint8_t * p_frame; ///< Pointer to frame that was requested to be transmitted, but failed.
162 nrf_802154_tx_error_t error; ///< An error code that indicates reason of the failure.
163 nrf_802154_transmit_done_metadata_t metadata; ///< Metadata structure describing @ref p_frame.
164 } transmit_failed; ///< Failed transmission details.
165
166 struct
167 {
168 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
169 nrf_802154_energy_detected_t result; ///< Energy detection result.
170
171 #else
172 int8_t result; ///< Energy detection result.
173
174 #endif
175 } energy_detected; ///< Energy detection details.
176
177 struct
178 {
179 nrf_802154_ed_error_t error; ///< An error code that indicates reason of the failure.
180 } energy_detection_failed; ///< Energy detection failure details.
181
182 struct
183 {
184 bool result; ///< CCA result.
185 } cca; ///< CCA details.
186
187 struct
188 {
189 nrf_802154_cca_error_t error; ///< An error code that indicates reason of the failure.
190 } cca_failed; ///< CCA failure details.
191 } data; ///< Notification data depending on it's type.
192 } nrf_802154_ntf_data_t;
193
194 /// Entry in the notification queue
195 typedef struct
196 {
197 uint8_t id; ///< Identifier of the pool and an entry within.
198 } nrf_802154_queue_entry_t;
199
200 static nrf_802154_ntf_data_t m_primary_ntf_pool[NTF_PRIMARY_POOL_SIZE];
201 static nrf_802154_ntf_data_t m_secondary_ntf_pool[NTF_SECONDARY_POOL_SIZE];
202
203 static nrf_802154_queue_t m_notifications_queue;
204 static nrf_802154_queue_entry_t m_notifications_queue_memory[NTF_QUEUE_SIZE];
205
206 static volatile nrf_802154_mcu_critical_state_t m_mcu_cs;
207
208 /** @brief Allocate notification slot from the specified pool.
209 *
210 * @param[inout] p_pool Pointer to a pool of slots.
211 * @param[in] pool_len Length of the pool.
212 *
213 * @return Index of the allocated slot or NTF_INVALID_SLOT_ID in case of failure.
214 */
ntf_slot_alloc(nrf_802154_ntf_data_t * p_pool,size_t pool_len)215 static uint8_t ntf_slot_alloc(nrf_802154_ntf_data_t * p_pool, size_t pool_len)
216 {
217 // Linear search for a free slot
218 for (size_t i = 0; i < pool_len; i++)
219 {
220 bool slot_found = true;
221
222 do
223 {
224 uint8_t taken = __LDREXB(&p_pool[i].taken);
225
226 if (taken)
227 {
228 // The slot is taken. Proceed to the next slot
229 __CLREX();
230 slot_found = false;
231 break;
232 }
233 }
234 while (__STREXB(true, &p_pool[i].taken));
235
236 __DMB();
237
238 if (slot_found)
239 {
240 // Free slot was found and it was successfully marked as taken
241 return i;
242 }
243 }
244
245 return NTF_INVALID_SLOT_ID;
246 }
247
248 /** @brief Release a slot.
249 *
250 * @param[inout] p_slot Pointer to a slot to free.
251 */
ntf_slot_free(nrf_802154_ntf_data_t * p_slot)252 static void ntf_slot_free(nrf_802154_ntf_data_t * p_slot)
253 {
254 __DMB();
255 p_slot->taken = false;
256 }
257
258 /**
259 * Enter notify block.
260 *
261 * This is a helper function used in all notification functions to atomically
262 * find an empty slot in the notification queue and allow atomic slot update.
263 *
264 * @return Pointer to an empty slot in the notification queue.
265 */
ntf_enter(void)266 static nrf_802154_queue_entry_t * ntf_enter(void)
267 {
268 nrf_802154_mcu_critical_enter(m_mcu_cs);
269
270 assert(!nrf_802154_queue_is_full(&m_notifications_queue));
271
272 return nrf_802154_queue_push_begin(&m_notifications_queue);
273 }
274
275 /**
276 * Exit notify block.
277 *
278 * This is a helper function used in all notification functions to end atomic slot update
279 * and trigger SWI to process the notification from the slot.
280 */
ntf_exit(void)281 static void ntf_exit(void)
282 {
283 nrf_802154_queue_push_commit(&m_notifications_queue);
284
285 nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, NTF_TASK);
286
287 nrf_802154_mcu_critical_exit(m_mcu_cs);
288 }
289
290 /** @brief Push notification to the queue.
291 *
292 * @param[in] slot_id Identifier of the pool and a slot within.
293 */
ntf_push(uint8_t slot_id)294 static void ntf_push(uint8_t slot_id)
295 {
296 nrf_802154_queue_entry_t * p_entry = ntf_enter();
297
298 p_entry->id = slot_id;
299 ntf_exit();
300 }
301
302 /**
303 * @brief Notifies the next higher layer that a frame was received.
304 *
305 * The notification is triggered from the SWI priority level.
306 *
307 * @param[in] p_data Pointer to a buffer that contains PHR and PSDU of the received frame.
308 * @param[in] power RSSI measured during the frame reception.
309 * @param[in] lqi LQI that indicates the measured link quality during the frame reception.
310 *
311 * @retval true Notification enqueued successfully.
312 * @retval false Notification could not be performed.
313 */
swi_notify_received(uint8_t * p_data,int8_t power,uint8_t lqi)314 bool swi_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi)
315 {
316 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
317
318 if (slot_id == NTF_INVALID_SLOT_ID)
319 {
320 // No slots are available.
321 return false;
322 }
323
324 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
325
326 p_slot->type = NTF_TYPE_RECEIVED;
327 p_slot->data.received.p_data = p_data;
328 p_slot->data.received.power = power;
329 p_slot->data.received.lqi = lqi;
330
331 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
332
333 return true;
334 }
335
336 /**
337 * @brief Notifies the next higher layer that the reception of a frame failed.
338 *
339 * @param[in] error Error code that indicates reason of the failure.
340 *
341 * @retval true Notification enqueued successfully.
342 * @retval false Notification could not be performed.
343 */
swi_notify_receive_failed(nrf_802154_rx_error_t error,uint32_t id,bool allow_drop)344 bool swi_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id, bool allow_drop)
345 {
346 nrf_802154_ntf_data_t * p_pool;
347 size_t pool_len;
348 uint32_t pool_id_bitmask;
349
350 if (!allow_drop)
351 {
352 // Choose the primary pool for DRX-related errors
353 p_pool = m_primary_ntf_pool;
354 pool_len = NTF_PRIMARY_POOL_SIZE;
355 pool_id_bitmask = NTF_PRIMARY_POOL_ID_MASK;
356 }
357 else
358 {
359 // Choose the secondary pool for spurious reception errors
360 p_pool = m_secondary_ntf_pool;
361 pool_len = NTF_SECONDARY_POOL_SIZE;
362 pool_id_bitmask = NTF_SECONDARY_POOL_ID_MASK;
363 }
364
365 uint8_t slot_id = ntf_slot_alloc(p_pool, pool_len);
366
367 if (slot_id == NTF_INVALID_SLOT_ID)
368 {
369 // No slots are available.
370 return false;
371 }
372
373 nrf_802154_ntf_data_t * p_slot = &p_pool[slot_id];
374
375 p_slot->type = NTF_TYPE_RECEIVE_FAILED;
376 p_slot->data.receive_failed.error = error;
377 p_slot->data.receive_failed.id = id;
378
379 ntf_push(slot_id | pool_id_bitmask);
380
381 return true;
382 }
383
384 /**
385 * @brief Notifies the next higher layer that a frame was transmitted
386 *
387 * The notification is triggered from the SWI priority level.
388 *
389 * @param[in] p_frame Pointer to a buffer that contains PHR and PSDU of the transmitted frame.
390 * @param[in] p_metadata Pointer to a metadata structure describing frame passed in @p p_frame.
391 *
392 * @retval true Notification enqueued successfully.
393 * @retval false Notification could not be performed.
394 */
swi_notify_transmitted(uint8_t * p_frame,nrf_802154_transmit_done_metadata_t * p_metadata)395 bool swi_notify_transmitted(uint8_t * p_frame,
396 nrf_802154_transmit_done_metadata_t * p_metadata)
397 {
398 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
399
400 if (slot_id == NTF_INVALID_SLOT_ID)
401 {
402 // No slots are available.
403 return false;
404 }
405
406 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
407
408 p_slot->type = NTF_TYPE_TRANSMITTED;
409 p_slot->data.transmitted.p_frame = p_frame;
410 p_slot->data.transmitted.metadata = *p_metadata;
411
412 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
413
414 return true;
415 }
416
417 /**
418 * @brief Notifies the next higher layer that a frame was not transmitted from the SWI priority
419 * level.
420 *
421 * @param[in] p_frame Pointer to a buffer that contains PHR and PSDU of the frame that failed
422 * the transmission.
423 * @param[in] error Reason of the transmission failure.
424 * @param[in] p_metadata Pointer to a metadata structure describing frame passed in @p p_frame.
425 *
426 * @retval true Notification enqueued successfully.
427 * @retval false Notification could not be performed.
428 */
swi_notify_transmit_failed(uint8_t * p_frame,nrf_802154_tx_error_t error,const nrf_802154_transmit_done_metadata_t * p_metadata)429 bool swi_notify_transmit_failed(uint8_t * p_frame,
430 nrf_802154_tx_error_t error,
431 const nrf_802154_transmit_done_metadata_t * p_metadata)
432 {
433 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
434
435 if (slot_id == NTF_INVALID_SLOT_ID)
436 {
437 // No slots are available.
438 return false;
439 }
440
441 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
442
443 p_slot->type = NTF_TYPE_TRANSMIT_FAILED;
444 p_slot->data.transmit_failed.p_frame = p_frame;
445 p_slot->data.transmit_failed.error = error;
446 p_slot->data.transmit_failed.metadata = *p_metadata;
447
448 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
449
450 return true;
451 }
452
453 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
454 /**
455 * @brief Notifies the next higher layer that the energy detection procedure ended from
456 * the SWI priority level.
457 *
458 * @param[in] p_result Structure holding the result of energy detection procedure.
459 *
460 * @retval true Notification enqueued successfully.
461 * @retval false Notification could not be performed.
462 */
swi_notify_energy_detected(const nrf_802154_energy_detected_t * p_result)463 bool swi_notify_energy_detected(const nrf_802154_energy_detected_t * p_result)
464 #else
465 /**
466 * @brief Notifies the next higher layer that the energy detection procedure ended from
467 * the SWI priority level.
468 *
469 * @param[in] result Detected energy level.
470 *
471 * @retval true Notification enqueued successfully.
472 * @retval false Notification could not be performed.
473 */
474 bool swi_notify_energy_detected(uint8_t result)
475 #endif
476 {
477 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
478
479 if (slot_id == NTF_INVALID_SLOT_ID)
480 {
481 // No slots are available.
482 return false;
483 }
484
485 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
486
487 p_slot->type = NTF_TYPE_ENERGY_DETECTED;
488 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
489 p_slot->data.energy_detected.result = *p_result;
490 #else
491 p_slot->data.energy_detected.result = result;
492 #endif
493
494 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
495
496 return true;
497 }
498
499 /**
500 * @brief Notifies the next higher layer that the energy detection procedure failed from
501 * the SWI priority level.
502 *
503 * @param[in] error Reason of the energy detection failure.
504 *
505 * @retval true Notification enqueued successfully.
506 * @retval false Notification could not be performed.
507 */
swi_notify_energy_detection_failed(nrf_802154_ed_error_t error)508 bool swi_notify_energy_detection_failed(nrf_802154_ed_error_t error)
509 {
510 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
511
512 if (slot_id == NTF_INVALID_SLOT_ID)
513 {
514 // No slots are available.
515 return false;
516 }
517
518 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
519
520 p_slot->type = NTF_TYPE_ENERGY_DETECTION_FAILED;
521 p_slot->data.energy_detection_failed.error = error;
522
523 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
524
525 return true;
526 }
527
528 /**
529 * @brief Notifies the next higher layer that the Clear Channel Assessment (CCA) procedure ended.
530 *
531 * The notification is triggered from the SWI priority level.
532 *
533 * @param[in] channel_free If a free channel was detected.
534 *
535 * @retval true Notification enqueued successfully.
536 * @retval false Notification could not be performed.
537 */
swi_notify_cca(bool channel_free)538 bool swi_notify_cca(bool channel_free)
539 {
540 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
541
542 if (slot_id == NTF_INVALID_SLOT_ID)
543 {
544 // No slots are available.
545 return false;
546 }
547
548 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
549
550 p_slot->type = NTF_TYPE_CCA;
551 p_slot->data.cca.result = channel_free;
552
553 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
554
555 return true;
556 }
557
558 /**
559 * @brief Notifies the next higher layer that the Clear Channel Assessment (CCA) procedure failed.
560 *
561 * The notification is triggered from the SWI priority level.
562 *
563 * @param[in] error Reason of the CCA failure.
564 *
565 * @retval true Notification enqueued successfully.
566 * @retval false Notification could not be performed.
567 */
swi_notify_cca_failed(nrf_802154_cca_error_t error)568 bool swi_notify_cca_failed(nrf_802154_cca_error_t error)
569 {
570 uint8_t slot_id = ntf_slot_alloc(m_primary_ntf_pool, NTF_PRIMARY_POOL_SIZE);
571
572 if (slot_id == NTF_INVALID_SLOT_ID)
573 {
574 // No slots are available.
575 return false;
576 }
577
578 nrf_802154_ntf_data_t * p_slot = &m_primary_ntf_pool[slot_id];
579
580 p_slot->type = NTF_TYPE_CCA_FAILED;
581 p_slot->data.cca_failed.error = error;
582
583 ntf_push(slot_id | NTF_PRIMARY_POOL_ID_MASK);
584
585 return true;
586 }
587
nrf_802154_notification_init(void)588 void nrf_802154_notification_init(void)
589 {
590 nrf_802154_queue_init(&m_notifications_queue,
591 m_notifications_queue_memory,
592 sizeof(m_notifications_queue_memory),
593 sizeof(m_notifications_queue_memory[0]));
594
595 nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, NTF_INT);
596
597 nrf_802154_swi_init();
598 }
599
nrf_802154_notify_received(uint8_t * p_data,int8_t power,uint8_t lqi)600 void nrf_802154_notify_received(uint8_t * p_data, int8_t power, uint8_t lqi)
601 {
602 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
603
604 bool notified = swi_notify_received(p_data, power, lqi);
605
606 // It should always be possible to notify a successful reception
607 assert(notified);
608 (void)notified;
609
610 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
611 }
612
nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error,uint32_t id,bool allow_drop)613 bool nrf_802154_notify_receive_failed(nrf_802154_rx_error_t error, uint32_t id, bool allow_drop)
614 {
615 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
616
617 bool notified = swi_notify_receive_failed(error, id, allow_drop);
618
619 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
620
621 return notified;
622 }
623
nrf_802154_notify_transmitted(uint8_t * p_frame,nrf_802154_transmit_done_metadata_t * p_metadata)624 void nrf_802154_notify_transmitted(uint8_t * p_frame,
625 nrf_802154_transmit_done_metadata_t * p_metadata)
626 {
627 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
628
629 // Update the transmitted frame contents and update frame status flags
630 nrf_802154_tx_work_buffer_original_frame_update(p_frame,
631 &p_metadata->frame_props);
632
633 bool notified = swi_notify_transmitted(p_frame, p_metadata);
634
635 // It should always be possible to notify transmission result
636 assert(notified);
637 (void)notified;
638
639 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
640 }
641
nrf_802154_notify_transmit_failed(uint8_t * p_frame,nrf_802154_tx_error_t error,const nrf_802154_transmit_done_metadata_t * p_metadata)642 void nrf_802154_notify_transmit_failed(uint8_t * p_frame,
643 nrf_802154_tx_error_t error,
644 const nrf_802154_transmit_done_metadata_t * p_metadata)
645 {
646 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
647
648 bool notified = swi_notify_transmit_failed(p_frame, error, p_metadata);
649
650 // It should always be possible to notify transmission result
651 assert(notified);
652 (void)notified;
653
654 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
655 }
656
657 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
nrf_802154_notify_energy_detected(const nrf_802154_energy_detected_t * p_result)658 void nrf_802154_notify_energy_detected(const nrf_802154_energy_detected_t * p_result)
659 #else
660 void nrf_802154_notify_energy_detected(uint8_t result)
661 #endif
662 {
663 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
664
665 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
666 bool notified = swi_notify_energy_detected(p_result);
667
668 #else
669 bool notified = swi_notify_energy_detected(result);
670
671 #endif
672
673 // It should always be possible to notify energy detection result
674 assert(notified);
675 (void)notified;
676
677 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
678 }
679
nrf_802154_notify_energy_detection_failed(nrf_802154_ed_error_t error)680 void nrf_802154_notify_energy_detection_failed(nrf_802154_ed_error_t error)
681 {
682 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
683
684 bool notified = swi_notify_energy_detection_failed(error);
685
686 // It should always be possible to notify energy detection result
687 assert(notified);
688 (void)notified;
689
690 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
691 }
692
nrf_802154_notify_cca(bool is_free)693 void nrf_802154_notify_cca(bool is_free)
694 {
695 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
696
697 bool notified = swi_notify_cca(is_free);
698
699 // It should always be possible to notify CCA result
700 assert(notified);
701 (void)notified;
702
703 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
704 }
705
nrf_802154_notify_cca_failed(nrf_802154_cca_error_t error)706 void nrf_802154_notify_cca_failed(nrf_802154_cca_error_t error)
707 {
708 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
709
710 bool notified = swi_notify_cca_failed(error);
711
712 // It should always be possible to notify CCA result
713 assert(notified);
714 (void)notified;
715
716 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
717 }
718
719 /**@brief Handles NTF_EVENT on NRF_802154_EGU_INSTANCE */
irq_handler_ntf_event(void)720 static void irq_handler_ntf_event(void)
721 {
722 nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
723
724 while (!nrf_802154_queue_is_empty(&m_notifications_queue))
725 {
726 nrf_802154_queue_entry_t * p_entry =
727 (nrf_802154_queue_entry_t *)nrf_802154_queue_pop_begin(&m_notifications_queue);
728
729 uint8_t slot_id = p_entry->id & (~NTF_POOL_ID_MASK);
730
731 nrf_802154_ntf_data_t * p_slot =
732 (p_entry->id & NTF_POOL_ID_MASK) ? &m_primary_ntf_pool[slot_id] :
733 &m_secondary_ntf_pool[slot_id];
734
735 switch (p_slot->type)
736 {
737 case NTF_TYPE_RECEIVED:
738 #if NRF_802154_USE_RAW_API
739 nrf_802154_received_raw(p_slot->data.received.p_data,
740 p_slot->data.received.power,
741 p_slot->data.received.lqi);
742 #else // NRF_802154_USE_RAW_API
743 nrf_802154_received(p_slot->data.received.p_data + RAW_PAYLOAD_OFFSET,
744 p_slot->data.received.p_data[RAW_LENGTH_OFFSET],
745 p_slot->data.received.power,
746 p_slot->data.received.lqi);
747 #endif
748 break;
749
750 case NTF_TYPE_RECEIVE_FAILED:
751 nrf_802154_receive_failed(p_slot->data.receive_failed.error,
752 p_slot->data.receive_failed.id);
753 break;
754
755 case NTF_TYPE_TRANSMITTED:
756 {
757 #if NRF_802154_USE_RAW_API
758 nrf_802154_transmitted_raw(p_slot->data.transmitted.p_frame,
759 &p_slot->data.transmitted.metadata);
760 #else // NRF_802154_USE_RAW_API
761 if (p_slot->data.transmitted.metadata.data.transmitted.p_ack != NULL)
762 {
763 p_slot->data.transmitted.metadata.data.transmitted.length =
764 p_slot->data.transmitted.metadata.data.transmitted.p_ack[RAW_LENGTH_OFFSET];
765 p_slot->data.transmitted.metadata.data.transmitted.p_ack += RAW_PAYLOAD_OFFSET;
766 }
767 nrf_802154_transmitted(p_slot->data.transmitted.p_frame + RAW_PAYLOAD_OFFSET,
768 &p_slot->data.transmitted.metadata);
769 #endif
770 }
771 break;
772
773 case NTF_TYPE_TRANSMIT_FAILED:
774 #if NRF_802154_USE_RAW_API
775 nrf_802154_transmit_failed(p_slot->data.transmit_failed.p_frame,
776 p_slot->data.transmit_failed.error,
777 &p_slot->data.transmit_failed.metadata);
778 #else // NRF_802154_USE_RAW_API
779 nrf_802154_transmit_failed(
780 p_slot->data.transmit_failed.p_frame + RAW_PAYLOAD_OFFSET,
781 p_slot->data.transmit_failed.error,
782 &p_slot->data.transmit_failed.metadata);
783 #endif
784 break;
785
786 case NTF_TYPE_ENERGY_DETECTED:
787 #if (NRF_802154_ENERGY_DETECTED_VERSION != 0)
788 nrf_802154_energy_detected(&p_slot->data.energy_detected.result);
789 #else
790 nrf_802154_energy_detected(p_slot->data.energy_detected.result);
791 #endif
792 break;
793
794 case NTF_TYPE_ENERGY_DETECTION_FAILED:
795 nrf_802154_energy_detection_failed(
796 p_slot->data.energy_detection_failed.error);
797 break;
798
799 case NTF_TYPE_CCA:
800 nrf_802154_cca_done(p_slot->data.cca.result);
801 break;
802
803 case NTF_TYPE_CCA_FAILED:
804 nrf_802154_cca_failed(p_slot->data.cca_failed.error);
805 break;
806
807 default:
808 assert(false);
809 }
810
811 nrf_802154_queue_pop_commit(&m_notifications_queue);
812 ntf_slot_free(p_slot);
813 }
814
815 nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
816 }
817
nrf_802154_notification_swi_irq_handler(void)818 void nrf_802154_notification_swi_irq_handler(void)
819 {
820 if (nrf_egu_event_check(NRF_802154_EGU_INSTANCE, NTF_EVENT))
821 {
822 nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, NTF_EVENT);
823
824 irq_handler_ntf_event();
825 }
826 }
827
828 #if defined(TEST)
nrf_802154_notification_swi_module_reset(void)829 void nrf_802154_notification_swi_module_reset(void)
830 {
831 m_mcu_cs = 0UL;
832 memset(&m_notifications_queue_memory, 0U, sizeof(m_notifications_queue_memory));
833 memset(&m_notifications_queue, 0U, sizeof(m_notifications_queue));
834 }
835
836 #endif // defined(TEST)
837