1 /*
2  * Copyright (c) 2020 - 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 provides the timer service for the 802.15.4 driver.
37  *
38  * The @b timer module allows scheduling future actions to happen. Object of type
39  * @ref nrf_802154_sl_timer_t (and related functions) is responsible for this feature.
40  */
41 
42 #ifndef NRF_802154_SL_TIMER_H_
43 #define NRF_802154_SL_TIMER_H_
44 
45 #include <stdint.h>
46 #include <stdbool.h>
47 
48 #ifdef __cplusplus
49 extern "C" {
50 #endif
51 
52 /**
53  * @defgroup nrf_802154_sl_timer Timer Service
54  * @{
55  * @ingroup nrf_802154_sl_timer
56  * @brief The Timer Service for the 802.15.4 driver.
57  *
58  */
59 
60 /**@brief Number of array elements required by @ref nrf_802154_sl_timer_priv_placeholder_t. */
61 #define NRF_802154_SL_TIMER_PRIV_SIZE 2U
62 
63 /**@brief Type of result returned by timer-related functions.
64  *
65  * Possible values:
66  * @ref NRF_802154_SL_TIMER_RET_SUCCESS
67  * @ref NRF_802154_SL_TIMER_RET_TOO_LATE
68  * @ref NRF_802154_SL_TIMER_RET_TOO_DISTANT
69  * @ref NRF_802154_SL_TIMER_RET_NO_RESOURCES
70  * @ref NRF_802154_SL_TIMER_RET_INACTIVE
71  * @ref NRF_802154_SL_TIMER_RET_BAD_REQUEST
72  */
73 typedef uint32_t nrf_802154_sl_timer_ret_t;
74 
75 /**@brief Operation performed successfully. */
76 #define NRF_802154_SL_TIMER_RET_SUCCESS      0U
77 
78 /**@brief Passed invalid parameters to a call.
79  * This result may occur if the user filled incorrect values in the request
80  * object or given feature is not supported yet
81  */
82 #define NRF_802154_SL_TIMER_RET_BAD_REQUEST  1U
83 
84 /**@brief Operation was requested too late to be performed in requested time. */
85 #define NRF_802154_SL_TIMER_RET_TOO_LATE     2U
86 
87 /**@brief The trigger time for the requested operation is too distant.
88  *
89  * Some platforms have a limitation to how far in the future operation can be
90  * scheduled. This result may happen for @ref nrf_802154_sl_timer_add with
91  * @ref nrf_802154_sl_timer_t::trigger_time containing a value too far from `now`.
92  */
93 #define NRF_802154_SL_TIMER_RET_TOO_DISTANT  3U
94 
95 /**@brief There were no available resources required to schedule requested activity.
96  *
97  * This result may happen for @ref nrf_802154_sl_timer_add with
98  * @ref nrf_802154_sl_timer_t::action_type containing
99  * @ref NRF_802154_SL_TIMER_ACTION_TYPE_HARDWARE. To trigger hardware task by the timer,
100  * some hardware resources like PPI/DPPI channels, EGU channels, timer compare channels
101  * (implementation dependent) were needed, but they were unavailable.
102  */
103 #define NRF_802154_SL_TIMER_RET_NO_RESOURCES 4U
104 
105 /**@brief The timer was inactive at the moment of requested operation. */
106 #define NRF_802154_SL_TIMER_RET_INACTIVE     5U
107 
108 /**@brief Type representing a timer. */
109 typedef struct nrf_802154_sl_timer_s nrf_802154_sl_timer_t;
110 
111 /**@brief Type of callback function pointer to be called when timer triggers. */
112 typedef void (* nrf_802154_sl_timer_callback_t)(nrf_802154_sl_timer_t * p_timer);
113 
114 /**@brief Action types to be performed when a timer triggers.
115  *
116  * This is a bitmask with possible masks:
117  * @ref NRF_802154_SL_TIMER_ACTION_TYPE_CALLBACK
118  * @ref NRF_802154_SL_TIMER_ACTION_TYPE_HARDWARE
119  */
120 typedef uint8_t nrf_802154_sl_timer_action_type_t;
121 
122 /**@brief Timer action type mask allowing a callback to be called. */
123 #define NRF_802154_SL_TIMER_ACTION_TYPE_CALLBACK (1U << 0)
124 /**@brief Timer action type mask allowing triggering a hardware task. */
125 #define NRF_802154_SL_TIMER_ACTION_TYPE_HARDWARE (1U << 1)
126 
127 /**
128  * @brief Special value that indicates that (D)PPI configuration is incomplete.
129  */
130 #define NRF_802154_SL_TIMER_INVALID_PPI_CHANNEL  UINT32_MAX
131 
132 /**@brief Structure that represents private fields of a timer required by the implementation. */
133 typedef struct
134 {
135     uint64_t placeholder[NRF_802154_SL_TIMER_PRIV_SIZE];
136 } nrf_802154_sl_timer_priv_placeholder_t;
137 
138 struct nrf_802154_sl_timer_s
139 {
140     /**@brief Private fields required by the implementation.
141      *
142      * Must be at the beginning of the structure.
143      */
144     nrf_802154_sl_timer_priv_placeholder_t priv;
145 
146     /**@brief The timestamp in microseconds at which the timer should be triggered.
147      *
148      * The callback will be called no earlier than at given @p trigger_time, but may be delayed
149      * due to processing time taken by other ISRs.
150      */
151     uint64_t trigger_time;
152 
153     /**@brief User-provided data.
154      *
155      * User preparing a timer can store any data within this field. Timer module does not
156      * process this data.
157      */
158     union
159     {
160         void       * p_pointer;
161         const void * p_cpointer;
162     } user_data;
163 
164     /**@brief Action type to be performed when the timer triggers.
165      *
166      * Depending on value bits set in this bitmask, appropriate fields of @c action is valid.
167      */
168     nrf_802154_sl_timer_action_type_t action_type;
169 
170     struct
171     {
172         /**@brief Parameters applicable when @c action_type contains
173          *        @ref NRF_802154_SL_TIMER_ACTION_TYPE_CALLBACK */
174         struct
175         {
176             /**@brief Callback to be called when the timer triggers.
177              *
178              * The callback is called within an ISR. Please take into account possible
179              * latency between moment of trigger and moment when the callback gets called.
180              */
181             nrf_802154_sl_timer_callback_t callback;
182         } callback;
183 
184         /**@brief Parameters applicable when @c action_type contains
185          *        @ref NRF_802154_SL_TIMER_ACTION_TYPE_HARDWARE */
186         struct
187         {
188             /**@brief Identifier of (D)PPI channel to be triggered at @c trigger_time.
189              *
190              * The API user is responsible for creating all necessary hardware bindings between
191              * provided (D)PPI channel and the requested task, as well as necessary configuration
192              * of these resources. Moreover, the API user must keep the hardware bindings enabled
193              * and functional until the requested hardware task is triggered or until the timer
194              * is successfully removed.
195              *
196              * A special value of @ref NRF_802154_SL_TIMER_INVALID_PPI_CHANNEL can be set. In this
197              * case, the binding creation is postponed and the user is required to use the
198              * @ref nrf_802154_sl_timer_update_ppi to complete the configuration. Must do so
199              * before @c trigger_time expires.
200              */
201             uint32_t ppi_channel;
202         } hardware;
203     } action;
204 };
205 
206 /**@brief Initializes the timer module. */
207 void nrf_802154_sl_timer_module_init(void);
208 
209 /**@brief Uninitializes the timer module. */
210 void nrf_802154_sl_timer_module_uninit(void);
211 
212 /**@brief Gets current time.
213  *
214  * @return Time in microseconds.
215  */
216 uint64_t nrf_802154_sl_timer_current_time_get(void);
217 
218 /**@brief Initializes a timer instance.
219  *
220  * This function plays a role of a constructor. It should be called once
221  * per timer instance before any other API call related to given
222  * timer instance. Calling any other API related to a timer
223  * instance before call to @ref nrf_802154_sl_timer_init or
224  * calling @ref nrf_802154_sl_timer_init more than once is an
225  * undefined behavior.
226  *
227  * @param p_timer   Pointer to a timer instance to be initialized.
228  */
229 void nrf_802154_sl_timer_init(nrf_802154_sl_timer_t * p_timer);
230 
231 /**@brief De-initializes a timer instance.
232  *
233  * This function plays a role of a destructor.
234  *
235  * @param p_timer   Pointer to a timer instance to be de-initialized.
236  */
237 void nrf_802154_sl_timer_deinit(nrf_802154_sl_timer_t * p_timer);
238 
239 /**@brief Adds a timer to the active timers list.
240  *
241  * This function adds the timer pointed by @p p_timer parameter to an active timers
242  * list. Before call to @ref nrf_802154_sl_timer_add the timer must fill
243  * public fields of timer object instance in the following way:
244  * - @ref nrf_802154_sl_timer_t::trigger_time is set up to the moment when the timer
245  *   is expected to trigger
246  * - Optionally @ref nrf_802154_sl_timer_t::user_data may be set, to user-dependent value.
247  * - @ref nrf_802154_sl_timer_t::action_type is set according to requested action.
248  * - Depending on value written to @ref nrf_802154_sl_timer_t::action_type
249  *   matching fields of @ref nrf_802154_sl_timer_t::action must be filled.
250  *
251  * When this function succeeds the timer module takes ownership of the timer instance.
252  * A user is forbidden to modify the structure until the callback is called or
253  * @ref nrf_802154_sl_timer_remove is successfully called. Modification of timer owned by the
254  * timer service results in an undefined behavior. In particular the user
255  * is forbidden to set a new value of @ref nrf_802154_sl_timer_t::trigger_time as long as the
256  * timer is owned by the timer service.
257  *
258  * Please note that if @ref nrf_802154_sl_timer_t::trigger_time is in the past or very near in
259  * the future, the timer is scheduled and will fire as soon as possible but not earlier than
260  * given by @ref nrf_802154_sl_timer_t::trigger_time.
261  *
262  * @param p_timer   Pointer to a timer instance to add to active timers list.
263  *
264  * @retval NRF_802154_SL_TIMER_RET_SUCCESS
265  *      Function succeeded. The timer is sussessfully added. The requested action is
266  *      scheduled to happen.
267  * @retval NRF_802154_SL_TIMER_RET_NO_RESOURCES
268  *      The requested hardware task can't be bound to the timer due to lack of hardware resources.
269  * @retval NRF_802154_SL_TIMER_RET_BAD_REQUEST
270  *      A user passed unsupported or invalid parameters in @p p_timer.
271  */
272 nrf_802154_sl_timer_ret_t nrf_802154_sl_timer_add(nrf_802154_sl_timer_t * p_timer);
273 
274 /**@brief Removes a timer from the active timers list.
275  *
276  * @param p_timer   Pointer to a timer instance to be removed from the active timers list.
277  *
278  * @retval NRF_802154_SL_TIMER_RET_SUCCESS
279  *      The timer was running and it has been successfully removed from active timers list.
280  *      The requested action (either callback or hardware task trigger) will not happen.
281  * @retval NRF_802154_SL_TIMER_RET_INACTIVE
282  *      The timer was not running at the moment of the call and is not in the active timers list.
283  *      Nothing can be implied about the completion of the timer's requested action, without
284  *      checking external conditions. It is up to the caller to detect if requested action
285  *      (either callback, hardware task or both) has already been executed, is currently
286  *      in progress or yet remains to be executed.
287  */
288 nrf_802154_sl_timer_ret_t nrf_802154_sl_timer_remove(nrf_802154_sl_timer_t * p_timer);
289 
290 /**@brief Updates the (D)PPI channel to be triggered.
291  *
292  * @param p_timer   Pointer to a timer instance to be updated.
293  * @param ppi_chn   Identifier of (D)PPI channel to be triggered at @c trigger_time.
294  *
295  * @retval NRF_802154_SL_TIMER_RET_SUCCESS
296  *      The (D)PPI channel was updated and it was done on time, i.e. before specified
297  *      trigger time.
298  * @retval NRF_802154_SL_TIMER_RET_TOO_LATE
299  *      It has been detected that the timer has already fired and because of this the update
300  *      could not complete at all or did not complete on time. Nevertheless, the (D)PPI may
301  *      have been triggered, but it cannot be stated reliably.
302  * @retval NRF_802154_SL_TIMER_RET_BAD_REQUEST
303  *      A user passed invalid parameters in @p p_timer, e.g. @c action_type does not contain
304  *      @ref NRF_802154_SL_TIMER_ACTION_TYPE_HARDWARE.
305  */
306 nrf_802154_sl_timer_ret_t nrf_802154_sl_timer_update_ppi(nrf_802154_sl_timer_t * p_timer,
307                                                          uint32_t                ppi_chn);
308 
309 /**
310  *@}
311  **/
312 
313 #ifdef __cplusplus
314 }
315 #endif
316 
317 #endif /* NRF_802154_SL_TIMER_H_ */
318