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