1 /*
2  * Copyright (c) 2022-2023, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef ti_drivers_RCL_Scheduler_h__include
34 #define ti_drivers_RCL_Scheduler_h__include
35 
36 #include <stdint.h>
37 #include <stddef.h>
38 
39 #include <ti/drivers/rcl/RCL_Command.h>
40 #include <ti/drivers/rcl/hal/hal.h>
41 
42 /**
43  *  Number of ticks in the given number of microseconds
44  */
45 #define RCL_SCHEDULER_SYSTIM_US(x) (((uint32_t) (x)) * 4U)
46 /**
47  *  Number of ticks in the given number of milliseconds
48  */
49 #define RCL_SCHEDULER_SYSTIM_MS(x) (((uint32_t) (x)) * 4U * 1000U)
50 
51 
52 /* Timing constants */
53 #define ABS_START_TIME_OFFSET            RCL_SCHEDULER_SYSTIM_US(100U) /*!< Delay from scheduled start to start trigger to LRF */
54 #define IMM_START_TIME_OFFSET            RCL_SCHEDULER_SYSTIM_US(90U)  /*!< Delay from immediate start to start trigger to LRF */
55 #define RCL_SCHEDULER_MARGIN_ARM         RCL_SCHEDULER_SYSTIM_US(40U)  /*!< Time to prepare FIFO + PBE */
56 #define RCL_SCHEDULER_MARGIN_CONFIGURE   RCL_SCHEDULER_SYSTIM_US(76U)  /*!< Time to reload REGBANKs */
57 #define RCL_SCHEDULER_MARGIN_LOAD        RCL_SCHEDULER_SYSTIM_US(460U) /*!< Time to load TOPsm images */
58 #define RCL_SCHEDULER_SLEEP_CUTOFF       RCL_SCHEDULER_SYSTIM_MS(10U)  /*!< Time margin when not to arm LRF immediately */
59 #define RCL_SCHEDULER_TRIG_NOW_DELAY     RCL_SCHEDULER_SYSTIM_US(50U)  /*!< Delay to add to current time to allow start to be in the future */
60 #if defined(DeviceFamily_CC23X0R5) || defined(DeviceFamily_CC23X0R2) || defined(DeviceFamily_CC23X0R22) || defined(DeviceFamily_CC2340R53)
61 #define RCL_SCHEDULER_WAKEUP_MARGIN      RCL_SCHEDULER_SYSTIM_US(390U) /*!< Wakeup margin to allow for varying command and setup time */
62 #else
63 #define RCL_SCHEDULER_WAKEUP_MARGIN      RCL_SCHEDULER_SYSTIM_US(1000U)/*!< Wakeup margin to allow for varying command and setup time */
64 #endif
65 
66 typedef enum {
67     RCL_SchedulerStopReason_None = 0,       /*!< No stop active */
68     RCL_SchedulerStopReason_Timeout = 1,    /*!< Command stop time is active  */
69     RCL_SchedulerStopReason_Scheduling = 2, /*!< Scheduler stop is active */
70     RCL_SchedulerStopReason_Api = 3,        /*!< API stop has been sent and will take precedence */
71 } RCL_SchedulerStopReason;
72 
73 typedef enum {
74     RCL_SchedulerStopTimeState_Init = 0,       /*!< Stop times not calculated or programmed */
75     RCL_SchedulerStopTimeState_Found = 1,      /*!< Stop times calculated, but not programmed */
76     RCL_SchedulerStopTimeState_Programmed = 2, /*!< Stop times calculated and programmed to timer */
77 } RCL_SchedulerStopTimeState;
78 
79 typedef struct RCL_SchedulerStopInfo_s {
80     uint32_t cmdStopEnabled                     : 1;
81     uint32_t schedStopEnabled                   : 1;
82     uint32_t apiStopEnabled                     : 1;
83     RCL_SchedulerStopReason stopReason          : 2;
84     uint32_t cmdStopTime;
85     uint32_t schedStopTime;
86 } RCL_SchedulerStopInfo;
87 
88 typedef struct RCL_SchedulerState_s {
89     RCL_Command  *currCmd;
90     uint32_t nextWantsStop                      : 1;
91     RCL_SchedulerStopTimeState stopTimeState    : 2;
92     RCL_SchedulerStopReason descheduleReason    : 2;
93     RCL_Events postedRclEvents; /* Events to be handled by the command handler */
94     uint32_t actualStartTime;
95     RCL_SchedulerStopInfo hardStopInfo;
96     RCL_SchedulerStopInfo gracefulStopInfo;
97     uint16_t requestedPhyFeatures;
98 } RCL_SchedulerState;
99 
100 extern RCL_SchedulerState rclSchedulerState;
101 
102 /** @defgroup timingHandlerFunctions Timing Handler Functions
103  *  These functions are meant mostly to be used by handlers and RCL itself
104  *  @{
105  */
106 
107 /**
108  *  @brief  Get relevant status when a command was stopped
109  *
110  *  Returns the status to be set for a command that was stopped with the given stop source,
111  *  depending on what caused the stop
112  *
113  *  @note This function is intended as internal to RCL and its handlers
114  *
115  *  @param  stopType Stop type observed
116  *
117  *  @return Command status that should be produced
118  */
119 RCL_CommandStatus RCL_Scheduler_findStopStatus(RCL_StopType stopType);
120 
121 /**
122  *  @brief  Set start and stop time for LRF based on command
123  *
124  *  Sets start and stop times for LRF based on scheduled times
125  *
126  *  @note This function is intended as internal to RCL and its handlers
127  *
128  *  @param  cmd Pointer to running command
129  *
130  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
131  */
132 RCL_CommandStatus RCL_Scheduler_setStartStopTime(const RCL_Command *cmd);
133 
134 /**
135  *  @brief  Set start and stop time for LRF based on command with earliest start time
136  *
137  *  Sets start and stop times for LRF based on scheduled times, but delay start if needed due to hardware startup time
138  *
139  *  @note This function is intended as internal to RCL and its handlers
140  *
141  *  @param  cmd Pointer to running command
142  *
143  *  @param  earliestStartTime Start at earliest at this time, or fail if delay not allowed
144  *
145  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
146  */
147 RCL_CommandStatus RCL_Scheduler_setStartStopTimeEarliestStart(const RCL_Command *cmd, uint32_t earliestStartTime);
148 
149 /**
150  *  @brief  Set start and stop time for LRF
151  *
152  *  Sets start and stop times for LRF based on provided times
153  *
154  *  @note This function is intended as internal to RCL and its handlers
155  *
156  *  @param  timing Start and stop times to set
157  *
158  *  @param  scheduling Scheduling type
159  *
160  *  @param  allowDelay True if start may be delayed; false if late start is an error
161  *
162  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
163  */
164 RCL_CommandStatus RCL_Scheduler_setCustomStartStopTime(const RCL_CommandTiming *timing, RCL_ScheduleType scheduling, bool allowDelay);
165 
166 /**
167  *  @brief  Set start and stop time for LRF with earliest start time
168  *
169  *  Sets start and stop times for LRF based on provided times, but delay start if needed due to hardware startup time
170  *
171  *  @note This function is intended as internal to RCL and its handlers
172  *
173  *  @param  timing Start and stop times to set
174  *
175  *  @param  scheduling Scheduling type
176  *
177  *  @param  allowDelay True if start may be delayed; false if late start is an error
178  *
179  *  @param  earliestStartTime Start at earliest at this time, or fail if delay not allowed
180  *
181  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
182  */
183 RCL_CommandStatus RCL_Scheduler_setCustomStartStopTimeEarliestStart(const RCL_CommandTiming *timing, RCL_ScheduleType scheduling, bool allowDelay, uint32_t earliestStartTime);
184 
185 /**
186  *  @brief  Set stop time for LRF based on command when it does not need a start trigger
187  *
188  *  Sets stop times for LRF based on scheduled times, but do not program any start trigger
189  *
190  *  @note This function is intended as internal to RCL and its handlers
191  *
192  *  @param  cmd Pointer to running command
193  *
194  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
195  */
196 RCL_CommandStatus RCL_Scheduler_setCmdStopTimeNoStartTrigger(const RCL_Command *cmd);
197 
198 /**
199  *  @brief  Set new start time for LRF to now, after a previous start
200  *
201  *  @note This function is intended as internal to RCL and its handlers
202  *
203  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
204  */
205 RCL_CommandStatus RCL_Scheduler_setNewStartNow(void);
206 
207 /**
208  *  @brief  Set new start time for LRF to given absolute time, after a previous start
209  *
210  *  @note This function is intended as internal to RCL and its handlers
211  *
212  *  @param  startTime Absloute start time
213  *
214  *  @param  allowDelay True if start may be delayed; false if late start is an error
215  *
216  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
217  */
218 RCL_CommandStatus RCL_Scheduler_setNewStartAbsTime(uint32_t startTime, bool allowDelay);
219 
220 /**
221  *  @brief  Set new start time for LRF to given time relative to previous LRF start
222  *
223  *  @note This function is intended as internal to RCL and its handlers
224  *
225  *  @param  relStartTime Start time relative to previous actual start time of LRF
226  *
227  *  @return Command status that should be produced if the command should end or RCL_CmdStatus_Active to go on
228  */
229 RCL_CommandStatus RCL_Scheduler_setNewStartRelTime(uint32_t relStartTime);
230 
231 /**
232  *  @brief  Function to apply relevant stop times
233  *
234  *  Sets stop times for LRF based on scheduled times
235  *
236  *  @note This function is intended as internal to RCL and its handlers
237  *
238  *  @return Stop type if stop needs to be applied immediately
239  */
240 RCL_StopType RCL_Scheduler_setStopTimes(void);
241 
242 /** @}
243  */
244 
245 /** @defgroup timingApiFunctions Timing API Functions
246  *  These functions are useful as part of the API to RCL
247  *  @{
248  */
249 
250 /**
251  *  @brief  Find if a time instant occurs after another, allowing wrap-around
252  *
253  *  Checks if a time is before or after another. In the processing, a time is assumed to be before
254  *  the reference if it is less than 1/8 of the full timer range (134 seconds) before it; otherwise
255  *  it is assumed to be in the future. This means that the time presumed to be the latest should
256  *  always be the second parameter (%chkTime)
257  *
258  *  @param  refTime Reference time
259  *
260  *  @param  chkTime Time to be checked
261  *
262  *  @return true if %chkTime comes after %refTime. false if %chkTime comes before %refTime or if they are equal.
263  */
264 bool               RCL_Scheduler_isLater(uint32_t refTime, uint32_t chkTime);
265 
266 /**
267  *  @brief  Find the time difference between two times, allowing wrap-around
268  *
269  *  Finds the signed difference between two times, saturated at the maximum signed 32-bit integer
270  *  value. In the processing, a time is assumed to be before the reference if it is less than 1/8
271  *  of the full timer range (134 seconds) before it; otherwise
272  *  it is assumed to be in the future.
273  *
274  *  @param  refTime Reference time
275  *
276  *  @param  chkTime Time to be checked
277  *
278  *  @return Time difference (%chkTime-%refTime) corrected for wrap-around.
279  *          Saturated at 0x7FFFFFFF (8 min 57 sec).
280  */
281 int32_t            RCL_Scheduler_delta(uint32_t refTime, uint32_t chkTime);
282 
283 /**
284  *  @brief  Get current time
285  *
286  *  @return Current SYSTIM time (0.25 us steps) usable for radio command timing
287  */
RCL_Scheduler_getCurrentTime(void)288 static inline uint32_t RCL_Scheduler_getCurrentTime(void)
289 {
290     return hal_get_current_time();
291 }
292 
293 /**
294  *  @brief  Set scheduler stop time
295  *
296  * Sets scheduler stop time for the given stop type, finds which of the
297  * active stop times comes first, sets selection bits accordingly and
298  * reprograms the stop time if it was already programmed.
299  *
300  *  @param  stopInfo Pointer to stop info for the relevant stop type
301  *
302  *  @param  schedStopTime New scheduler stop time to apply
303  *
304  *  @return Stop type if stop needs to be applied immediately
305  */
306 RCL_StopType RCL_Scheduler_setSchedStopTime(RCL_SchedulerStopInfo *stopInfo, uint32_t schedStopTime);
307 
308 /**
309  *  @brief  Set command stop time
310  *
311  * Sets command stop time for the given stop type, finds which of the
312  * active stop times comes first, sets selection bits accordingly and
313  * reprograms the stop time if it was already programmed.
314  *
315  *  @param  stopInfo Pointer to stop info for the relevant stop type
316  *
317  *  @param  cmdStopTime New command stop time to apply
318  *
319  *  @return Stop type if stop needs to be applied immediately
320  */
321 RCL_StopType RCL_Scheduler_setCmdStopTime(RCL_SchedulerStopInfo *stopInfo, uint32_t cmdStopTime);
322 
323 /**
324  *  @brief  Cancel scheduler stop time
325  *
326  * Cancels scheduler stop time for the given stop type, finds if there
327  * is still an active stop time, cancels or reprograms the stop time
328  * if it was already programmed.
329  *
330  *  @param  stopInfo Pointer to stop info for the relevant stop type
331  *
332  *  @return Stop type if stop needs to be applied immediately
333  */
334 RCL_StopType RCL_Scheduler_cancelSchedStopTime(RCL_SchedulerStopInfo *stopInfo);
335 
336 /**
337  *  @brief  Cancel command stop time
338  *
339  * Cancels command stop time for the given stop type, finds if there
340  * is still an active stop time, cancels or reprograms the stop time
341  * if it was already programmed.
342  *
343  *  @param  stopInfo Pointer to stop info for the relevant stop type
344  *
345  *  @return Stop type if stop needs to be applied immediately
346  */
347 RCL_StopType RCL_Scheduler_cancelCmdStopTime(RCL_SchedulerStopInfo *stopInfo);
348 
349 /**
350  * @brief Post event to command handler
351  *
352  * @param[in] c Command to post event to
353  * @param[in] e Event(s) to post
354  * @return true If command was active and event was posted
355  * @return false If command was not active
356  */
357 bool RCL_Scheduler_postEvent(RCL_Command_Handle c, RCL_Events e);
358 
359 /** @}
360  */
361 
362 #endif
363