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(×tamp);
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