1 /*
2  * Copyright (c) 2018 - 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  * @brief Module that defines the Radio Scheduler interface.
37  *
38  */
39 
40 #ifndef NRF_802154_RSCH_H_
41 #define NRF_802154_RSCH_H_
42 
43 #include <stdbool.h>
44 #include <stdint.h>
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
50 /**
51  * @defgroup nrf_rsch Radio Scheduler
52  * @{
53  * @ingroup nrf_802154
54  * @brief The Radio Scheduler interface.
55  *
56  * Radio Scheduler is responsible to schedule radio activities and preconditions in time. It is
57  * expected that the Radio Scheduler module manages timings to meet the requirements requested from
58  * the core module.
59  *
60  * Examples of the radio activity preconditions are: High-Frequency Clock running, radio arbiter (RAAL)
61  * granted access to the RADIO peripheral.
62  */
63 
64 /**
65  * @brief Maximum number of DTX delayed timeslots that can be scheduled simultaneously.
66  */
67 #ifndef NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS
68 #define NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS 1
69 #endif
70 
71 /**
72  * @brief Maximum number of DRX delayed timeslots that can be scheduled simultaneously.
73  */
74 #ifndef NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS
75 #define NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS 2
76 #endif
77 
78 /**
79  * @brief Maximum number of CSMA/CA delayed timeslots that can be scheduled simultaneously.
80  */
81 #ifndef NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS
82 #define NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS 1
83 #endif
84 
85 /**
86  * @brief Number of available slots for all delayed timeslots.
87  */
88 #define NRF_802154_RSCH_DLY_TS_SLOTS      \
89     NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS + \
90     NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS + \
91     NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS
92 
93 /**
94  * @brief List of the preconditions that have to be met before any radio activity.
95  */
96 typedef enum
97 {
98     RSCH_PREC_HFCLK,
99     RSCH_PREC_RAAL,
100     RSCH_PREC_COEX,
101     RSCH_PREC_CNT,
102 } rsch_prec_t;
103 
104 /**
105  * @brief Priorities of the 802.15.4 radio operations.
106  */
107 typedef enum
108 {
109     RSCH_PRIO_IDLE,                                    ///< Priority used in the sleep state. With this priority, RSCH releases all preconditions.
110     RSCH_PRIO_IDLE_LISTENING,                          ///< Priority used during the idle listening procedure.
111     RSCH_PRIO_RX,                                      ///< Priority used when a frame is being received.
112     RSCH_PRIO_DETECT,                                  ///< Priority used to detect channel conditions (CCA, ED).
113     RSCH_PRIO_TX,                                      ///< Priority used to transmit a frame.
114 
115     RSCH_PRIO_MIN_APPROVED = RSCH_PRIO_IDLE_LISTENING, ///< Minimal priority indicating that the given precondition is approved.
116     RSCH_PRIO_MAX          = RSCH_PRIO_TX,             ///< Maximal priority available in the RSCH module.
117 } rsch_prio_t;
118 
119 /**
120  * @brief Enumeration of the delayed timeslot operation types.
121  */
122 typedef enum
123 {
124     RSCH_DLY_TS_OP_DTX,    ///< Timeslot for delayed TX operation.
125     RSCH_DLY_TS_OP_DRX,    ///< Timeslot for delayed RX operation.
126     RSCH_DLY_TS_OP_CSMACA, ///< Timeslot for CSMA/CA operation.
127 } rsch_dly_ts_op_t;
128 
129 /**
130  * @brief Identifier of a delayed timeslot.
131  */
132 typedef uint32_t rsch_dly_ts_id_t;
133 
134 /**
135  * @brief Enumeration of the precondition requesting strategies.
136  */
137 typedef enum
138 {
139     /** The following delayed timeslot type requires preconditions to be requested immediately
140      *  and released only by @ref nrf_802154_rsch_delayed_timeslot_cancel call. It is scheduled
141      *  irrespectively of current approved preconditions, which might introduce additional delays.
142      *  This delayed timeslot type also supports requests with target time in the past.
143      */
144     RSCH_DLY_TS_TYPE_RELAXED,
145 
146     /** The following delayed timeslot type requires preconditions to be requested as late
147      *  as possible to ensure they are ramped up on target time, and released as soon as possible.
148      *  This mode of operation does not allow for requests in the past and puts strict conditions
149      *  on preconditions that must be approved when the scheduled operation starts.
150      */
151     RSCH_DLY_TS_TYPE_PRECISE,
152 } rsch_dly_ts_type_t;
153 
154 /**
155  * @brief Function pointer used for notifying about delayed timeslot start.
156  *
157  * @param[in]  dly_ts_id  Identifier of the started delayed timeslot.
158  */
159 typedef void (* rsch_dly_ts_started_callback_t)(rsch_dly_ts_id_t dly_ts_id);
160 
161 /**
162  * @brief Structure that holds parameters of a delayed timeslot request.
163  */
164 typedef struct
165 {
166     uint64_t                       trigger_time;     ///< Trigger time of the timeslot start, in microseconds.
167     bool                           ppi_trigger_en;   ///< Enable the (D)PPI triggering after the start of the timeslot.
168     uint32_t                       ppi_trigger_dly;  ///< Time delta between @p trigger_time and the moment of (D)PPI triggering.
169     rsch_prio_t                    prio;             ///< Priority level required for the delayed timeslot.
170     rsch_dly_ts_op_t               op;               ///< Operation to be performed in the requested timeslot.
171     rsch_dly_ts_type_t             type;             ///< Type of the requested timeslot.
172     rsch_dly_ts_started_callback_t started_callback; ///< Callback called when delayed timeslot starts.
173     rsch_dly_ts_id_t               id;               ///< Identifier of the timeslot provided by its owner. Its value must be unique, to unambigously map to an active slot.
174 } rsch_dly_ts_param_t;
175 
176 /**
177  * @brief Initializes Radio Scheduler.
178  *
179  * @note This function must be called once, before any other function from this module.
180  *
181  * @note Radio Scheduler starts in the inactive mode after the initialization. To start the radio activity,
182  *       @ref nrf_802154_rsch_continuous_mode_enter should be called.
183  *
184  */
185 void nrf_802154_rsch_init(void);
186 
187 /**
188  * @brief Deinitializes Radio Scheduler.
189  *
190  */
191 void nrf_802154_rsch_uninit(void);
192 
193 /**
194  * @brief Sets the priority for the continuous radio mode.
195  *
196  * In the continuous mode, Radio Scheduler tries to satisfy all preconditions for as long as
197  * possible to give the radio driver core as much radio time as possible while
198  * disturbing the other activities to the minimum extent.
199  *
200  * @note The start of a timeslot is indicated by the @ref nrf_802154_rsch_prec_is_approved call.
201  * @note To disable the continuous radio mode, the @ref RSCH_PRIO_IDLE should be used.
202  *
203  * @param[in]  prio  Priority level used in the continuous radio mode.
204  *
205  */
206 void nrf_802154_rsch_continuous_mode_priority_set(rsch_prio_t prio);
207 
208 /**
209  * @brief Confirms that the current part of the continuous timeslot is ended by the core.
210  *
211  * This confirmation is used by the core to synchronize the ending of the continuous timeslot parts with
212  * the RSCH module.
213  *
214  */
215 void nrf_802154_rsch_continuous_ended(void);
216 
217 /**
218  * @brief Immediately requests a timeslot for radio communication.
219  *
220  * This function is to be called only after @ref nrf_802154_rsch_prec_is_approved indicated the
221  * start of a timeslot.
222  *
223  * @param[in] length_us  Requested radio timeslot length in microseconds.
224  *
225  * @retval true   Radio driver has now exclusive access to the RADIO peripheral for the
226  *                full length of the timeslot.
227  * @retval false  Slot cannot be assigned due to other activities.
228  *
229  */
230 bool nrf_802154_rsch_timeslot_request(uint32_t length_us);
231 
232 /**
233  * @brief Requests a timeslot in the future.
234  *
235  * Request timeslot that is to be granted in the future. The function parameters provide data when
236  * the timeslot is supposed to start and how long it is to last. When the requested timeslot starts,
237  * @p p_dly_ts_param->started_callback is called.
238  *
239  * For a given type of operation to be performed in the delayed timeslot, @p p_dly_ts_param->op,
240  * there's a limited number of delayed timeslots that can be scheduled at the same time:
241  *   - for delayed transmissions it's @ref NRF_802154_RSCH_DLY_TS_OP_DTX_SLOTS;
242  *   - for delayed receptions it's @ref NRF_802154_RSCH_DLY_TS_OP_DRX_SLOTS;
243  *   - for CSMA/CA it's @ref NRF_802154_RSCH_DLY_TS_OP_CSMACA_SLOTS.
244  *
245  * If the API user requests more delayed timeslots with given @p p_dly_ts_param->op than specified
246  * by these constants, the request will fail unconditionally. It also implies that there can only
247  * be as many delayed timeslots scheduled simultaneously in total as the sum of these constants.
248  *
249  * @note Every call to this function must be paired with a call to
250  *       @ref nrf_802154_rsch_delayed_timeslot_cancel so that the assigned slot becomes
251  *       available for future requests.
252  *
253  * @note @p p_dly_ts_param->started_callback can be delayed and it is up to
254  *       the called module to check the delay and decide if it causes any issues.
255  *
256  * @note The time parameters use the same units that are used in the SL Timer module.
257  *
258  * @param[in]   p_dly_ts_param  Parameters of the requested delayed timeslot.
259  *
260  * @retval true   Requested timeslot has been scheduled.
261  * @retval false  Requested timeslot cannot be scheduled and will not be granted.
262  */
263 bool nrf_802154_rsch_delayed_timeslot_request(const rsch_dly_ts_param_t * p_dly_ts_param);
264 
265 /**
266  * @brief Cancels a requested future timeslot.
267  *
268  * The delayed timeslot must be explicitly cancelled from the @p p_dly_ts_param->started_callback
269  * handler function passed to @ref nrf_802154_rsch_delayed_timeslot_request. When timeslot is
270  * released from the handler context, the @p handler flag must be set to @p true.
271  * Otherwise, the timeslot can be cancelled before it starts, which may be earlier than entering the
272  * @p p_dly_ts_param->started_callback handler function.
273  *
274  * Care must be taken when canceling a timeslot from an interrupt context. Delayed timeslots with
275  * type @p RSCH_DLY_TS_TYPE_PRECISE cannot be safely canceled from an interrupt context with higher
276  * priority than delayed timeslot callback context.
277  *
278  * @param[in] dly_ts_id  Identifier of the requested timeslot. If the provided value does not refer
279  *                       to any scheduled delayed timeslot, the function returns false.
280  * @param[in] handler    Indicates whether the requested timeslot is released from handler function.
281  *
282  * @retval true     Scheduled timeslot has been cancelled.
283  * @retval false    No scheduled timeslot has been requested (nothing to cancel).
284  */
285 bool nrf_802154_rsch_delayed_timeslot_cancel(rsch_dly_ts_id_t dly_ts_id, bool handler);
286 
287 /**
288  * @brief Updates the id of (D)PPI channel to be triggered in the current timeslot.
289  *
290  * The update must be done after the start of the timeslot but earlier than @c ppi_trigger_dly.
291  * If updating does not complete on time, (D)PPI triggering may not be performed.
292  *
293  * @retval true     (D)PPI channel has been updated and it was done on time, i.e. before
294  *                  target trigger time.
295  * @retval false    Update could not complete or did not complete on time. Nevertheless,
296  *                  the (D)PPI may have been triggered, but it cannot be stated reliably.
297  */
298 bool nrf_802154_rsch_delayed_timeslot_ppi_update(uint32_t ppi_channel);
299 
300 /**
301  * @brief Updates priority of a requested delayed timeslot.
302  *
303  * @param[in] dly_ts_id    Identifier of the requested timeslot. If the provided value does not
304  *                         refer to any scheduled or active delayed timeslot, the function
305  *                         returns false.
306  * @param[in] dly_ts_prio  Priority to be assigned to the requested timeslot.
307  *
308  * @retval true     Scheduled timeslot's priority has been updated.
309  * @retval false    Priority of the specified timeslot could not be updated.
310  */
311 bool nrf_802154_rsch_delayed_timeslot_priority_update(rsch_dly_ts_id_t dly_ts_id,
312                                                       rsch_prio_t      dly_ts_prio);
313 
314 /**
315  * @brief Retrieves the remaining time until a requested timeslot begins.
316  *
317  * @param[in]  dly_ts_id        ID of the requested timeslot.
318  * @param[out] p_time_to_start  Pointer to a 32-bit variable where time to start will be stored.
319  *
320  * @retval true     The given timeslot was scheduled and p_time_to_start contains a valid value.
321  * @retval false    The given timeslot was not scheduled and p_time_to_start was not modified.
322  */
323 bool nrf_802154_rsch_delayed_timeslot_time_to_start_get(rsch_dly_ts_id_t dly_ts_id,
324                                                         uint64_t       * p_time_to_start);
325 /**
326  * @brief Checks if there is a pending timeslot request.
327  *
328  * @note The delayed timeslot is considered requested once its preconditions are requested
329  *       or granted.
330  *
331  * @retval true   There is a timeslot request pending.
332  * @retval false  There are no pending timeslot requests.
333  */
334 bool nrf_802154_rsch_timeslot_is_requested(void);
335 
336 /**
337  * @brief Checks if the RSCH precondition is satisfied.
338  *
339  * @param[in]  prec    RSCH precondition to be checked.
340  * @param[in]  prio    Minimal required priority level of the given precondition.
341  *
342  * @retval true   Precondition @p prec is currently granted.
343  * @retval false  Precondition @p prec is not currently granted.
344  */
345 bool nrf_802154_rsch_prec_is_approved(rsch_prec_t prec, rsch_prio_t prio);
346 
347 /**
348  * @brief Gets the remaining time of the currently granted timeslot, in microseconds.
349  *
350  * @returns  Number of microseconds remaining in the currently granted timeslot.
351  */
352 uint32_t nrf_802154_rsch_timeslot_us_left_get(void);
353 
354 /**
355  * @brief Notifies the core about changes of the approved priority level.
356  *
357  * If @p prio is greater than @ref RSCH_PRIO_IDLE, the radio driver has exclusive access to the
358  * peripherals until this function is called with @p prio equal to @ref RSCH_PRIO_IDLE.
359  *
360  * @note The end of the timeslot is indicated by @p prio equal to @ref RSCH_PRIO_IDLE.
361  *
362  * @param[in]  prio  Currently approved priority level.
363  */
364 extern void nrf_802154_rsch_continuous_prio_changed(rsch_prio_t prio);
365 
366 /**
367  *@}
368  **/
369 
370 #ifdef __cplusplus
371 }
372 #endif
373 
374 #endif /* NRF_802154_RSCH_H_ */
375