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 Finite State Machine of nRF 802.15.4 radio driver.
38  *
39  */
40 
41 #define NRF_802154_MODULE_ID NRF_802154_DRV_MODULE_ID_CORE
42 
43 #include "nrf_802154_core.h"
44 
45 #include "nrf_802154_assert.h"
46 #include <stdbool.h>
47 #include <stdint.h>
48 #include <string.h>
49 
50 #include "nrf_802154.h"
51 #include "nrf_802154_config.h"
52 #include "nrf_802154_const.h"
53 #include "nrf_802154_critical_section.h"
54 #include "nrf_802154_debug.h"
55 #include "nrf_802154_notification.h"
56 #include "nrf_802154_pib.h"
57 #include "nrf_802154_procedures_duration.h"
58 #include "nrf_802154_rssi.h"
59 #include "nrf_802154_rx_buffer.h"
60 #include "nrf_802154_sl_atomics.h"
61 #include "nrf_802154_sl_timer.h"
62 #include "nrf_802154_sl_utils.h"
63 #include "nrf_802154_stats.h"
64 #include "nrf_802154_utils.h"
65 #include "nrf_802154_trx.h"
66 #include "nrf_802154_tx_work_buffer.h"
67 #include "nrf_802154_tx_power.h"
68 #include "nrf_802154_types_internal.h"
69 #include "nrf_802154_utils.h"
70 #include "drivers/nrfx_errors.h"
71 #include "hal/nrf_radio.h"
72 #include "mac_features/nrf_802154_filter.h"
73 #include "mac_features/nrf_802154_frame_parser.h"
74 #include "mac_features/ack_generator/nrf_802154_ack_generator.h"
75 #include "rsch/nrf_802154_rsch.h"
76 #include "rsch/nrf_802154_rsch_crit_sect.h"
77 #include "timer/nrf_802154_timer_coord.h"
78 #include "platform/nrf_802154_irq.h"
79 #include "protocol/mpsl_fem_protocol_api.h"
80 
81 #include "nrf_802154_core_hooks.h"
82 #include "nrf_802154_sl_ant_div.h"
83 
84 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
85 #include "nrf_802154_bsim_utils.h"
86 #include "NRF_AES_ECB.h"
87 #endif
88 
89 /// Delay before first check of received frame: 24 bits is PHY header and MAC Frame Control field.
90 #define BCC_INIT                    (3 * 8)
91 
92 /// Duration of single iteration of Energy Detection procedure
93 #define ED_ITER_DURATION            128U
94 /// Overhead of hardware preparation for ED procedure (aTurnaroundTime) [number of iterations]
95 #define ED_ITERS_OVERHEAD           2U
96 
97 #define MAX_CRIT_SECT_TIME          60   ///< Maximal time that the driver spends in single critical section.
98 
99 #define LQI_VALUE_FACTOR            4    ///< Factor needed to calculate LQI value based on data from RADIO peripheral
100 #define LQI_MAX                     0xff ///< Maximal LQI value
101 
102 /** Get LQI of given received packet. If CRC is calculated by hardware LQI is included instead of CRC
103  *  in the frame. Length is stored in byte with index 0; CRC is 2 last bytes.
104  */
105 #define RX_FRAME_LQI(data)          ((data)[(data)[0] - 1])
106 
107 /** Timeout value when waiting for ntf_802154_trx_receive_frame_started after ntf_802154_trx_receive_frame_prestarted.
108  *  Timeout value in microseconds. The time equals to whole synchronization header (SHR) duration of 802.15.4 frame.
109  */
110 #define PRESTARTED_TIMER_TIMEOUT_US (160U)
111 
112 #if NRF_802154_RX_BUFFERS > 1
113 /// Pointer to currently used receive buffer.
114 static rx_buffer_t * mp_current_rx_buffer;
115 
116 #else
117 /// If there is only one buffer use const pointer to the receive buffer.
118 static rx_buffer_t * const mp_current_rx_buffer = &nrf_802154_rx_buffers[0];
119 
120 #endif
121 
122 static uint8_t                       * mp_ack;                  ///< Pointer to Ack frame buffer.
123 static uint8_t                       * mp_tx_data;              ///< Pointer to the data to transmit.
124 static uint32_t                        m_ed_time_left;          ///< Remaining time of the current energy detection procedure [us].
125 static uint8_t                         m_ed_result;             ///< Result of the current energy detection procedure.
126 static uint8_t                         m_last_lqi;              ///< LQI of the last received non-ACK frame, corrected for the temperature.
127 static nrf_802154_fal_tx_power_split_t m_tx_power;              ///< Power to be used to transmit the current frame split into components.
128 static uint8_t                         m_tx_channel;            ///< Channel to be used to transmit the current frame.
129 static int8_t                          m_last_rssi;             ///< RSSI of the last received non-ACK frame, corrected for the temperature.
130 static uint8_t                         m_no_rx_buffer_notified; ///< Set when NRF_802154_RX_ERROR_NO_BUFFER has been notified.
131 
132 static nrf_802154_frame_parser_data_t m_current_rx_frame_data;  ///< RX frame parser data.
133 
134 static volatile radio_state_t m_state;                          ///< State of the radio driver.
135 
136 typedef struct
137 {
138     bool frame_filtered        : 1; ///< If frame being received passed filtering operation.
139     bool frame_parsed          : 1; ///< If frame being received has been parsed
140     bool rx_timeslot_requested : 1; ///< If timeslot for the frame being received is already requested.
141     bool tx_with_cca           : 1; ///< If currently transmitted frame is transmitted with cca.
142     bool tx_diminished_prio    : 1; ///< If priority of the current transmission should be diminished.
143 
144 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
145     bool tx_started_notify     : 1; ///< If higher layer should be notified that transmission started.
146 
147 #endif
148 } nrf_802154_flags_t;
149 
150 static nrf_802154_flags_t m_flags;                            ///< Flags used to store the current driver state.
151 
152 static volatile bool        m_rsch_timeslot_is_granted;       ///< State of the RSCH timeslot.
153 static volatile rsch_prio_t m_rsch_priority = RSCH_PRIO_IDLE; ///< Last notified RSCH priority.
154 
155 /** @brief Value of argument @c notifications_mask to @ref nrf_802154_trx_receive_frame */
156 static nrf_802154_trx_receive_notifications_t m_trx_receive_frame_notifications_mask;
157 /** @brief Value of argument @c notifications_mask to @ref nrf_802154_trx_transmit_frame */
158 static nrf_802154_trx_transmit_notifications_t m_trx_transmit_frame_notifications_mask;
159 
160 static volatile uint8_t      m_rx_prestarted_trig_count;
161 static nrf_802154_sl_timer_t m_rx_prestarted_timer;
162 
163 /** @brief Value of Coex TX Request mode */
164 static nrf_802154_coex_tx_request_mode_t m_coex_tx_request_mode;
165 
166 /** @brief Identifier of currently active reception window. */
167 static uint32_t m_rx_window_id;
168 
169 static const nrf_802154_transmitted_frame_props_t m_default_frame_props =
170     NRF_802154_TRANSMITTED_FRAME_PROPS_DEFAULT_INIT;
171 
172 /***************************************************************************************************
173  * @section Common core operations
174  **************************************************************************************************/
175 
176 static rsch_prio_t min_required_rsch_prio(radio_state_t state);
177 
request_preconditions_for_state(radio_state_t state)178 static void request_preconditions_for_state(radio_state_t state)
179 {
180     nrf_802154_rsch_crit_sect_prio_request(min_required_rsch_prio(state));
181 }
182 
183 /** Set driver state.
184  *
185  * @param[in]  state  Driver state to set.
186  */
state_set(radio_state_t state)187 static void state_set(radio_state_t state)
188 {
189     m_state = state;
190 
191     nrf_802154_log_local_event(NRF_802154_LOG_VERBOSITY_LOW,
192                                NRF_802154_LOG_LOCAL_EVENT_ID_CORE__SET_STATE,
193                                (uint32_t)state);
194 
195     request_preconditions_for_state(state);
196 }
197 
198 /** Specifies what ramp up trigger mode to use when handling RX or TX operation request.
199  *
200  * It is assumed that the DELAYED_TRX module always requests HW mode both RX and TX,
201  * while in all other cases SW mode is required.
202  *
203  * @param[in]  request_orig  Module that originates the request.
204  */
ramp_up_mode_choose(req_originator_t request_orig)205 static nrf_802154_trx_ramp_up_trigger_mode_t ramp_up_mode_choose(req_originator_t request_orig)
206 {
207     return (request_orig == REQ_ORIG_DELAYED_TRX) ?
208            TRX_RAMP_UP_HW_TRIGGER : TRX_RAMP_UP_SW_TRIGGER;
209 }
210 
211 /** Clear RX frame data. */
rx_data_clear(void)212 static void rx_data_clear(void)
213 {
214     (void)nrf_802154_frame_parser_data_init(mp_current_rx_buffer->data,
215                                             0U,
216                                             PARSE_LEVEL_NONE,
217                                             &m_current_rx_frame_data);
218 }
219 
220 /** Clear flags describing frame being received. */
rx_flags_clear(void)221 static void rx_flags_clear(void)
222 {
223     m_flags.frame_filtered        = false;
224     m_flags.rx_timeslot_requested = false;
225     m_flags.frame_parsed          = false;
226 }
227 
228 /** Wait for the RSSI measurement. */
rssi_measurement_wait(void)229 static void rssi_measurement_wait(void)
230 {
231     while (!nrf_802154_trx_rssi_sample_is_available())
232     {
233         // Intentionally empty: This function is called from a critical section.
234         // WFE would not be waken up by a RADIO event.
235     }
236 }
237 
238 /** Get the result of the last RSSI measurement.
239  *
240  * @returns  Result of the last RSSI measurement in dBm.
241  */
rssi_last_measurement_get(void)242 static int8_t rssi_last_measurement_get(void)
243 {
244     uint8_t rssi_sample = nrf_802154_trx_rssi_last_sample_get();
245 
246     rssi_sample = nrf_802154_rssi_sample_corrected_get(rssi_sample);
247 
248     return -((int8_t)rssi_sample);
249 }
250 
251 /** Get LQI of a received frame.
252  *
253  * @param[in]  p_data  Pointer to buffer containing PHR and PSDU of received frame
254  *
255  * @returns  LQI of given frame.
256  */
lqi_get(const uint8_t * p_data)257 static uint8_t lqi_get(const uint8_t * p_data)
258 {
259     uint32_t lqi = RX_FRAME_LQI(p_data);
260 
261     lqi  = nrf_802154_rssi_lqi_corrected_get(lqi);
262     lqi *= LQI_VALUE_FACTOR;
263 
264     if (lqi > LQI_MAX)
265     {
266         lqi = LQI_MAX;
267     }
268 
269     return (uint8_t)lqi;
270 }
271 
272 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
273 /**
274  * @brief Get timestamp made by timer coordinator.
275  *
276  * @note This function increments the returned value by 1 us if the timestamp is equal to the
277  *       @ref NRF_802154_NO_TIMESTAMP value to indicate that the timestamp is available.
278  *
279  * @returns Timestamp [us] of the last event captured by timer coordinator frame or
280  *          @ref NRF_802154_NO_TIMESTAMP if the timestamp is inaccurate.
281  */
timer_coord_timestamp_get(void)282 static uint64_t timer_coord_timestamp_get(void)
283 {
284     uint64_t timestamp          = NRF_802154_NO_TIMESTAMP;
285     bool     timestamp_received = nrf_802154_timer_coord_timestamp_get(&timestamp);
286 
287     if (!timestamp_received)
288     {
289         timestamp = NRF_802154_NO_TIMESTAMP;
290     }
291     else if (timestamp == NRF_802154_NO_TIMESTAMP)
292     {
293         timestamp++;
294     }
295     else
296     {
297         // Return timestamp without correction
298     }
299 
300     return timestamp;
301 }
302 
303 #endif
304 
received_frame_notify(uint8_t * p_data)305 static void received_frame_notify(uint8_t * p_data)
306 {
307     nrf_802154_notify_received(p_data, m_last_rssi, m_last_lqi);
308 }
309 
310 /** Allow nesting critical sections and notify MAC layer that a frame was received. */
received_frame_notify_and_nesting_allow(uint8_t * p_data)311 static void received_frame_notify_and_nesting_allow(uint8_t * p_data)
312 {
313     nrf_802154_critical_section_nesting_allow();
314 
315     received_frame_notify(p_data);
316 
317     nrf_802154_critical_section_nesting_deny();
318 }
319 
320 /** Notify MAC layer that receive procedure failed. */
receive_failed_notify(nrf_802154_rx_error_t error)321 static void receive_failed_notify(nrf_802154_rx_error_t error)
322 {
323     nrf_802154_critical_section_nesting_allow();
324 
325     // Don't care about the result - if the notification cannot be performed
326     // no impact on the device's operation is expected
327     (void)nrf_802154_notify_receive_failed(error, m_rx_window_id, true);
328 
329     nrf_802154_critical_section_nesting_deny();
330 }
331 
332 /** Notify MAC layer that transmission of requested frame has started. */
transmit_started_notify(void)333 static void transmit_started_notify(void)
334 {
335     uint8_t * p_frame = mp_tx_data;
336 
337 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
338     /**
339      * TX started hooks were executed before transmission started. Use latched result
340      */
341     if (m_flags.tx_started_notify)
342 #else
343     if (nrf_802154_core_hooks_tx_started(p_frame))
344 #endif
345     {
346         nrf_802154_tx_started(p_frame);
347     }
348 
349 }
350 
351 /** Notify MAC layer that transmission of ACK frame has started. */
transmit_ack_started_notify()352 static void transmit_ack_started_notify()
353 {
354 #if !defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
355     nrf_802154_core_hooks_tx_ack_started(mp_ack);
356 #else
357     /**
358      * Otherwise this was already called immediately after setting up the transmission.
359      */
360 #endif
361     nrf_802154_tx_ack_started(mp_ack);
362 }
363 
364 /** Notify that reception of a frame has started. */
receive_started_notify(void)365 static void receive_started_notify(void)
366 {
367     const uint8_t * p_frame = mp_current_rx_buffer->data;
368 
369     nrf_802154_core_hooks_rx_started(p_frame);
370 }
371 
372 /** Notify MAC layer that a frame was transmitted. */
transmitted_frame_notify(uint8_t * p_ack,int8_t power,uint8_t lqi)373 static void transmitted_frame_notify(uint8_t * p_ack, int8_t power, uint8_t lqi)
374 {
375     uint8_t                           * p_frame  = mp_tx_data;
376     nrf_802154_transmit_done_metadata_t metadata = {0};
377 
378     metadata.data.transmitted.p_ack = p_ack;
379     metadata.data.transmitted.power = power;
380     metadata.data.transmitted.lqi   = lqi;
381 
382     if (p_ack == NULL)
383     {
384         metadata.data.transmitted.time = NRF_802154_NO_TIMESTAMP;
385     }
386     else
387     {
388         nrf_802154_stat_timestamp_read(&metadata.data.transmitted.time, last_ack_end_timestamp);
389     }
390 
391     nrf_802154_critical_section_nesting_allow();
392 
393     nrf_802154_core_hooks_transmitted(p_frame);
394 
395     nrf_802154_notify_transmitted(p_frame, &metadata);
396 
397     nrf_802154_critical_section_nesting_deny();
398 }
399 
400 /** Notify MAC layer that transmission procedure failed. */
transmit_failed_notify(uint8_t * p_frame,nrf_802154_tx_error_t error,const nrf_802154_transmit_done_metadata_t * p_meta)401 static void transmit_failed_notify(uint8_t                                   * p_frame,
402                                    nrf_802154_tx_error_t                       error,
403                                    const nrf_802154_transmit_done_metadata_t * p_meta)
404 {
405     if (nrf_802154_core_hooks_tx_failed(p_frame, error))
406     {
407         nrf_802154_notify_transmit_failed(p_frame, error, p_meta);
408     }
409 }
410 
411 /** Allow nesting critical sections and notify MAC layer that transmission procedure failed. */
transmit_failed_notify_and_nesting_allow(nrf_802154_tx_error_t error,const nrf_802154_transmit_done_metadata_t * p_meta)412 static void transmit_failed_notify_and_nesting_allow(
413     nrf_802154_tx_error_t                       error,
414     const nrf_802154_transmit_done_metadata_t * p_meta)
415 {
416     nrf_802154_critical_section_nesting_allow();
417 
418     transmit_failed_notify(mp_tx_data, error, p_meta);
419 
420     nrf_802154_critical_section_nesting_deny();
421 }
422 
423 /** Notify MAC layer that energy detection procedure ended. */
energy_detected_notify(const nrf_802154_energy_detected_t * p_result)424 static void energy_detected_notify(const nrf_802154_energy_detected_t * p_result)
425 {
426     nrf_802154_critical_section_nesting_allow();
427 
428     nrf_802154_notify_energy_detected(p_result);
429 
430     nrf_802154_critical_section_nesting_deny();
431 }
432 
433 /** Notify MAC layer that CCA procedure ended. */
cca_notify(bool result)434 static void cca_notify(bool result)
435 {
436     nrf_802154_critical_section_nesting_allow();
437 
438     nrf_802154_notify_cca(result);
439 
440     nrf_802154_critical_section_nesting_deny();
441 }
442 
443 /** Check if timeslot is currently granted.
444  *
445  * @retval true   The timeslot is granted.
446  * @retval false  The timeslot is not granted.
447  */
timeslot_is_granted(void)448 static bool timeslot_is_granted(void)
449 {
450     return m_rsch_timeslot_is_granted;
451 }
452 
antenna_diversity_is_enabled(void)453 static bool antenna_diversity_is_enabled(void)
454 {
455     return (NRF_802154_SL_ANT_DIV_MODE_DISABLED !=
456             nrf_802154_sl_ant_div_cfg_mode_get(NRF_802154_SL_ANT_DIV_OP_RX));
457 }
458 
459 /***************************************************************************************************
460  * @section RX buffer management
461  **************************************************************************************************/
462 
463 /** Set currently used rx buffer to given address.
464  *
465  * @param[in]  p_rx_buffer  Pointer to receive buffer that should be used now.
466  */
rx_buffer_in_use_set(rx_buffer_t * p_rx_buffer)467 static void rx_buffer_in_use_set(rx_buffer_t * p_rx_buffer)
468 {
469 #if NRF_802154_RX_BUFFERS > 1
470     mp_current_rx_buffer = p_rx_buffer;
471 #else
472     (void)p_rx_buffer;
473 #endif
474 }
475 
476 /** Check if currently there is available rx buffer.
477  *
478  * @retval true   There is available rx buffer.
479  * @retval false  Currently there is no available rx buffer.
480  */
rx_buffer_is_available(void)481 static bool rx_buffer_is_available(void)
482 {
483     return (mp_current_rx_buffer != NULL) && (mp_current_rx_buffer->free);
484 }
485 
486 /** Get pointer to available rx buffer.
487  *
488  * @returns Pointer to available rx buffer or NULL if rx buffer is not available.
489  */
rx_buffer_get(void)490 static uint8_t * rx_buffer_get(void)
491 {
492     return rx_buffer_is_available() ? mp_current_rx_buffer->data : NULL;
493 }
494 
495 /***************************************************************************************************
496  * @section ACK transmission management
497  **************************************************************************************************/
498 
499 /** Check if ACK is requested in given frame.
500  *
501  * @param[in]  p_frame  Pointer to a frame to check.
502  *
503  * @retval  true   ACK is requested in given frame.
504  * @retval  false  ACK is not requested in given frame.
505  */
ack_is_requested(const uint8_t * p_frame)506 static bool ack_is_requested(const uint8_t * p_frame)
507 {
508     nrf_802154_frame_parser_data_t frame_data;
509 
510     if ((p_frame[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK) == FRAME_TYPE_MULTIPURPOSE)
511     {
512         // Multipurpose frame parsing is not implemented, so assume AR is not set.
513         return false;
514     }
515 
516     bool result = nrf_802154_frame_parser_data_init(p_frame,
517                                                     p_frame[PHR_OFFSET] + PHR_SIZE,
518                                                     PARSE_LEVEL_FCF_OFFSETS,
519                                                     &frame_data);
520 
521     return result && nrf_802154_frame_parser_ar_bit_is_set(&frame_data);
522 }
523 
524 /***************************************************************************************************
525  * @section Energy detection management
526  **************************************************************************************************/
527 
528 /** Setup next iteration of energy detection procedure.
529  *
530  *  Energy detection procedure is performed in iterations to make sure it is performed for requested
531  *  time regardless radio arbitration.
532  *
533  *  @param[inout] p_requested_ed_time_us  Remaining time of energy detection procedure [us]. Value will be updated
534  *                                        with time remaining for the next attempt of energy detection.
535  *  @param[out]   p_next_trx_ed_count     Number of trx energy detection iterations to perform.
536  *
537  *  @retval  true   Next iteration of energy detection procedure will be performed now.
538  *  @retval  false  Next iteration of energy detection procedure will not be performed now due to
539  *                  ending timeslot.
540  */
ed_iter_setup(uint32_t * p_requested_ed_time_us,uint32_t * p_next_trx_ed_count)541 static bool ed_iter_setup(uint32_t * p_requested_ed_time_us, uint32_t * p_next_trx_ed_count)
542 {
543     uint32_t iters_left_in_timeslot = nrf_802154_rsch_timeslot_us_left_get() / ED_ITER_DURATION;
544 
545     if (iters_left_in_timeslot > ED_ITERS_OVERHEAD)
546     {
547         /* Note that in single phy iters_left_in_timeslot will always be very big thus we will get here. */
548         iters_left_in_timeslot -= ED_ITERS_OVERHEAD;
549 
550         uint32_t requested_iters = *p_requested_ed_time_us / ED_ITER_DURATION;
551 
552         if (requested_iters < iters_left_in_timeslot)
553         {
554             /* We will finish all iterations before timeslot end, thus no time is left */
555             *p_requested_ed_time_us = 0U;
556         }
557         else
558         {
559             *p_requested_ed_time_us = *p_requested_ed_time_us -
560                                       (iters_left_in_timeslot * ED_ITER_DURATION);
561             requested_iters = iters_left_in_timeslot;
562         }
563 
564         *p_next_trx_ed_count = requested_iters;
565 
566         return true;
567     }
568 
569     return false;
570 }
571 
572 /***************************************************************************************************
573  * @section FSM transition request sub-procedures
574  **************************************************************************************************/
575 
min_required_rsch_prio(radio_state_t state)576 static rsch_prio_t min_required_rsch_prio(radio_state_t state)
577 {
578     switch (state)
579     {
580         case RADIO_STATE_SLEEP:
581             return RSCH_PRIO_IDLE;
582 
583         case RADIO_STATE_FALLING_ASLEEP:
584         case RADIO_STATE_RX:
585             return RSCH_PRIO_IDLE_LISTENING;
586 
587         case RADIO_STATE_RX_ACK:
588         case RADIO_STATE_ED:
589         case RADIO_STATE_CCA:
590             return RSCH_PRIO_RX;
591 
592         case RADIO_STATE_TX:
593         case RADIO_STATE_TX_ACK:
594 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
595         case RADIO_STATE_CONTINUOUS_CARRIER:
596         case RADIO_STATE_MODULATED_CARRIER:
597 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
598             return RSCH_PRIO_TX;
599 
600         case RADIO_STATE_CCA_TX:
601             if (m_flags.tx_diminished_prio)
602             {
603                 return RSCH_PRIO_IDLE_LISTENING;
604             }
605             else
606             {
607                 return RSCH_PRIO_TX;
608             }
609 
610         default:
611             NRF_802154_ASSERT(false);
612             return RSCH_PRIO_IDLE;
613     }
614 }
615 
is_state_allowed_for_prio(rsch_prio_t prio,radio_state_t state)616 static bool is_state_allowed_for_prio(rsch_prio_t prio, radio_state_t state)
617 {
618     return (min_required_rsch_prio(state) <= prio);
619 }
620 
are_preconditions_met(void)621 static bool are_preconditions_met(void)
622 {
623     rsch_prio_t   current_prio;
624     radio_state_t current_state;
625 
626     current_prio  = m_rsch_priority;
627     current_state = m_state;
628 
629     return is_state_allowed_for_prio(current_prio, current_state);
630 }
631 
action_needed(rsch_prio_t old_prio,rsch_prio_t new_prio,radio_state_t state)632 static int_fast8_t action_needed(rsch_prio_t old_prio, rsch_prio_t new_prio, radio_state_t state)
633 {
634     bool old_prio_allows = is_state_allowed_for_prio(old_prio, state);
635     bool new_prio_allows = is_state_allowed_for_prio(new_prio, state);
636 
637     int_fast8_t result = 0;
638 
639     if (old_prio_allows && !new_prio_allows)
640     {
641         result = -1;
642     }
643     else if (!old_prio_allows && new_prio_allows)
644     {
645         result = 1;
646     }
647 
648     return result;
649 }
650 
651 /** Check if time remaining in the timeslot is long enough to process whole critical section. */
remaining_timeslot_time_is_enough_for_crit_sect(void)652 static bool remaining_timeslot_time_is_enough_for_crit_sect(void)
653 {
654     return nrf_802154_rsch_timeslot_us_left_get() >= MAX_CRIT_SECT_TIME;
655 }
656 
657 /** Check if critical section can be processed at the moment.
658  *
659  * @note This function returns valid result only inside critical section.
660  *
661  * @retval true   There is enough time in current timeslot or timeslot is denied at the moment.
662  * @retval false  Current timeslot ends too shortly to process critical section inside.
663  */
critical_section_can_be_processed_now(void)664 static bool critical_section_can_be_processed_now(void)
665 {
666     return !timeslot_is_granted() || remaining_timeslot_time_is_enough_for_crit_sect();
667 }
668 
669 /** Enter critical section and verify if there is enough time to complete operations within. */
critical_section_enter_and_verify_timeslot_length(void)670 static bool critical_section_enter_and_verify_timeslot_length(void)
671 {
672     bool result = nrf_802154_critical_section_enter();
673 
674     if (result)
675     {
676         if (!critical_section_can_be_processed_now())
677         {
678             result = false;
679 
680             nrf_802154_critical_section_exit();
681         }
682     }
683 
684     return result;
685 }
686 
can_terminate_current_operation(radio_state_t state,nrf_802154_term_t term_lvl,bool receiving_psdu_now)687 static bool can_terminate_current_operation(radio_state_t     state,
688                                             nrf_802154_term_t term_lvl,
689                                             bool              receiving_psdu_now)
690 {
691     bool result = false;
692 
693     switch (state)
694     {
695         case RADIO_STATE_SLEEP:
696         case RADIO_STATE_FALLING_ASLEEP:
697 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
698         case RADIO_STATE_CONTINUOUS_CARRIER:
699         case RADIO_STATE_MODULATED_CARRIER:
700 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
701             result = true;
702             break;
703 
704         case RADIO_STATE_RX:
705             result = (term_lvl >= NRF_802154_TERM_802154) || !receiving_psdu_now;
706             break;
707 
708         case RADIO_STATE_TX_ACK:
709         case RADIO_STATE_CCA_TX:
710         case RADIO_STATE_TX:
711         case RADIO_STATE_RX_ACK:
712         case RADIO_STATE_ED:
713         case RADIO_STATE_CCA:
714             result = (term_lvl >= NRF_802154_TERM_802154);
715             break;
716 
717         default:
718             NRF_802154_ASSERT(false);
719     }
720 
721     return result;
722 }
723 
operation_terminated_notify(radio_state_t state,bool receiving_psdu_now)724 static void operation_terminated_notify(radio_state_t state, bool receiving_psdu_now)
725 {
726     switch (state)
727     {
728         case RADIO_STATE_SLEEP:
729         case RADIO_STATE_FALLING_ASLEEP:
730 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
731         case RADIO_STATE_CONTINUOUS_CARRIER:
732         case RADIO_STATE_MODULATED_CARRIER:
733 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
734             break;
735 
736         case RADIO_STATE_RX:
737             if (receiving_psdu_now)
738             {
739                 // Don't care about the result - if the notification cannot be performed
740                 // no impact on the device's operation is expected
741                 (void)nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_ABORTED,
742                                                        m_rx_window_id,
743                                                        true);
744             }
745 
746             break;
747 
748         case RADIO_STATE_TX_ACK:
749             mp_current_rx_buffer->free = false;
750             nrf_802154_core_hooks_tx_ack_failed(mp_ack, NRF_802154_TX_ERROR_ABORTED);
751             received_frame_notify(mp_current_rx_buffer->data);
752             break;
753 
754         case RADIO_STATE_CCA_TX:
755         case RADIO_STATE_TX:
756         {
757             nrf_802154_transmit_done_metadata_t metadata = {};
758 
759             nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
760             transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_ABORTED, &metadata);
761         }
762         break;
763 
764         case RADIO_STATE_RX_ACK:
765         {
766             nrf_802154_transmit_done_metadata_t metadata = {};
767 
768             nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
769             transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_NO_ACK, &metadata);
770         }
771         break;
772 
773         case RADIO_STATE_ED:
774             nrf_802154_notify_energy_detection_failed(NRF_802154_ED_ERROR_ABORTED);
775             break;
776 
777         case RADIO_STATE_CCA:
778             nrf_802154_notify_cca_failed(NRF_802154_CCA_ERROR_ABORTED);
779             break;
780 
781         default:
782             NRF_802154_ASSERT(false);
783     }
784 }
785 
786 /** Terminate ongoing operation.
787  *
788  * This function is called when MAC layer requests transition to another operation.
789  *
790  * After calling this function RADIO should enter DISABLED state and Radio Scheduler
791  * should be in continuous mode.
792  *
793  * @param[in]  term_lvl      Termination level of this request. Selects procedures to abort.
794  * @param[in]  req_orig      Module that originates termination request.
795  * @param[in]  notify_abort  If Termination of current operation shall be notified.
796  *
797  * @retval true   Terminated ongoing operation.
798  * @retval false  Ongoing operation was not terminated.
799  */
current_operation_terminate(nrf_802154_term_t term_lvl,req_originator_t req_orig,bool notify)800 static bool current_operation_terminate(nrf_802154_term_t term_lvl,
801                                         req_originator_t  req_orig,
802                                         bool              notify)
803 {
804     bool result = nrf_802154_core_hooks_terminate(term_lvl, req_orig);
805 
806     if (result)
807     {
808         bool receiving_psdu_now = false;
809 
810         if (m_state == RADIO_STATE_RX)
811         {
812             receiving_psdu_now = nrf_802154_trx_psdu_is_being_received();
813         }
814 
815         result = can_terminate_current_operation(m_state, term_lvl, receiving_psdu_now);
816 
817         if (result)
818         {
819             nrf_802154_trx_abort();
820 
821             if (m_state == RADIO_STATE_RX)
822             {
823                 /* When in rx mode, nrf_802154_trx_receive_frame_prestarted handler might
824                  * have already been called. We need to stop counting timeout. */
825                 m_rx_prestarted_trig_count = 0;
826                 (void)nrf_802154_sl_timer_remove(&m_rx_prestarted_timer);
827 
828                 /* Notify antenna diversity module that RX has been aborted. */
829                 nrf_802154_sl_ant_div_rx_aborted_notify();
830 
831                 /* We might have boosted preconditions (to support coex) above level
832                  * normally requested for current state by request_preconditions_for_state(m_state).
833                  * When current operation is terminated we request preconditions back
834                  * thus ceasing to request to coex. */
835                 request_preconditions_for_state(m_state);
836             }
837 
838             if (m_state == RADIO_STATE_ED)
839             {
840                 nrf_802154_sl_ant_div_energy_detection_aborted_notify();
841             }
842 
843             if (notify)
844             {
845                 operation_terminated_notify(m_state, receiving_psdu_now);
846             }
847         }
848 
849     }
850 
851     return result;
852 }
853 
854 /** Initialize Falling Asleep operation. */
falling_asleep_init(void)855 static void falling_asleep_init(void)
856 {
857     if (nrf_802154_trx_go_idle())
858     {
859         // There will be nrf_802154_trx_in_idle call, where we will continue processing
860     }
861     else
862     {
863         state_set(RADIO_STATE_SLEEP);
864     }
865 }
866 
867 /**@brief Makes value to be passed to @ref nrf_802154_trx_receive_frame as @c notifications_mask parameter */
make_trx_frame_receive_notification_mask(void)868 static nrf_802154_trx_receive_notifications_t make_trx_frame_receive_notification_mask(void)
869 {
870     nrf_802154_trx_receive_notifications_t result = TRX_RECEIVE_NOTIFICATION_NONE;
871 
872 #if (NRF_802154_STATS_COUNT_ENERGY_DETECTED_EVENTS)
873     result |= TRX_RECEIVE_NOTIFICATION_PRESTARTED;
874 #endif
875 #if (NRF_802154_STATS_COUNT_RECEIVED_PREAMBLES)
876     result |= TRX_RECEIVE_NOTIFICATION_STARTED;
877 #endif
878 
879     if (nrf_802154_wifi_coex_is_enabled())
880     {
881         switch (nrf_802154_pib_coex_rx_request_mode_get())
882         {
883             case NRF_802154_COEX_RX_REQUEST_MODE_DESTINED:
884                 /* Coex requesting handled through nrf_802154_trx_receive_frame_bcmatched handler.
885                  * No additional notifications required. */
886                 break;
887 
888             case NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION:
889                 result |= TRX_RECEIVE_NOTIFICATION_PRESTARTED | TRX_RECEIVE_NOTIFICATION_STARTED;
890                 // Note: TRX_RECEIVE_NOTIFICATION_STARTED is required for stopping counting timeout for
891                 // activity triggered by nrf_802154_trx_receive_frame_prestarted.
892                 break;
893 
894             case NRF_802154_COEX_RX_REQUEST_MODE_PREAMBLE:
895                 result |= TRX_RECEIVE_NOTIFICATION_STARTED;
896                 break;
897 
898             default:
899                 NRF_802154_ASSERT(false);
900         }
901     }
902 
903     return result;
904 }
905 
906 /**@brief Makes value to be passed to @ref nrf_802154_trx_transmit_frame as @c notifications_mask parameter
907  *
908  * @param[in] cca   Pass true, if cca operation it to be performed before transmit.
909  *                  Pass false otherwise.
910  */
make_trx_frame_transmit_notification_mask(bool cca)911 static nrf_802154_trx_transmit_notifications_t make_trx_frame_transmit_notification_mask(bool cca)
912 {
913     nrf_802154_trx_transmit_notifications_t result = TRX_TRANSMIT_NOTIFICATION_NONE;
914 
915 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
916     if (cca)
917     {
918         result |= TRX_TRANSMIT_NOTIFICATION_CCAIDLE;
919     }
920 #endif
921 
922     if (nrf_802154_wifi_coex_is_enabled())
923     {
924         switch (nrf_802154_pib_coex_tx_request_mode_get())
925         {
926             case NRF_802154_COEX_TX_REQUEST_MODE_FRAME_READY:
927             case NRF_802154_COEX_TX_REQUEST_MODE_CCA_START:
928             case NRF_802154_COEX_TX_REQUEST_MODE_ON_CCA_TOGGLE:
929                 /* No additional notifications required. */
930                 break;
931 
932             case NRF_802154_COEX_TX_REQUEST_MODE_CCA_DONE:
933                 result |= TRX_TRANSMIT_NOTIFICATION_CCAIDLE;
934                 break;
935 
936             default:
937                 NRF_802154_ASSERT(false);
938         }
939     }
940 
941     return result;
942 }
943 
notify_no_rx_buffer(void)944 static void notify_no_rx_buffer(void)
945 {
946     uint8_t old_value = 0U;
947 
948     if (nrf_802154_sl_atomic_cas_u8(&m_no_rx_buffer_notified, &old_value, 1U))
949     {
950         receive_failed_notify(NRF_802154_RX_ERROR_NO_BUFFER);
951     }
952 }
953 
rx_init_free_buffer_find_and_update(bool free_buffer)954 static void rx_init_free_buffer_find_and_update(bool free_buffer)
955 {
956     if (!free_buffer)
957     {
958         // If no buffer was available, then find a new one.
959         rx_buffer_in_use_set(nrf_802154_rx_buffer_free_find());
960 
961         uint8_t * rx_buffer = rx_buffer_get();
962 
963         nrf_802154_trx_receive_buffer_set(rx_buffer);
964 
965         if (NULL == rx_buffer)
966         {
967             notify_no_rx_buffer();
968         }
969     }
970 }
971 
972 /**
973  * @brief Initializes RX operation
974  *
975  * @param[in]  ru_tr_mode            Desired trigger mode for radio ramp up.
976  * @param[out] p_abort_shall_follow  It is set to `true` when initialization fails and the trx
977  *                                   module needs to be reset. When obtaining `true` here, the user
978  *                                   is then obliged to call @ref nrf_802154_trx_abort. Such a case
979  *                                   can only happen when @p ru_tr_mode = TRX_RAMP_UP_HW_TRIGGER.
980  *                                   In all other cases, the value is not modified at all, so it
981  *                                   should be initialized to `false` before calling the function.
982  *                                   Can be NULL if @p ru_tr_mode is not TRX_RAMP_UP_HW_TRIGGER.
983  */
rx_init(nrf_802154_trx_ramp_up_trigger_mode_t ru_tr_mode,bool * p_abort_shall_follow)984 static void rx_init(nrf_802154_trx_ramp_up_trigger_mode_t ru_tr_mode, bool * p_abort_shall_follow)
985 {
986     bool free_buffer;
987 
988     if (!timeslot_is_granted())
989     {
990         return;
991     }
992 
993     if (!are_preconditions_met())
994     {
995         return;
996     }
997 
998     // Clear filtering flag
999     rx_flags_clear();
1000 
1001     // Find available RX buffer
1002     free_buffer = rx_buffer_is_available();
1003 
1004     nrf_802154_trx_receive_buffer_set(rx_buffer_get());
1005 
1006     nrf_802154_fal_tx_power_split_t split_power = {0};
1007 
1008     (void)nrf_802154_tx_power_split_pib_power_get(&split_power);
1009 
1010     nrf_802154_trx_channel_set(nrf_802154_pib_channel_get());
1011 
1012     nrf_802154_trx_receive_frame(BCC_INIT / 8U,
1013                                  ru_tr_mode,
1014                                  m_trx_receive_frame_notifications_mask,
1015                                  &split_power);
1016 
1017     if (ru_tr_mode == TRX_RAMP_UP_HW_TRIGGER)
1018     {
1019         uint32_t ppi_ch = nrf_802154_trx_ramp_up_ppi_channel_get();
1020 
1021         if (!nrf_802154_rsch_delayed_timeslot_ppi_update(ppi_ch))
1022         {
1023             /**
1024              * The trigger has occurred. This has happened too early so there is a high risk
1025              * that the radio will not ramp up. It is necessary to abort the operation.
1026              */
1027             NRF_802154_ASSERT(p_abort_shall_follow);
1028             *p_abort_shall_follow = true;
1029         }
1030     }
1031 
1032 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
1033     // Configure the timer coordinator to get a timestamp of the CRCOK event.
1034     nrf_802154_timer_coord_timestamp_prepare(nrf_802154_trx_radio_crcok_event_handle_get());
1035 #endif
1036 
1037     rx_init_free_buffer_find_and_update(free_buffer);
1038 
1039     rx_data_clear();
1040 
1041     mp_ack = NULL;
1042 }
1043 
1044 /** Initialize TX operation. */
tx_init(const uint8_t * p_data,nrf_802154_trx_ramp_up_trigger_mode_t rampup_trigg_mode,uint8_t cca_attempts)1045 static bool tx_init(const uint8_t                       * p_data,
1046                     nrf_802154_trx_ramp_up_trigger_mode_t rampup_trigg_mode,
1047                     uint8_t                               cca_attempts)
1048 {
1049     bool cca = cca_attempts > 0;
1050 
1051     if (!timeslot_is_granted() || !nrf_802154_rsch_timeslot_request(
1052             nrf_802154_tx_duration_get(p_data[0], cca, ack_is_requested(p_data))))
1053     {
1054         return false;
1055     }
1056 
1057     if (!are_preconditions_met())
1058     {
1059         return false;
1060     }
1061 
1062 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
1063     if (cca)
1064     {
1065         // Configure the timer coordinator to get a time stamp of the READY event.
1066         // Note: This event triggers CCASTART, so the time stamp of READY event
1067         // is the time stamp when CCA started.
1068         nrf_802154_timer_coord_timestamp_prepare(nrf_802154_trx_radio_ready_event_handle_get());
1069     }
1070     else
1071     {
1072         // Configure the timer coordinator to get a time stamp of the PHYEND event.
1073         nrf_802154_timer_coord_timestamp_prepare(nrf_802154_trx_radio_phyend_event_handle_get());
1074     }
1075 #endif
1076 
1077     nrf_802154_trx_channel_set(m_tx_channel);
1078     m_flags.tx_with_cca = cca;
1079     nrf_802154_trx_transmit_frame(nrf_802154_tx_work_buffer_get(p_data),
1080                                   rampup_trigg_mode,
1081                                   cca_attempts,
1082                                   &m_tx_power,
1083                                   m_trx_transmit_frame_notifications_mask);
1084 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
1085     /**
1086      * In simulation the frame contents are latched when the first bit of the preamble is
1087      * "transmitted" by the simulated radio. Any modifications performed after that (for example in
1088      * handler of RADIO.ADDRESS event) have no effect on the frame received by other devices in the
1089      * simulation.
1090      *
1091      * Because of these limitations of the simulation, modification of the transmitted frame buffer
1092      * is performed immediately after the radio ramp-up start. Also, since in simulation no time
1093      * passes while the CPU is executing code and the radio ramp-up is shorter than the time needed
1094      * by the ECB peripheral to encrypt the longest possible 802.15.4 frame, the ECB is artificially
1095      * sped up to guarantee that encryption completes before the transmission starts.
1096      */
1097     nrf_802154_bsim_utils_core_hooks_adjustments_t adjustments;
1098 
1099     adjustments.tx_started.time_to_radio_address_us =
1100         nrf_802154_rsch_delayed_timeslot_time_to_hw_trigger_get();
1101 
1102     if (cca)
1103     {
1104         // Assume that the first CCA succeeds
1105         adjustments.tx_started.time_to_radio_address_us +=
1106             RX_RAMP_UP_TIME + CCA_TIME + RX_TX_TURNAROUND_TIME;
1107     }
1108     else
1109     {
1110         adjustments.tx_started.time_to_radio_address_us += TX_RAMP_UP_TIME;
1111     }
1112 
1113     adjustments.tx_started.time_to_radio_address_us += PHY_US_TIME_FROM_SYMBOLS(PHY_SHR_SYMBOLS);
1114 
1115     nrf_802154_bsim_utils_core_hooks_adjustments_set(&adjustments);
1116 
1117     m_flags.tx_started_notify = nrf_802154_core_hooks_tx_started(mp_tx_data);
1118 
1119     nrf_802154_bsim_utils_core_hooks_adjustments_t zeroes = {0};
1120 
1121     nrf_802154_bsim_utils_core_hooks_adjustments_set(&zeroes);
1122 #endif
1123 
1124     if (rampup_trigg_mode == TRX_RAMP_UP_HW_TRIGGER)
1125     {
1126         uint32_t ppi_ch = nrf_802154_trx_ramp_up_ppi_channel_get();
1127 
1128         if (!nrf_802154_rsch_delayed_timeslot_ppi_update(ppi_ch))
1129         {
1130             /**
1131              * The trigger has occurred. This has happened too early so there is a high risk
1132              * that the radio will not ramp up. It is necessary to abort the operation.
1133              */
1134             nrf_802154_trx_abort();
1135             return false;
1136         }
1137     }
1138 
1139     return true;
1140 }
1141 
1142 /** Initialize ED operation */
ed_init(void)1143 static void ed_init(void)
1144 {
1145     if (!timeslot_is_granted())
1146     {
1147         return;
1148     }
1149 
1150     if (!are_preconditions_met())
1151     {
1152         return;
1153     }
1154 
1155     uint32_t trx_ed_count = 0U;
1156 
1157     // Notify antenna diversity about energy detection request. Antenna diversity state
1158     // will be updated, and m_ed_time_left reduced accordingly.
1159     nrf_802154_sl_ant_div_energy_detection_requested_notify(&m_ed_time_left);
1160 
1161     if (!ed_iter_setup(&m_ed_time_left, &trx_ed_count))
1162     {
1163         // Just wait for next timeslot if there is not enough time in this one.
1164         return;
1165     }
1166 
1167     nrf_802154_trx_energy_detection(trx_ed_count);
1168 }
1169 
1170 /** Initialize CCA operation. */
cca_init(void)1171 static void cca_init(void)
1172 {
1173     if (!timeslot_is_granted() || !nrf_802154_rsch_timeslot_request(nrf_802154_cca_duration_get()))
1174     {
1175         return;
1176     }
1177 
1178     if (!are_preconditions_met())
1179     {
1180         return;
1181     }
1182 
1183     nrf_802154_trx_standalone_cca();
1184 }
1185 
1186 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
1187 
1188 /** Initialize Continuous Carrier operation. */
continuous_carrier_init(void)1189 static void continuous_carrier_init(void)
1190 {
1191     if (!timeslot_is_granted())
1192     {
1193         return;
1194     }
1195 
1196     if (!are_preconditions_met())
1197     {
1198         return;
1199     }
1200     nrf_802154_fal_tx_power_split_t split_power = {0};
1201 
1202     (void)nrf_802154_tx_power_split_pib_power_get(&split_power);
1203 
1204     nrf_802154_trx_continuous_carrier(&split_power);
1205 }
1206 
1207 /** Initialize Modulated Carrier operation. */
modulated_carrier_init(const uint8_t * p_data)1208 static void modulated_carrier_init(const uint8_t * p_data)
1209 {
1210     if (!timeslot_is_granted())
1211     {
1212         return;
1213     }
1214 
1215     if (!are_preconditions_met())
1216     {
1217         return;
1218     }
1219 
1220     nrf_802154_fal_tx_power_split_t split_power = {0};
1221 
1222     (void)nrf_802154_tx_power_split_pib_power_get(&split_power);
1223 
1224     nrf_802154_trx_modulated_carrier(p_data, &split_power);
1225 }
1226 
1227 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
1228 
1229 /** Switches to idle state: rx or sleep depending on RxOnWhenIdle mode */
switch_to_idle(void)1230 static void switch_to_idle(void)
1231 {
1232     if (!nrf_802154_pib_rx_on_when_idle_get())
1233     {
1234         state_set(RADIO_STATE_SLEEP);
1235     }
1236     else
1237     {
1238         state_set(RADIO_STATE_RX);
1239         rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
1240     }
1241 }
1242 
1243 /***************************************************************************************************
1244  * @section Radio Scheduler notification handlers
1245  **************************************************************************************************/
on_timeslot_ended(void)1246 static void on_timeslot_ended(void)
1247 {
1248     bool result;
1249 
1250     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1251 
1252     if (timeslot_is_granted())
1253     {
1254         m_rsch_timeslot_is_granted = false;
1255 
1256         bool receiving_psdu_now = false;
1257 
1258         if (m_state == RADIO_STATE_RX)
1259         {
1260             receiving_psdu_now = nrf_802154_trx_psdu_is_being_received();
1261         }
1262 
1263         nrf_802154_trx_disable();
1264 
1265         nrf_802154_timer_coord_stop();
1266 
1267 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
1268         /**
1269          * In simulation no time passes while the CPU is executing code and the radio ramp-up is
1270          * shorter than the time needed by the ECB peripheral to encrypt the longest possible
1271          * 802.15.4 frame. The ECB is artificially sped up to guarantee that encryption completes
1272          * before transmission starts. Reset its settings to not confuse other users of this
1273          * peripheral outside of 802.15.4 timeslot.
1274          */
1275         nrf_aes_ecb_cheat_reset_t_ecb();
1276 #endif
1277 
1278         nrf_802154_rsch_continuous_ended();
1279 
1280         result = nrf_802154_core_hooks_terminate(NRF_802154_TERM_802154, REQ_ORIG_RSCH);
1281         NRF_802154_ASSERT(result);
1282         (void)result;
1283 
1284         switch (m_state)
1285         {
1286             case RADIO_STATE_FALLING_ASLEEP:
1287                 state_set(RADIO_STATE_SLEEP);
1288                 break;
1289 
1290             case RADIO_STATE_RX:
1291                 if (receiving_psdu_now)
1292                 {
1293                     receive_failed_notify(NRF_802154_RX_ERROR_TIMESLOT_ENDED);
1294                 }
1295 
1296                 break;
1297 
1298             case RADIO_STATE_TX_ACK:
1299                 state_set(RADIO_STATE_RX);
1300                 mp_current_rx_buffer->free = false;
1301                 nrf_802154_core_hooks_tx_ack_failed(mp_ack, NRF_802154_TX_ERROR_TIMESLOT_ENDED);
1302                 received_frame_notify_and_nesting_allow(mp_current_rx_buffer->data);
1303                 break;
1304 
1305             case RADIO_STATE_CCA_TX:
1306             case RADIO_STATE_TX:
1307             {
1308                 state_set(RADIO_STATE_RX);
1309                 nrf_802154_transmit_done_metadata_t metadata = {};
1310 
1311                 nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
1312                 transmit_failed_notify_and_nesting_allow(NRF_802154_TX_ERROR_TIMESLOT_ENDED,
1313                                                          &metadata);
1314             }
1315             break;
1316 
1317             case RADIO_STATE_RX_ACK:
1318             {
1319                 state_set(RADIO_STATE_RX);
1320                 nrf_802154_transmit_done_metadata_t metadata = {};
1321 
1322                 nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
1323                 transmit_failed_notify_and_nesting_allow(NRF_802154_TX_ERROR_NO_ACK,
1324                                                          &metadata);
1325             }
1326             break;
1327 
1328             case RADIO_STATE_ED:
1329             case RADIO_STATE_CCA:
1330 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
1331             case RADIO_STATE_CONTINUOUS_CARRIER:
1332             case RADIO_STATE_MODULATED_CARRIER:
1333 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
1334             case RADIO_STATE_SLEEP:
1335                 // Intentionally empty.
1336                 break;
1337 
1338             default:
1339                 NRF_802154_ASSERT(false);
1340         }
1341     }
1342 
1343     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1344 }
1345 
on_preconditions_denied(radio_state_t state)1346 static void on_preconditions_denied(radio_state_t state)
1347 {
1348     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1349 
1350     bool result;
1351 
1352     result = nrf_802154_core_hooks_terminate(NRF_802154_TERM_802154, REQ_ORIG_RSCH);
1353     NRF_802154_ASSERT(result);
1354     (void)result;
1355 
1356     bool receiving_psdu_now = false;
1357 
1358     if (state == RADIO_STATE_RX)
1359     {
1360         receiving_psdu_now = nrf_802154_trx_psdu_is_being_received();
1361     }
1362 
1363     nrf_802154_trx_abort();
1364 
1365     switch (state)
1366     {
1367         case RADIO_STATE_FALLING_ASLEEP:
1368             // There should be on_timeslot_ended event
1369             break;
1370 
1371         case RADIO_STATE_RX:
1372             if (receiving_psdu_now)
1373             {
1374                 receive_failed_notify(NRF_802154_RX_ERROR_ABORTED);
1375             }
1376 
1377             break;
1378 
1379         case RADIO_STATE_TX_ACK:
1380             state_set(RADIO_STATE_RX);
1381             break;
1382 
1383         case RADIO_STATE_CCA_TX:
1384             m_flags.tx_diminished_prio = false;
1385         // Fallthrough
1386 
1387         case RADIO_STATE_TX:
1388         case RADIO_STATE_RX_ACK:
1389             state_set(RADIO_STATE_RX);
1390             break;
1391 
1392         case RADIO_STATE_ED:
1393         case RADIO_STATE_CCA:
1394 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
1395         case RADIO_STATE_CONTINUOUS_CARRIER:
1396         case RADIO_STATE_MODULATED_CARRIER:
1397 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
1398         case RADIO_STATE_SLEEP:
1399             // Intentionally empty.
1400             break;
1401 
1402         default:
1403             NRF_802154_ASSERT(false);
1404     }
1405 
1406     operation_terminated_notify(state, receiving_psdu_now);
1407 
1408     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1409 }
1410 
on_preconditions_approved(radio_state_t state)1411 static void on_preconditions_approved(radio_state_t state)
1412 {
1413     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1414 
1415     nrf_802154_trx_abort();
1416 
1417     switch (state)
1418     {
1419         case RADIO_STATE_SLEEP:
1420             // Intentionally empty. Appropriate action will be performed on state change.
1421             break;
1422 
1423         case RADIO_STATE_RX:
1424             rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
1425             break;
1426 
1427         case RADIO_STATE_CCA_TX:
1428             (void)tx_init(mp_tx_data, TRX_RAMP_UP_SW_TRIGGER, true);
1429             break;
1430 
1431         case RADIO_STATE_TX:
1432             (void)tx_init(mp_tx_data, TRX_RAMP_UP_SW_TRIGGER, false);
1433             break;
1434 
1435         case RADIO_STATE_ED:
1436             ed_init();
1437             break;
1438 
1439         case RADIO_STATE_CCA:
1440             cca_init();
1441             break;
1442 
1443 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
1444         case RADIO_STATE_CONTINUOUS_CARRIER:
1445             continuous_carrier_init();
1446             break;
1447 
1448         case RADIO_STATE_MODULATED_CARRIER:
1449             modulated_carrier_init(mp_tx_data);
1450             break;
1451 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
1452 
1453         default:
1454             NRF_802154_ASSERT(false);
1455     }
1456 
1457     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1458 }
1459 
on_timeslot_started(void)1460 static void on_timeslot_started(void)
1461 {
1462     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1463 
1464     nrf_802154_trx_enable();
1465 
1466     m_rsch_timeslot_is_granted = true;
1467 
1468     nrf_802154_timer_coord_start();
1469 
1470 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
1471     /**
1472      * In simulation no time passes while the CPU is executing code and the radio ramp-up is shorter
1473      * than the time needed by the ECB peripheral to encrypt the longest possible 802.15.4 frame.
1474      * Speed up the ECB to guarantee that encryption completes before transmission starts.
1475      */
1476     nrf_aes_ecb_cheat_set_t_ecb(1);
1477 #endif
1478 
1479     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1480 }
1481 
preconditions_approved_should_be_ignored(rsch_prio_t previously_approved_prio,rsch_prio_t currently_approved_prio)1482 static bool preconditions_approved_should_be_ignored(rsch_prio_t previously_approved_prio,
1483                                                      rsch_prio_t currently_approved_prio)
1484 {
1485     // Approved preconditions should only be ignored only all the following conditions are met:
1486     // * all preconditions apart from Coex had already been approved;
1487     // * the call is a result of Coex becoming approved at the highest priority;
1488     // * currently performed operation is transmission with CCA;
1489     // * Coex for transmission is requested after CCA reports idle channel
1490     bool only_coex_was_unapproved       = (previously_approved_prio == RSCH_PRIO_RX);
1491     bool all_preconditions_are_approved = (currently_approved_prio == RSCH_PRIO_MAX);
1492     bool current_state_is_cca_tx        = (m_state == RADIO_STATE_CCA_TX);
1493     bool coex_tx_request_mode_allows    = (m_coex_tx_request_mode ==
1494                                            NRF_802154_COEX_TX_REQUEST_MODE_CCA_DONE);
1495 
1496     return (only_coex_was_unapproved &&
1497             all_preconditions_are_approved &&
1498             current_state_is_cca_tx &&
1499             coex_tx_request_mode_allows);
1500 }
1501 
nrf_802154_rsch_crit_sect_prio_changed(rsch_prio_t prio)1502 void nrf_802154_rsch_crit_sect_prio_changed(rsch_prio_t prio)
1503 {
1504     rsch_prio_t old_prio = m_rsch_priority;
1505 
1506     m_rsch_priority = prio;
1507 
1508     if ((old_prio == RSCH_PRIO_IDLE) && (prio != RSCH_PRIO_IDLE))
1509     {
1510         // We have just got a timeslot.
1511         on_timeslot_started();
1512     }
1513     else if ((old_prio != RSCH_PRIO_IDLE) && (prio == RSCH_PRIO_IDLE))
1514     {
1515         // We are giving back timeslot.
1516         on_timeslot_ended();
1517         return;
1518     }
1519     else if (prio == RSCH_PRIO_IDLE)
1520     {
1521         // It might happen that even though IDLE has already been notified, this function is called
1522         // again as a result of preemptions caused by unexpected timeslot change (e.g. the application
1523         // requested transition to sleep while out of timeslot and RAAL notified timeslot start
1524         // in the middle of that sleep request). The following block makes RAAL finish its processing.
1525         nrf_802154_rsch_continuous_ended();
1526     }
1527     else
1528     {
1529         // Intentionally empty
1530     }
1531 
1532     int_fast8_t transition = action_needed(old_prio, prio, m_state);
1533 
1534     if (transition == 0)
1535     {
1536         return;
1537     }
1538     else if (transition < 0)
1539     {
1540         on_preconditions_denied(m_state);
1541 
1542         // After denying preconditions, TRX is disabled. However, it is possible that the existing
1543         // preconditions are enough for the new state (entered due to denied preconditions) and TRX
1544         // could be enabled for the new state. If this is the case, on_preconditions_approved() is
1545         // called to fully switch to the new state.
1546         radio_state_t new_state = m_state;
1547 
1548         if (is_state_allowed_for_prio(prio, new_state))
1549         {
1550             on_preconditions_approved(new_state);
1551         }
1552     }
1553     else
1554     {
1555         if (!preconditions_approved_should_be_ignored(old_prio, prio))
1556         {
1557             on_preconditions_approved(m_state);
1558         }
1559     }
1560 }
1561 
1562 /***************************************************************************************************
1563  * @section RADIO interrupt handler
1564  **************************************************************************************************/
1565 
nrf_802154_trx_receive_ack_started(void)1566 void nrf_802154_trx_receive_ack_started(void)
1567 {
1568     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1569 
1570     NRF_802154_ASSERT(m_state == RADIO_STATE_RX_ACK);
1571     nrf_802154_core_hooks_rx_ack_started();
1572 
1573     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1574 }
1575 
on_rx_prestarted_timeout(nrf_802154_sl_timer_t * p_timer)1576 static void on_rx_prestarted_timeout(nrf_802154_sl_timer_t * p_timer)
1577 {
1578     (void)p_timer;
1579 
1580     /* If we were in critical section this handler would not be called.
1581      * If we were outside of critical section this handler could be called,
1582      * and nrf_802154_critical_section_enter must succeed.
1583      * Justification:
1584      * - If higher priority interrupt preempts this handler before it takes critical section, that
1585      * interrupt may enter/exit critical section, but when it returns to this handler
1586      * entering critical section will succeed.
1587      * - If we entered critical section here the higher priority interrupt from radio
1588      * will not occur.
1589      * - The only related interrupt that can preempt this handler while it owns critical section
1590      * is from raal timeslot margin, which will fail to enter critical section and schedule
1591      * priority change to be called by nrf_802154_critical_section_exit.
1592      *
1593      * Critical section is entered forcefully here nonetheless, due to a rare issue with
1594      * nrf_802154_critical_section_exit being preempted before the nested critical section counter
1595      * could be decremented. Allowing for critical section nesting here resolves the problem.
1596      * TODO: After the bug is fixed, change to nrf_802154_critical_section_enter and check if
1597      * critical section was successfully entered.
1598      */
1599 
1600     nrf_802154_critical_section_forcefully_enter();
1601 
1602     nrf_802154_sl_ant_div_rx_preamble_timeout_notify();
1603 
1604     do
1605     {
1606         /**
1607          * Multiple, rapidly consecutive reception start events without later moving to the next
1608          * step are possible. There is a special handling for this case here.
1609          */
1610         if (m_rx_prestarted_trig_count > 1)
1611         {
1612             uint64_t now = nrf_802154_sl_timer_current_time_get();
1613 
1614             /**
1615              * If the value of trigger_time field is a moment in the future, it means that timer
1616              * handling has been preempted by HELPER1 radio event after removing the timer from
1617              * scheduler, but before handling this callback. In that case, process the timeout
1618              * as usual, but notify  antenna diversity module that another preamble was detected
1619              * in order to repeat RSSI measurements.
1620              */
1621             if (nrf_802154_sl_time64_is_in_future(now, m_rx_prestarted_timer.trigger_time))
1622             {
1623                 m_rx_prestarted_trig_count = 1;
1624                 nrf_802154_sl_ant_div_rx_preamble_detected_notify();
1625                 break;
1626             }
1627         }
1628 
1629         m_rx_prestarted_trig_count = 0;
1630     }
1631     while (0);
1632 
1633     /* If nrf_802154_trx_receive_frame_prestarted boosted preconditions beyond those normally
1634      * required by current state, they need to be restored now.
1635      */
1636     if (nrf_802154_pib_coex_rx_request_mode_get() ==
1637         NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION)
1638     {
1639         request_preconditions_for_state(m_state);
1640     }
1641     nrf_802154_critical_section_exit();
1642 }
1643 
nrf_802154_trx_receive_frame_prestarted(void)1644 void nrf_802154_trx_receive_frame_prestarted(void)
1645 {
1646     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1647 
1648     if (!antenna_diversity_is_enabled())
1649     {
1650         // Only assert if notifications mask would not allow for calling this function.
1651         NRF_802154_ASSERT((m_trx_receive_frame_notifications_mask &
1652                            TRX_RECEIVE_NOTIFICATION_PRESTARTED) !=
1653                           0U);
1654     }
1655     else
1656     {
1657         // Antenna diversity uses this function for detecting possible preamble on air.
1658     }
1659 
1660     NRF_802154_ASSERT(m_state == RADIO_STATE_RX);
1661 
1662 #if (NRF_802154_STATS_COUNT_ENERGY_DETECTED_EVENTS)
1663     nrf_802154_stat_counter_increment(received_energy_events);
1664 #endif
1665 
1666     nrf_802154_sl_ant_div_rx_preamble_detected_notify();
1667 
1668     // Antenna diversity module should be notified if framestart doesn't come.
1669     bool rx_timeout_should_be_started = antenna_diversity_is_enabled();
1670 
1671     if (nrf_802154_pib_coex_rx_request_mode_get() ==
1672         NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION)
1673     {
1674         // Request boosted preconditions for receive
1675         nrf_802154_rsch_crit_sect_prio_request(RSCH_PRIO_RX);
1676         // Boosted preconditions should be reverted if the framestart doesn't come.
1677         rx_timeout_should_be_started = true;
1678     }
1679 
1680     /*
1681      * This handler might not be followed by nrf_802154_trx_receive_frame_started. The timer
1682      * below is used for timing out if the framestart doesn't come.
1683      * There are two reasons for that: reverting boosted preconditions and notifying antenna diversity
1684      * module.
1685      */
1686     if (rx_timeout_should_be_started)
1687     {
1688 
1689         uint64_t now = nrf_802154_sl_timer_current_time_get();
1690 
1691         (void)nrf_802154_sl_timer_remove(&m_rx_prestarted_timer);
1692 
1693         m_rx_prestarted_timer.trigger_time             = now + PRESTARTED_TIMER_TIMEOUT_US;
1694         m_rx_prestarted_timer.action_type              = NRF_802154_SL_TIMER_ACTION_TYPE_CALLBACK;
1695         m_rx_prestarted_timer.action.callback.callback = on_rx_prestarted_timeout;
1696 
1697         nrf_802154_sl_timer_ret_t ret;
1698 
1699         ret = nrf_802154_sl_timer_add(&m_rx_prestarted_timer);
1700         NRF_802154_ASSERT(ret == NRF_802154_SL_TIMER_RET_SUCCESS);
1701         (void)ret;
1702 
1703         m_rx_prestarted_trig_count += 1;
1704     }
1705 
1706     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1707 }
1708 
nrf_802154_trx_receive_frame_started(void)1709 void nrf_802154_trx_receive_frame_started(void)
1710 {
1711     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1712 
1713     NRF_802154_ASSERT(m_state == RADIO_STATE_RX);
1714     NRF_802154_ASSERT(
1715         (m_trx_receive_frame_notifications_mask & TRX_RECEIVE_NOTIFICATION_STARTED) != 0U);
1716 
1717 #if (NRF_802154_STATS_COUNT_RECEIVED_PREAMBLES)
1718     nrf_802154_stat_counter_increment(received_preambles);
1719 #endif
1720 
1721     switch (nrf_802154_pib_coex_rx_request_mode_get())
1722     {
1723         case NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION:
1724             m_rx_prestarted_trig_count = 0;
1725             (void)nrf_802154_sl_timer_remove(&m_rx_prestarted_timer);
1726         /* Fallthrough */
1727 
1728         case NRF_802154_COEX_RX_REQUEST_MODE_PREAMBLE:
1729             /* Request boosted preconditions */
1730             nrf_802154_rsch_crit_sect_prio_request(RSCH_PRIO_RX);
1731             break;
1732 
1733         default:
1734             break;
1735     }
1736 
1737     if (antenna_diversity_is_enabled())
1738     {
1739         // If antenna diversity is enabled, rx_prestarted_timer would be started even
1740         // in different coex rx request modes than NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION
1741         m_rx_prestarted_trig_count = 0;
1742         (void)nrf_802154_sl_timer_remove(&m_rx_prestarted_timer);
1743         nrf_802154_sl_ant_div_rx_frame_started_notify();
1744     }
1745 
1746     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1747 }
1748 
nrf_802154_trx_receive_frame_bcmatched(uint8_t bcc)1749 uint8_t nrf_802154_trx_receive_frame_bcmatched(uint8_t bcc)
1750 {
1751     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1752 
1753     uint8_t                         next_bcc;
1754     nrf_802154_filter_mode_t        filter_mode;
1755     bool                            parse_result;
1756     bool                            should_filter = false;
1757     nrf_802154_rx_error_t           filter_result = NRF_802154_RX_ERROR_NONE;
1758     nrf_802154_frame_parser_level_t parse_level   = PARSE_LEVEL_NONE;
1759     nrf_802154_frame_parser_level_t prev_level    =
1760         nrf_802154_frame_parser_parse_level_get(&m_current_rx_frame_data);
1761 
1762     NRF_802154_ASSERT(m_state == RADIO_STATE_RX);
1763 
1764     switch (prev_level)
1765     {
1766         case PARSE_LEVEL_NONE:
1767             parse_level   = PARSE_LEVEL_FCF_OFFSETS;
1768             filter_mode   = NRF_802154_FILTER_MODE_FCF;
1769             should_filter = true;
1770             break;
1771 
1772         case PARSE_LEVEL_FCF_OFFSETS:
1773             parse_level   = PARSE_LEVEL_DST_ADDRESSING_END;
1774             filter_mode   = NRF_802154_FILTER_MODE_DST_ADDR;
1775             should_filter = true;
1776             break;
1777 
1778         case PARSE_LEVEL_DST_ADDRESSING_END:
1779             parse_level = PARSE_LEVEL_SEC_CTRL_OFFSETS;
1780             break;
1781 
1782         case PARSE_LEVEL_SEC_CTRL_OFFSETS:
1783             parse_level = PARSE_LEVEL_AUX_SEC_HDR_END;
1784             break;
1785 
1786         default:
1787             /* Parsing completed. Nothing more to be done. */
1788             nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1789             return 0;
1790     }
1791 
1792     if (nrf_802154_frame_parser_frame_type_get(&m_current_rx_frame_data) == FRAME_TYPE_MULTIPURPOSE)
1793     {
1794         m_flags.frame_filtered = true;
1795         return 0;
1796     }
1797 
1798     parse_result = nrf_802154_frame_parser_valid_data_extend(&m_current_rx_frame_data,
1799                                                              bcc,
1800                                                              parse_level);
1801 
1802     if (!parse_result)
1803     {
1804         should_filter = false;
1805         filter_result = NRF_802154_RX_ERROR_INVALID_FRAME;
1806     }
1807 
1808     if (should_filter)
1809     {
1810         filter_result = nrf_802154_filter_frame_part(&m_current_rx_frame_data, filter_mode);
1811 
1812         if ((filter_result == NRF_802154_RX_ERROR_NONE) &&
1813             (filter_mode == NRF_802154_FILTER_MODE_DST_ADDR))
1814         {
1815             m_flags.frame_filtered = true;
1816 
1817             nrf_802154_rsch_crit_sect_prio_request(RSCH_PRIO_RX);
1818             nrf_802154_ack_generator_reset();
1819         }
1820     }
1821 
1822     if (nrf_802154_pib_promiscuous_get())
1823     {
1824         /*
1825          * In promiscuous mode all filtering should be ignored unless the frame has
1826          * length 0 or above maximum frame length.
1827          */
1828         uint8_t psdu_length = nrf_802154_frame_parser_frame_length_get(&m_current_rx_frame_data);
1829 
1830         if (psdu_length > 0 && psdu_length <= MAX_PACKET_SIZE)
1831         {
1832             filter_result = NRF_802154_RX_ERROR_NONE;
1833         }
1834     }
1835 
1836     if (filter_result != NRF_802154_RX_ERROR_NONE)
1837     {
1838         nrf_802154_trx_abort();
1839         rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
1840 
1841         /* Release boosted preconditions */
1842         request_preconditions_for_state(m_state);
1843 
1844         if (nrf_802154_frame_parser_frame_type_get(&m_current_rx_frame_data) != FRAME_TYPE_ACK)
1845         {
1846             receive_failed_notify(filter_result);
1847         }
1848 
1849         nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1850         return 0;
1851     }
1852 
1853     switch (parse_level)
1854     {
1855         case PARSE_LEVEL_FCF_OFFSETS:
1856             next_bcc = PHR_SIZE + nrf_802154_frame_parser_dst_addressing_end_offset_get(
1857                 &m_current_rx_frame_data);
1858             break;
1859 
1860         case PARSE_LEVEL_DST_ADDRESSING_END:
1861             next_bcc = PHR_SIZE + nrf_802154_frame_parser_addressing_end_offset_get(
1862                 &m_current_rx_frame_data) + SECURITY_CONTROL_SIZE;
1863             break;
1864 
1865         case PARSE_LEVEL_SEC_CTRL_OFFSETS:
1866             next_bcc = PHR_SIZE + nrf_802154_frame_parser_aux_sec_hdr_end_offset_get(
1867                 &m_current_rx_frame_data);
1868             break;
1869 
1870         default:
1871             next_bcc = 0;
1872             break;
1873     }
1874 
1875     if (!m_flags.rx_timeslot_requested)
1876     {
1877         uint16_t duration = nrf_802154_rx_duration_get(
1878             mp_current_rx_buffer->data[0],
1879             nrf_802154_frame_parser_ar_bit_is_set(&m_current_rx_frame_data));
1880 
1881         if (nrf_802154_rsch_timeslot_request(duration))
1882         {
1883             m_flags.rx_timeslot_requested = true;
1884 
1885             receive_started_notify();
1886         }
1887         else
1888         {
1889             // Disable receiver and wait for a new timeslot.
1890             nrf_802154_trx_abort();
1891 
1892             // We should not leave trx in temporary state, let's receive then.
1893             // We avoid hard reset of radio during TX ACK phase due to timeslot end,
1894             // which could result in spurious RF emission.
1895             rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
1896 
1897             // Don't care about the result - if the notification cannot be performed
1898             // no impact on the device's operation is expected
1899             (void)nrf_802154_notify_receive_failed(NRF_802154_RX_ERROR_TIMESLOT_ENDED,
1900                                                    m_rx_window_id,
1901                                                    true);
1902         }
1903     }
1904 
1905     if (m_flags.frame_filtered &&
1906         nrf_802154_frame_parser_ar_bit_is_set(&m_current_rx_frame_data) &&
1907         nrf_802154_pib_auto_ack_get())
1908     {
1909         mp_ack = nrf_802154_ack_generator_create(&m_current_rx_frame_data);
1910     }
1911 
1912     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1913 
1914     return next_bcc;
1915 }
1916 
nrf_802154_trx_go_idle_finished(void)1917 void nrf_802154_trx_go_idle_finished(void)
1918 {
1919     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1920 
1921     state_set(RADIO_STATE_SLEEP);
1922 
1923     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1924 }
1925 
1926 static void on_bad_ack(void);
1927 
nrf_802154_trx_receive_frame_crcerror(void)1928 void nrf_802154_trx_receive_frame_crcerror(void)
1929 {
1930     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1931 
1932     NRF_802154_ASSERT(m_state == RADIO_STATE_RX);
1933     rx_flags_clear();
1934     rx_data_clear();
1935 
1936     // We don't change receive buffer, receive will go to the same that was already used
1937     request_preconditions_for_state(m_state);
1938 
1939     nrf_802154_fal_tx_power_split_t split_power = {0};
1940 
1941     (void)nrf_802154_tx_power_split_pib_power_get(&split_power);
1942 
1943     nrf_802154_trx_receive_frame(BCC_INIT / 8U,
1944                                  TRX_RAMP_UP_SW_TRIGGER,
1945                                  m_trx_receive_frame_notifications_mask,
1946                                  &split_power);
1947 
1948 #if NRF_802154_NOTIFY_CRCERROR
1949     receive_failed_notify(NRF_802154_RX_ERROR_INVALID_FCS);
1950 #endif // NRF_802154_NOTIFY_CRCERROR
1951 
1952     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1953 }
1954 
nrf_802154_trx_receive_ack_crcerror(void)1955 void nrf_802154_trx_receive_ack_crcerror(void)
1956 {
1957     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1958 
1959     NRF_802154_ASSERT(m_state == RADIO_STATE_RX_ACK);
1960 
1961     on_bad_ack();
1962 
1963     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
1964 }
1965 
nrf_802154_trx_receive_frame_received(void)1966 void nrf_802154_trx_receive_frame_received(void)
1967 {
1968     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
1969 
1970     uint8_t             * p_received_data = mp_current_rx_buffer->data;
1971     nrf_802154_rx_error_t filter_result   = NRF_802154_RX_ERROR_RUNTIME;
1972 
1973     // Latch RSSI and LQI values before sending ACK
1974     m_last_rssi = rssi_last_measurement_get();
1975     m_last_lqi  = lqi_get(p_received_data);
1976 
1977     bool parse_result = nrf_802154_frame_parser_valid_data_extend(
1978         &m_current_rx_frame_data,
1979         PHR_SIZE + nrf_802154_frame_parser_frame_length_get(&m_current_rx_frame_data),
1980         PARSE_LEVEL_FULL);
1981 
1982     if (parse_result && !m_flags.frame_filtered)
1983     {
1984         filter_result = nrf_802154_filter_frame_part(&m_current_rx_frame_data,
1985                                                      NRF_802154_FILTER_MODE_ALL);
1986 
1987         if (filter_result == NRF_802154_RX_ERROR_NONE)
1988         {
1989             uint16_t duration = nrf_802154_ack_duration_with_turnaround_get();
1990 
1991             if (nrf_802154_rsch_timeslot_request(duration))
1992             {
1993                 m_flags.frame_filtered        = true;
1994                 m_flags.rx_timeslot_requested = true;
1995 
1996                 nrf_802154_ack_generator_reset();
1997                 receive_started_notify();
1998             }
1999             else
2000             {
2001                 filter_result = NRF_802154_RX_ERROR_TIMESLOT_ENDED;
2002             }
2003         }
2004     }
2005 
2006     if (m_flags.frame_filtered || nrf_802154_pib_promiscuous_get())
2007     {
2008         nrf_802154_stat_counter_increment(received_frames);
2009 
2010 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
2011         uint64_t ts = timer_coord_timestamp_get();
2012 
2013         nrf_802154_stat_timestamp_write(last_rx_end_timestamp, ts);
2014 #endif
2015 
2016         nrf_802154_sl_ant_div_rx_frame_received_notify();
2017 
2018         bool send_ack = false;
2019 
2020         if (m_flags.frame_filtered &&
2021             parse_result &&
2022             nrf_802154_frame_parser_ar_bit_is_set(&m_current_rx_frame_data) &&
2023             nrf_802154_pib_auto_ack_get())
2024         {
2025             nrf_802154_tx_work_buffer_reset(&m_default_frame_props);
2026             mp_ack   = nrf_802154_ack_generator_create(&m_current_rx_frame_data);
2027             send_ack = (mp_ack != NULL);
2028         }
2029 
2030         if (send_ack)
2031         {
2032             state_set(RADIO_STATE_TX_ACK);
2033 
2034             if (is_state_allowed_for_prio(m_rsch_priority, RADIO_STATE_TX_ACK))
2035             {
2036                 if (nrf_802154_trx_transmit_ack(nrf_802154_tx_work_buffer_get(mp_ack), ACK_IFS))
2037                 {
2038                     // Intentionally empty: transmitting ack, because we can
2039 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
2040                     /**
2041                      * In simulation the frame contents are latched when the first bit of the
2042                      * preamble is "transmitted" by the simulated radio. Any modifications performed
2043                      * after that (for example in handler of RADIO.ADDRESS event) have no effect on
2044                      * the frame received by other devices in the simulation.
2045                      *
2046                      * Because of these limitations of the simulation, modification of the transmitted
2047                      * frame buffer is performed immediately after the radio ramp-up start. Also,
2048                      * since in simulation no time passes while the CPU is executing code and the
2049                      * radio ramp-up is shorter than the time needed by the ECB peripheral to encrypt
2050                      * the longest possible 802.15.4 frame, the ECB is artificially sped up to
2051                      * guarantee that encryption completes before the transmission starts.
2052                      */
2053                     nrf_802154_bsim_utils_core_hooks_adjustments_t adjustments;
2054 
2055                     adjustments.tx_ack_started.time_to_radio_address_us =
2056                         ACK_IFS + TX_RAMP_UP_TIME + PHY_US_TIME_FROM_SYMBOLS(PHY_SHR_SYMBOLS);
2057 
2058                     nrf_802154_bsim_utils_core_hooks_adjustments_set(&adjustments);
2059 
2060                     nrf_802154_core_hooks_tx_ack_started(mp_ack);
2061 
2062                     nrf_802154_bsim_utils_core_hooks_adjustments_t zeroes = {0};
2063 
2064                     nrf_802154_bsim_utils_core_hooks_adjustments_set(&zeroes);
2065 #endif /* defined(CONFIG_SOC_SERIES_BSIM_NRFXX) */
2066                 }
2067                 else
2068                 {
2069                     mp_current_rx_buffer->free = false;
2070 
2071                     switch_to_idle();
2072 
2073                     received_frame_notify_and_nesting_allow(p_received_data);
2074                 }
2075             }
2076             else
2077             {
2078                 if (!nrf_802154_rsch_prec_is_approved(RSCH_PREC_COEX,
2079                                                       min_required_rsch_prio(RADIO_STATE_TX_ACK)))
2080                 {
2081                     nrf_802154_stat_counter_increment(coex_denied_requests);
2082                 }
2083 
2084                 mp_current_rx_buffer->free = false;
2085 
2086                 switch_to_idle();
2087 
2088                 received_frame_notify_and_nesting_allow(p_received_data);
2089             }
2090         }
2091         else
2092         {
2093             request_preconditions_for_state(m_state);
2094             // Filter out received ACK frame if promiscuous mode is disabled.
2095             if (((p_received_data[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK) != FRAME_TYPE_ACK) ||
2096                 nrf_802154_pib_promiscuous_get())
2097             {
2098                 // Current buffer will be passed to the application
2099                 mp_current_rx_buffer->free = false;
2100 
2101                 switch_to_idle();
2102 
2103                 received_frame_notify_and_nesting_allow(p_received_data);
2104             }
2105             else
2106             {
2107                 // Receive to the same buffer
2108                 rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
2109             }
2110         }
2111     }
2112     else
2113     {
2114         // CRC is OK, but filtering operation did not end - it is invalid frame with valid CRC
2115         // or problem due to software latency (i.e. handled BCMATCH, CRCERROR, CRCOK from two
2116         // consecutively received frames).
2117         request_preconditions_for_state(m_state);
2118         rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
2119 
2120         receive_failed_notify(filter_result);
2121     }
2122 
2123     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2124 }
2125 
fcf_is_security_enabled(const uint8_t * p_frame)2126 static bool fcf_is_security_enabled(const uint8_t * p_frame)
2127 {
2128     return p_frame[SECURITY_ENABLED_OFFSET] & SECURITY_ENABLED_BIT;
2129 }
2130 
tx_started_core_hooks_will_fit_within_timeslot(const uint8_t * p_frame)2131 static inline bool tx_started_core_hooks_will_fit_within_timeslot(const uint8_t * p_frame)
2132 {
2133     if (!fcf_is_security_enabled(p_frame))
2134     {
2135         return true;
2136     }
2137 
2138     uint32_t estimated_max_hook_time = nrf_802154_frame_duration_get(p_frame[0], false, true) / 2U;
2139 
2140     return nrf_802154_rsch_timeslot_us_left_get() >= estimated_max_hook_time;
2141 }
2142 
nrf_802154_trx_transmit_frame_started(void)2143 void nrf_802154_trx_transmit_frame_started(void)
2144 {
2145     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2146 
2147     NRF_802154_ASSERT((m_state == RADIO_STATE_TX) || (m_state == RADIO_STATE_CCA_TX));
2148     if (tx_started_core_hooks_will_fit_within_timeslot(mp_tx_data))
2149     {
2150         transmit_started_notify();
2151     }
2152     else
2153     {
2154         nrf_802154_trx_abort();
2155         switch_to_idle();
2156 
2157         nrf_802154_transmit_done_metadata_t metadata = {};
2158 
2159         nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
2160 
2161         transmit_failed_notify(mp_tx_data, NRF_802154_TX_ERROR_TIMESLOT_ENDED, &metadata);
2162     }
2163 
2164     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2165 }
2166 
nrf_802154_trx_transmit_ack_started(void)2167 void nrf_802154_trx_transmit_ack_started(void)
2168 {
2169     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2170 
2171     NRF_802154_ASSERT(m_state == RADIO_STATE_TX_ACK);
2172     if (tx_started_core_hooks_will_fit_within_timeslot(mp_ack))
2173     {
2174         transmit_ack_started_notify();
2175     }
2176     else
2177     {
2178         uint8_t * p_received_data = mp_current_rx_buffer->data;
2179 
2180         nrf_802154_trx_abort();
2181         mp_current_rx_buffer->free = false;
2182 
2183         nrf_802154_core_hooks_tx_ack_failed(mp_ack, NRF_802154_RX_ERROR_TIMESLOT_ENDED);
2184         switch_to_idle();
2185         received_frame_notify_and_nesting_allow(p_received_data);
2186     }
2187 
2188     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2189 }
2190 
nrf_802154_trx_transmit_ack_transmitted(void)2191 void nrf_802154_trx_transmit_ack_transmitted(void)
2192 {
2193     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2194 
2195     NRF_802154_ASSERT(m_state == RADIO_STATE_TX_ACK);
2196 
2197     uint8_t * p_received_data = mp_current_rx_buffer->data;
2198 
2199     // Current buffer used for receive operation will be passed to the application
2200     mp_current_rx_buffer->free = false;
2201 
2202     switch_to_idle();
2203 
2204     received_frame_notify_and_nesting_allow(p_received_data);
2205 
2206     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2207 }
2208 
nrf_802154_trx_transmit_frame_transmitted(void)2209 void nrf_802154_trx_transmit_frame_transmitted(void)
2210 {
2211     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2212 
2213 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
2214     uint64_t ts = timer_coord_timestamp_get();
2215 
2216     // ts holds now timestamp of the PHYEND event
2217     nrf_802154_stat_timestamp_write(last_tx_end_timestamp, ts);
2218 
2219     if (m_flags.tx_with_cca)
2220     {
2221         m_flags.tx_diminished_prio = false;
2222 
2223         // We calculate the timestamp when ccaidle must happened.
2224         ts -= nrf_802154_frame_duration_get(mp_tx_data[0], true, true) + RX_TX_TURNAROUND_TIME;
2225 
2226         nrf_802154_stat_timestamp_write(last_cca_idle_timestamp, ts);
2227     }
2228 
2229 #endif
2230 
2231     if (ack_is_requested(mp_tx_data))
2232     {
2233         state_set(RADIO_STATE_RX_ACK);
2234 
2235         bool rx_buffer_free = rx_buffer_is_available();
2236 
2237         nrf_802154_trx_receive_buffer_set(rx_buffer_get());
2238 
2239 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
2240         // Configure the timer coordinator to get a timestamp of the CRCOK event.
2241         nrf_802154_timer_coord_timestamp_prepare(nrf_802154_trx_radio_crcok_event_handle_get());
2242 #endif
2243 
2244         nrf_802154_trx_receive_ack();
2245 
2246         rx_init_free_buffer_find_and_update(rx_buffer_free);
2247     }
2248     else
2249     {
2250         switch_to_idle();
2251 
2252         transmitted_frame_notify(NULL, 0, 0);
2253     }
2254 
2255     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2256 }
2257 
ack_match_check_version_not_2(const uint8_t * p_tx_data,const uint8_t * p_ack_data)2258 static bool ack_match_check_version_not_2(const uint8_t * p_tx_data, const uint8_t * p_ack_data)
2259 {
2260     // Frame Version != 2
2261 
2262     // Check: Phy length
2263     if (p_ack_data[PHR_OFFSET] != IMM_ACK_LENGTH)
2264     {
2265         return false;
2266     }
2267 
2268     // Check if Frame version is 0 or 1.
2269     switch (p_ack_data[FRAME_VERSION_OFFSET] & FRAME_VERSION_MASK)
2270     {
2271         case FRAME_VERSION_0:
2272         case FRAME_VERSION_1:
2273             break;
2274 
2275         default:
2276             return false;
2277     }
2278 
2279     // Check: Sequence number match
2280     if (p_ack_data[DSN_OFFSET] != p_tx_data[DSN_OFFSET])
2281     {
2282         return false;
2283     }
2284 
2285     return true;
2286 }
2287 
ack_match_check_version_2(const uint8_t * p_tx_frame,const uint8_t * p_ack_frame)2288 static bool ack_match_check_version_2(const uint8_t * p_tx_frame, const uint8_t * p_ack_frame)
2289 {
2290     nrf_802154_frame_parser_data_t tx_data;
2291     nrf_802154_frame_parser_data_t ack_data;
2292     bool                           parse_result;
2293 
2294     parse_result = nrf_802154_frame_parser_data_init(p_tx_frame,
2295                                                      p_tx_frame[PHR_OFFSET] + PHR_SIZE,
2296                                                      PARSE_LEVEL_ADDRESSING_END,
2297                                                      &tx_data);
2298     if (!parse_result)
2299     {
2300         return false;
2301     }
2302 
2303     parse_result = nrf_802154_frame_parser_data_init(p_ack_frame,
2304                                                      p_ack_frame[PHR_OFFSET] + PHR_SIZE,
2305                                                      PARSE_LEVEL_ADDRESSING_END,
2306                                                      &ack_data);
2307 
2308     if (nrf_802154_frame_parser_frame_version_get(&ack_data) != FRAME_VERSION_2)
2309     {
2310         return false;
2311     }
2312 
2313     // Transmitted frame was Version 2
2314     // For frame version 2 sequence number bit may be suppressed and its check fails.
2315     // Verify ACK frame using its destination address.
2316 
2317     const uint8_t * p_tx_src_addr     = nrf_802154_frame_parser_src_addr_get(&tx_data);
2318     const uint8_t * p_ack_dst_addr    = nrf_802154_frame_parser_dst_addr_get(&ack_data);
2319     uint8_t         tx_src_addr_size  = nrf_802154_frame_parser_src_addr_size_get(&tx_data);
2320     uint8_t         ack_dst_addr_size = nrf_802154_frame_parser_dst_addr_size_get(&ack_data);
2321 
2322     if (!parse_result ||
2323         (p_tx_src_addr == NULL) ||
2324         (p_ack_dst_addr == NULL) ||
2325         (tx_src_addr_size != ack_dst_addr_size) ||
2326         (0 != memcmp(p_tx_src_addr,
2327                      p_ack_dst_addr,
2328                      tx_src_addr_size)))
2329     {
2330         // Mismatch
2331         return false;
2332     }
2333 
2334     return true;
2335 }
2336 
ack_match_check(const uint8_t * p_tx_data,const uint8_t * p_ack_data)2337 static bool ack_match_check(const uint8_t * p_tx_data, const uint8_t * p_ack_data)
2338 {
2339     if ((p_tx_data == NULL) || (p_ack_data == NULL))
2340     {
2341         return false;
2342     }
2343 
2344     // Check: Frame Control Field -> Frame type
2345     if ((p_ack_data[FRAME_TYPE_OFFSET] & FRAME_TYPE_MASK) != FRAME_TYPE_ACK)
2346     {
2347         return false; // This is not an ACK frame
2348     }
2349 
2350     // Check: Frame Control Field -> Frame version
2351     if ((p_tx_data[FRAME_VERSION_OFFSET] & FRAME_VERSION_MASK) == FRAME_VERSION_2)
2352     {
2353         return ack_match_check_version_2(p_tx_data, p_ack_data);
2354     }
2355 
2356     return ack_match_check_version_not_2(p_tx_data, p_ack_data);
2357 }
2358 
on_bad_ack(void)2359 static void on_bad_ack(void)
2360 {
2361     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2362 
2363     // We received either a frame with incorrect CRC or not an ACK frame or not matching ACK
2364     switch_to_idle();
2365 
2366     nrf_802154_transmit_done_metadata_t metadata = {};
2367 
2368     nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
2369     transmit_failed_notify_and_nesting_allow(NRF_802154_TX_ERROR_INVALID_ACK, &metadata);
2370 
2371     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2372 }
2373 
nrf_802154_trx_receive_ack_received(void)2374 void nrf_802154_trx_receive_ack_received(void)
2375 {
2376     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2377 
2378     // CRC of received frame is correct
2379     uint8_t * p_ack_data = mp_current_rx_buffer->data;
2380 
2381     if (ack_match_check(mp_tx_data, p_ack_data))
2382     {
2383 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
2384         uint64_t ts = timer_coord_timestamp_get();
2385 
2386         nrf_802154_stat_timestamp_write(last_ack_end_timestamp, ts);
2387 #endif
2388 
2389         rx_buffer_t * p_ack_buffer = mp_current_rx_buffer;
2390 
2391         mp_current_rx_buffer->free = false;
2392 
2393         // Detect Frame Pending field set to one on Ack frame received after a Data Request Command
2394         bool                           should_receive = false;
2395         nrf_802154_frame_parser_data_t frame_data;
2396 
2397         bool parse_result = nrf_802154_frame_parser_data_init(mp_tx_data,
2398                                                               mp_tx_data[PHR_OFFSET] + PHR_SIZE,
2399                                                               PARSE_LEVEL_FULL,
2400                                                               &frame_data);
2401 
2402         if (parse_result &&
2403             (nrf_802154_frame_parser_frame_type_get(&frame_data) == FRAME_TYPE_COMMAND))
2404         {
2405             const uint8_t * p_cmd = nrf_802154_frame_parser_mac_command_id_get(&frame_data);
2406 
2407             if ((p_cmd != NULL) && (*p_cmd == MAC_CMD_DATA_REQ))
2408             {
2409                 if (p_ack_data[FRAME_PENDING_OFFSET] & FRAME_PENDING_BIT)
2410                 {
2411                     should_receive = true;
2412                 }
2413             }
2414         }
2415 
2416         if (should_receive)
2417         {
2418             state_set(RADIO_STATE_RX);
2419             rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
2420         }
2421         else
2422         {
2423             switch_to_idle();
2424         }
2425 
2426         transmitted_frame_notify(p_ack_buffer->data,           // phr + psdu
2427                                  rssi_last_measurement_get(),  // rssi
2428                                  lqi_get(p_ack_buffer->data)); // lqi;
2429     }
2430     else
2431     {
2432         on_bad_ack();
2433     }
2434 
2435     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2436 }
2437 
nrf_802154_trx_standalone_cca_finished(bool channel_was_idle)2438 void nrf_802154_trx_standalone_cca_finished(bool channel_was_idle)
2439 {
2440     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2441 
2442     switch_to_idle();
2443 
2444     cca_notify(channel_was_idle);
2445 
2446     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2447 }
2448 
nrf_802154_trx_transmit_frame_ccastarted(void)2449 void nrf_802154_trx_transmit_frame_ccastarted(void)
2450 {
2451     // This handler provided by trx is never called because parameter notifications_mask
2452     // of the nrf_802154_trx_transmit_frame does not contain TRX_TRANSMIT_NOTIFICATION_CCASTARTED.
2453     NRF_802154_ASSERT(false);
2454 }
2455 
nrf_802154_trx_transmit_frame_ccaidle(void)2456 void nrf_802154_trx_transmit_frame_ccaidle(void)
2457 {
2458     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2459 
2460     NRF_802154_ASSERT(m_state == RADIO_STATE_CCA_TX);
2461     NRF_802154_ASSERT(m_trx_transmit_frame_notifications_mask & TRX_TRANSMIT_NOTIFICATION_CCAIDLE);
2462 
2463 #if (NRF_802154_FRAME_TIMESTAMP_ENABLED)
2464     uint64_t ts = timer_coord_timestamp_get();
2465 
2466     // Configure the timer coordinator to get a timestamp of the PHYEND event.
2467     nrf_802154_timer_coord_timestamp_prepare(nrf_802154_trx_radio_phyend_event_handle_get());
2468 
2469     // Update stat timestamp of CCASTART event
2470     nrf_802154_stat_timestamp_write(last_cca_start_timestamp, ts);
2471 #endif
2472 
2473     if (m_coex_tx_request_mode == NRF_802154_COEX_TX_REQUEST_MODE_CCA_DONE)
2474     {
2475         nrf_802154_rsch_crit_sect_prio_request(RSCH_PRIO_TX);
2476         m_flags.tx_diminished_prio = false;
2477     }
2478 
2479     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2480 }
2481 
nrf_802154_trx_transmit_frame_ccabusy(void)2482 void nrf_802154_trx_transmit_frame_ccabusy(void)
2483 {
2484     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2485 
2486     nrf_802154_stat_counter_increment(cca_failed_attempts);
2487 
2488     switch_to_idle();
2489 
2490     nrf_802154_transmit_done_metadata_t metadata = {};
2491 
2492     nrf_802154_tx_work_buffer_original_frame_update(mp_tx_data, &metadata.frame_props);
2493     transmit_failed_notify_and_nesting_allow(NRF_802154_TX_ERROR_BUSY_CHANNEL, &metadata);
2494 
2495     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2496 }
2497 
nrf_802154_trx_energy_detection_finished(uint8_t ed_sample)2498 void nrf_802154_trx_energy_detection_finished(uint8_t ed_sample)
2499 {
2500     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2501 
2502     if (m_ed_result < ed_sample)
2503     {
2504         // Collect maximum value of samples provided by trx
2505         m_ed_result = ed_sample;
2506     }
2507 
2508     if (m_ed_time_left >= ED_ITER_DURATION)
2509     {
2510         uint32_t trx_ed_count = 0U;
2511 
2512         if (ed_iter_setup(&m_ed_time_left, &trx_ed_count))
2513         {
2514             nrf_802154_trx_energy_detection(trx_ed_count);
2515         }
2516         else
2517         {
2518             /* There is too little time in current timeslot, just wait for timeslot end.
2519              * Operation will be resumed in next timeslot */
2520         }
2521     }
2522     else if (nrf_802154_sl_ant_div_energy_detection_finished_notify())
2523     {
2524         ed_init();
2525     }
2526     else
2527     {
2528         nrf_802154_trx_channel_set(nrf_802154_pib_channel_get());
2529 
2530         switch_to_idle();
2531 
2532         nrf_802154_energy_detected_t ed_result = {};
2533 
2534         ed_result.ed_dbm = nrf_802154_rssi_ed_sample_to_dbm_convert(m_ed_result);
2535 
2536         energy_detected_notify(&ed_result);
2537     }
2538 
2539     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2540 }
2541 
2542 /***************************************************************************************************
2543  * @section API functions
2544  **************************************************************************************************/
2545 
nrf_802154_core_init(void)2546 void nrf_802154_core_init(void)
2547 {
2548     m_state                    = RADIO_STATE_SLEEP;
2549     m_rsch_timeslot_is_granted = false;
2550     m_rx_prestarted_trig_count = 0;
2551     m_no_rx_buffer_notified    = 0U;
2552 
2553     nrf_802154_sl_timer_init(&m_rx_prestarted_timer);
2554 
2555     nrf_802154_trx_init();
2556     nrf_802154_ack_generator_init();
2557 }
2558 
nrf_802154_core_deinit(void)2559 void nrf_802154_core_deinit(void)
2560 {
2561     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2562 
2563     if (timeslot_is_granted())
2564     {
2565         nrf_802154_trx_disable();
2566     }
2567 
2568     mpsl_fem_cleanup();
2569 
2570     nrf_802154_irq_disable(nrfx_get_irq_number(NRF_RADIO));
2571     nrf_802154_irq_clear_pending(nrfx_get_irq_number(NRF_RADIO));
2572 
2573     nrf_802154_sl_timer_deinit(&m_rx_prestarted_timer);
2574 
2575     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2576 }
2577 
nrf_802154_core_state_get(void)2578 radio_state_t nrf_802154_core_state_get(void)
2579 {
2580     return m_state;
2581 }
2582 
core_sleep(nrf_802154_term_t term_lvl,req_originator_t req_orig,bool notify_abort)2583 static bool core_sleep(nrf_802154_term_t term_lvl, req_originator_t req_orig, bool notify_abort)
2584 {
2585     bool result = current_operation_terminate(term_lvl, req_orig, notify_abort);
2586 
2587     if (result)
2588     {
2589         // The order of calls in the following blocks is inverted to avoid RAAL races.
2590         if (timeslot_is_granted())
2591         {
2592             state_set(RADIO_STATE_FALLING_ASLEEP);
2593             falling_asleep_init();
2594         }
2595         else
2596         {
2597             state_set(RADIO_STATE_SLEEP);
2598         }
2599     }
2600 
2601     return result;
2602 }
2603 
nrf_802154_core_sleep(nrf_802154_term_t term_lvl)2604 bool nrf_802154_core_sleep(nrf_802154_term_t term_lvl)
2605 {
2606     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2607 
2608     bool result = nrf_802154_critical_section_enter();
2609 
2610     if (result)
2611     {
2612         if ((m_state != RADIO_STATE_SLEEP) && (m_state != RADIO_STATE_FALLING_ASLEEP))
2613         {
2614             result = core_sleep(term_lvl, REQ_ORIG_CORE, true);
2615         }
2616 
2617         nrf_802154_critical_section_exit();
2618     }
2619 
2620     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2621 
2622     return result;
2623 }
2624 
core_receive(nrf_802154_term_t term_lvl,req_originator_t req_orig,bool notify_abort,uint32_t id)2625 static bool core_receive(nrf_802154_term_t term_lvl,
2626                          req_originator_t  req_orig,
2627                          bool              notify_abort,
2628                          uint32_t          id)
2629 {
2630     bool result = current_operation_terminate(term_lvl, req_orig, notify_abort);
2631 
2632     if (result)
2633     {
2634         m_trx_receive_frame_notifications_mask =
2635             make_trx_frame_receive_notification_mask();
2636 
2637         m_rx_window_id = id;
2638         state_set(RADIO_STATE_RX);
2639 
2640         bool abort_shall_follow = false;
2641 
2642         rx_init(ramp_up_mode_choose(req_orig), &abort_shall_follow);
2643 
2644         if (abort_shall_follow)
2645         {
2646             nrf_802154_trx_abort();
2647 
2648             // HW triggering failed, fallback is SW trigger.
2649             // (fallback immunizes against the rare case of spurious lptimer firing)
2650             rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
2651         }
2652     }
2653 
2654     return result;
2655 }
2656 
nrf_802154_core_receive(nrf_802154_term_t term_lvl,req_originator_t req_orig,nrf_802154_notification_func_t notify_function,bool notify_abort,uint32_t id)2657 bool nrf_802154_core_receive(nrf_802154_term_t              term_lvl,
2658                              req_originator_t               req_orig,
2659                              nrf_802154_notification_func_t notify_function,
2660                              bool                           notify_abort,
2661                              uint32_t                       id)
2662 {
2663     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2664 
2665     bool result = nrf_802154_critical_section_enter();
2666 
2667     if (result)
2668     {
2669         if ((m_state != RADIO_STATE_RX) && (m_state != RADIO_STATE_TX_ACK))
2670         {
2671             if (critical_section_can_be_processed_now())
2672             {
2673                 result = core_receive(term_lvl, req_orig, notify_abort, id);
2674             }
2675             else
2676             {
2677                 result = false;
2678             }
2679         }
2680 
2681         if (notify_function != NULL)
2682         {
2683             notify_function(result);
2684         }
2685 
2686         nrf_802154_critical_section_exit();
2687     }
2688     else
2689     {
2690         if (notify_function != NULL)
2691         {
2692             notify_function(false);
2693         }
2694     }
2695 
2696     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2697 
2698     return result;
2699 }
2700 
nrf_802154_core_transmit(nrf_802154_term_t term_lvl,req_originator_t req_orig,uint8_t * p_data,nrf_802154_transmit_params_t * p_params,nrf_802154_notification_func_t notify_function)2701 bool nrf_802154_core_transmit(nrf_802154_term_t              term_lvl,
2702                               req_originator_t               req_orig,
2703                               uint8_t                      * p_data,
2704                               nrf_802154_transmit_params_t * p_params,
2705                               nrf_802154_notification_func_t notify_function)
2706 {
2707     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2708 
2709     bool result = critical_section_enter_and_verify_timeslot_length();
2710 
2711     if (result)
2712     {
2713         if (nrf_802154_core_hooks_pre_transmission(p_data, p_params, &transmit_failed_notify))
2714         {
2715             result = current_operation_terminate(term_lvl, req_orig, true);
2716 
2717             if (result)
2718             {
2719                 nrf_802154_tx_work_buffer_reset(&p_params->frame_props);
2720                 result = nrf_802154_core_hooks_tx_setup(p_data, p_params, &transmit_failed_notify);
2721 
2722                 if (!result)
2723                 {
2724                     switch_to_idle();
2725                 }
2726             }
2727 
2728             if (result)
2729             {
2730                 m_coex_tx_request_mode                  = nrf_802154_pib_coex_tx_request_mode_get();
2731                 m_trx_transmit_frame_notifications_mask =
2732                     make_trx_frame_transmit_notification_mask(p_params->cca);
2733                 m_flags.tx_diminished_prio =
2734                     m_coex_tx_request_mode == NRF_802154_COEX_TX_REQUEST_MODE_CCA_DONE;
2735 
2736                 state_set(p_params->cca ? RADIO_STATE_CCA_TX : RADIO_STATE_TX);
2737                 mp_tx_data   = p_data;
2738                 m_tx_power   = p_params->tx_power;
2739                 m_tx_channel = p_params->channel;
2740 
2741                 uint8_t cca_attempts = p_params->cca ? (1 + p_params->extra_cca_attempts) : 0;
2742 
2743                 // coverity[check_return]
2744                 result = tx_init(p_data, ramp_up_mode_choose(req_orig), cca_attempts);
2745 
2746                 if (p_params->immediate)
2747                 {
2748                     if (!result)
2749                     {
2750                         switch_to_idle();
2751                     }
2752                 }
2753                 else
2754                 {
2755                     result = true;
2756                 }
2757             }
2758         }
2759 
2760         if (notify_function != NULL)
2761         {
2762             notify_function(result);
2763         }
2764 
2765         nrf_802154_critical_section_exit();
2766     }
2767     else
2768     {
2769         if (notify_function != NULL)
2770         {
2771             notify_function(false);
2772         }
2773     }
2774 
2775     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2776 
2777     return result;
2778 }
2779 
nrf_802154_core_ack_timeout_handle(const nrf_802154_ack_timeout_handle_params_t * p_param)2780 bool nrf_802154_core_ack_timeout_handle(const nrf_802154_ack_timeout_handle_params_t * p_param)
2781 {
2782     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2783 
2784     bool result = critical_section_enter_and_verify_timeslot_length();
2785 
2786     if (result)
2787     {
2788         if ((m_state == RADIO_STATE_RX_ACK) && (p_param->p_frame == mp_tx_data))
2789         {
2790             bool r;
2791 
2792             if (!nrf_802154_pib_rx_on_when_idle_get())
2793             {
2794                 r = core_sleep(NRF_802154_TERM_802154, REQ_ORIG_ACK_TIMEOUT, false);
2795             }
2796             else
2797             {
2798                 r = core_receive(NRF_802154_TERM_802154,
2799                                  REQ_ORIG_ACK_TIMEOUT,
2800                                  false,
2801                                  NRF_802154_RESERVED_IMM_RX_WINDOW_ID);
2802 
2803             }
2804             NRF_802154_ASSERT(r);
2805             (void)r;
2806 
2807             nrf_802154_transmit_done_metadata_t metadata = {0};
2808 
2809             nrf_802154_tx_work_buffer_original_frame_update(p_param->p_frame,
2810                                                             &metadata.frame_props);
2811             nrf_802154_notify_transmit_failed(p_param->p_frame,
2812                                               NRF_802154_TX_ERROR_NO_ACK,
2813                                               &metadata);
2814         }
2815 
2816         nrf_802154_critical_section_exit();
2817     }
2818 
2819     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2820 
2821     return result;
2822 }
2823 
nrf_802154_core_energy_detection(nrf_802154_term_t term_lvl,uint32_t time_us)2824 bool nrf_802154_core_energy_detection(nrf_802154_term_t term_lvl, uint32_t time_us)
2825 {
2826     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2827 
2828     bool result = critical_section_enter_and_verify_timeslot_length();
2829 
2830     if (result)
2831     {
2832         result = current_operation_terminate(term_lvl, REQ_ORIG_CORE, true);
2833 
2834         if (result)
2835         {
2836             if (time_us < ED_ITER_DURATION)
2837             {
2838                 time_us = ED_ITER_DURATION;
2839             }
2840 
2841             m_ed_time_left = time_us;
2842             m_ed_result    = 0;
2843 
2844             state_set(RADIO_STATE_ED);
2845             ed_init();
2846         }
2847 
2848         nrf_802154_critical_section_exit();
2849     }
2850 
2851     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2852 
2853     return result;
2854 }
2855 
nrf_802154_core_cca(nrf_802154_term_t term_lvl)2856 bool nrf_802154_core_cca(nrf_802154_term_t term_lvl)
2857 {
2858     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2859 
2860     bool result = critical_section_enter_and_verify_timeslot_length();
2861 
2862     if (result)
2863     {
2864         result = current_operation_terminate(term_lvl, REQ_ORIG_CORE, true);
2865 
2866         if (result)
2867         {
2868             state_set(RADIO_STATE_CCA);
2869             cca_init();
2870         }
2871 
2872         nrf_802154_critical_section_exit();
2873     }
2874 
2875     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2876 
2877     return result;
2878 }
2879 
2880 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
2881 
nrf_802154_core_continuous_carrier(nrf_802154_term_t term_lvl)2882 bool nrf_802154_core_continuous_carrier(nrf_802154_term_t term_lvl)
2883 {
2884     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2885 
2886     bool result = critical_section_enter_and_verify_timeslot_length();
2887 
2888     if (result)
2889     {
2890         result = current_operation_terminate(term_lvl, REQ_ORIG_CORE, true);
2891 
2892         if (result)
2893         {
2894             state_set(RADIO_STATE_CONTINUOUS_CARRIER);
2895             continuous_carrier_init();
2896         }
2897 
2898         nrf_802154_critical_section_exit();
2899     }
2900 
2901     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2902 
2903     return result;
2904 }
2905 
nrf_802154_core_modulated_carrier(nrf_802154_term_t term_lvl,const uint8_t * p_data)2906 bool nrf_802154_core_modulated_carrier(nrf_802154_term_t term_lvl,
2907                                        const uint8_t   * p_data)
2908 {
2909     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2910 
2911     bool result = critical_section_enter_and_verify_timeslot_length();
2912 
2913     if (result)
2914     {
2915         result = current_operation_terminate(term_lvl, REQ_ORIG_CORE, true);
2916 
2917         if (result)
2918         {
2919             state_set(RADIO_STATE_MODULATED_CARRIER);
2920             mp_tx_data = (uint8_t *)p_data;
2921             modulated_carrier_init(p_data);
2922         }
2923 
2924         nrf_802154_critical_section_exit();
2925     }
2926 
2927     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2928 
2929     return result;
2930 }
2931 
2932 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
2933 
nrf_802154_core_notify_buffer_free(uint8_t * p_data)2934 bool nrf_802154_core_notify_buffer_free(uint8_t * p_data)
2935 {
2936     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2937 
2938     rx_buffer_t * p_buffer     = (rx_buffer_t *)p_data;
2939     bool          in_crit_sect = critical_section_enter_and_verify_timeslot_length();
2940 
2941     p_buffer->free = true;
2942     nrf_802154_sl_atomic_store_u8(&m_no_rx_buffer_notified, 0U);
2943 
2944     if (in_crit_sect)
2945     {
2946         if (timeslot_is_granted())
2947         {
2948             if (nrf_802154_trx_receive_is_buffer_missing())
2949             {
2950                 rx_buffer_in_use_set(p_buffer);
2951                 nrf_802154_trx_receive_buffer_set(rx_buffer_get());
2952             }
2953         }
2954 
2955         nrf_802154_critical_section_exit();
2956     }
2957 
2958     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
2959 
2960     return true;
2961 }
2962 
nrf_802154_core_channel_update(req_originator_t req_orig)2963 bool nrf_802154_core_channel_update(req_originator_t req_orig)
2964 {
2965     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
2966 
2967     bool result = critical_section_enter_and_verify_timeslot_length();
2968 
2969     if (result)
2970     {
2971         if (timeslot_is_granted())
2972         {
2973             nrf_802154_trx_channel_set(nrf_802154_pib_channel_get());
2974         }
2975 
2976         switch (m_state)
2977         {
2978             case RADIO_STATE_RX:
2979                 if (current_operation_terminate(NRF_802154_TERM_802154, req_orig, true))
2980                 {
2981                     rx_init(TRX_RAMP_UP_SW_TRIGGER, NULL);
2982                 }
2983                 break;
2984 
2985 #if NRF_802154_CARRIER_FUNCTIONS_ENABLED
2986             case RADIO_STATE_CONTINUOUS_CARRIER:
2987                 if (timeslot_is_granted())
2988                 {
2989                     nrf_802154_trx_continuous_carrier_restart();
2990                 }
2991                 break;
2992 
2993             case RADIO_STATE_MODULATED_CARRIER:
2994                 if (timeslot_is_granted())
2995                 {
2996                     nrf_802154_trx_modulated_carrier_restart();
2997                 }
2998                 break;
2999 
3000 #endif // NRF_802154_CARRIER_FUNCTIONS_ENABLED
3001             default:
3002                 // Don't perform any additional action in any other state.
3003                 break;
3004         }
3005 
3006         nrf_802154_critical_section_exit();
3007     }
3008 
3009     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
3010 
3011     return result;
3012 }
3013 
nrf_802154_core_cca_cfg_update(void)3014 bool nrf_802154_core_cca_cfg_update(void)
3015 {
3016     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
3017 
3018     bool result = critical_section_enter_and_verify_timeslot_length();
3019 
3020     if (result)
3021     {
3022         if (timeslot_is_granted())
3023         {
3024             nrf_802154_trx_cca_configuration_update();
3025         }
3026 
3027         nrf_802154_critical_section_exit();
3028     }
3029 
3030     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
3031 
3032     return result;
3033 }
3034 
nrf_802154_core_rssi_measure(void)3035 bool nrf_802154_core_rssi_measure(void)
3036 {
3037     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
3038 
3039     bool result = critical_section_enter_and_verify_timeslot_length();
3040 
3041     if (result)
3042     {
3043         if (timeslot_is_granted() && (m_state == RADIO_STATE_RX))
3044         {
3045             result = nrf_802154_trx_rssi_measure();
3046         }
3047         else
3048         {
3049             result = false;
3050         }
3051 
3052         nrf_802154_critical_section_exit();
3053     }
3054 
3055     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
3056 
3057     return result;
3058 }
3059 
nrf_802154_core_last_rssi_measurement_get(int8_t * p_rssi)3060 bool nrf_802154_core_last_rssi_measurement_get(int8_t * p_rssi)
3061 {
3062     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
3063 
3064     bool result       = false;
3065     bool in_crit_sect = false;
3066     bool rssi_started = nrf_802154_trx_rssi_measure_is_started();
3067 
3068     if (rssi_started)
3069     {
3070         in_crit_sect = critical_section_enter_and_verify_timeslot_length();
3071     }
3072 
3073     if (rssi_started && in_crit_sect)
3074     {
3075         // Checking if a timeslot is granted is valid only in a critical section
3076         if (timeslot_is_granted())
3077         {
3078             rssi_started = nrf_802154_trx_rssi_measure_is_started();
3079             if (rssi_started)
3080             {
3081                 rssi_measurement_wait();
3082                 *p_rssi = rssi_last_measurement_get();
3083                 result  = true;
3084             }
3085         }
3086     }
3087 
3088     if (in_crit_sect)
3089     {
3090         nrf_802154_critical_section_exit();
3091     }
3092 
3093     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
3094 
3095     return result;
3096 }
3097 
nrf_802154_core_last_frame_rssi_get(void)3098 int8_t  nrf_802154_core_last_frame_rssi_get(void)
3099 {
3100     return m_last_rssi;
3101 }
3102 
nrf_802154_core_last_frame_lqi_get(void)3103 uint8_t nrf_802154_core_last_frame_lqi_get(void)
3104 {
3105     return m_last_lqi;
3106 }
3107 
nrf_802154_core_antenna_update(void)3108 bool nrf_802154_core_antenna_update(void)
3109 {
3110     nrf_802154_log_function_enter(NRF_802154_LOG_VERBOSITY_LOW);
3111 
3112     bool result = critical_section_enter_and_verify_timeslot_length();
3113 
3114     if (result)
3115     {
3116         if (timeslot_is_granted())
3117         {
3118             nrf_802154_trx_antenna_update();
3119         }
3120 
3121         nrf_802154_critical_section_exit();
3122     }
3123 
3124     nrf_802154_log_function_exit(NRF_802154_LOG_VERBOSITY_LOW);
3125 
3126     return result;
3127 }
3128 
nrf_802154_sl_ant_div_rssi_measure_get(void)3129 int8_t nrf_802154_sl_ant_div_rssi_measure_get(void)
3130 {
3131     int8_t result = NRF_802154_RSSI_INVALID;
3132 
3133     // This function is supposed to be called after detecting frame prestarted event, but before
3134     // detecting valid frame address. This means that we're currently in critical section, but the
3135     // timeslot is not yet extended due to detecting valid frame. To avoid invalid timeslot extension
3136     // due to blocking rssi measurements, antenna check can be aborted here if timeslot is about to end.
3137     // Antenna switching takes 200 ns (250 ns with safety margin), while rssi measurement - 250,
3138     // which gives total time of 750 ns.
3139     // 750 ns is less than safety margin, so timeslot us left different than 0 is sufficient.
3140     if (!nrf_802154_rsch_timeslot_us_left_get())
3141     {
3142         return result;
3143     }
3144 
3145     nrf_802154_trx_rssi_measure();
3146 
3147     if (nrf_802154_trx_rssi_measure_is_started())
3148     {
3149         while (!nrf_802154_trx_rssi_sample_is_available())
3150         {
3151             // Intentionally empty: This function is called from a critical section.
3152             // WFE would not be waken up by a RADIO event.
3153         }
3154 
3155         uint8_t rssi_sample = nrf_802154_trx_rssi_last_sample_get();
3156 
3157         rssi_sample = nrf_802154_rssi_sample_corrected_get(rssi_sample);
3158 
3159         result = -((int8_t)rssi_sample);
3160     }
3161 
3162     return result;
3163 }
3164