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