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