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