Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_timer.c @ ad02f035

History | View | Annotate | Download (10.198 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
/**
20
 * @file    aos_timer.c
21
 * @brief   Timer code.
22
 * @details Implementation of aos_timer_t and aos_periodictimer_t functions.
23
 *
24
 * @addtogroup aos_timers
25
 * @{
26
 */
27

    
28
#include <amiroos.h>
29

    
30
/******************************************************************************/
31
/* LOCAL DEFINITIONS                                                          */
32
/******************************************************************************/
33

    
34
/******************************************************************************/
35
/* EXPORTED VARIABLES                                                         */
36
/******************************************************************************/
37

    
38
/******************************************************************************/
39
/* LOCAL TYPES                                                                */
40
/******************************************************************************/
41

    
42
/******************************************************************************/
43
/* LOCAL VARIABLES                                                            */
44
/******************************************************************************/
45

    
46
/******************************************************************************/
47
/* LOCAL FUNCTIONS                                                            */
48
/******************************************************************************/
49

    
50
/*
51
 * forward declarations
52
 */
53
static void _intermediateCb(void* timer);
54
static void _fireCb(void *timer);
55
static void _periodicCb(void* ptimer);
56

    
57
/**
58
 * @brief   Setup a timer according to its configuration.
59
 *
60
 * @param[in] timer   Pointer to the timer to setup.
61
 */
62
static void _setupTimer(aos_timer_t* timer)
63
{
64
  aos_timestamp_t uptime;
65

    
66
  // get current system uptime
67
  aosSysGetUptimeX(&uptime);
68

    
69
  // if the wakeup time is more than TIME_IMMEDIATE in the future
70
  if ( (timer->wkuptime > uptime) && ((timer->wkuptime - uptime) > TIME_IMMEDIATE) ) {
71
    // split the time delta if necessary
72
    if ((timer->wkuptime - uptime) > AOS_TIMER_MAX_INTERVAL_US) {
73
      chVTSetI(&(timer->vt), chTimeUS2I(AOS_TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
74
    } else {
75
      chVTSetI(&(timer->vt), chTimeUS2I(timer->wkuptime - uptime), _fireCb, timer);
76
    }
77
  } else {
78
    vtfunc_t fn = timer->callback;
79
    timer->callback = NULL;
80
    fn(timer->cbparam);
81
  }
82

    
83
  return;
84
}
85

    
86
/**
87
 * @brief   Setup a periodic timer according to its configuration.
88
 *
89
 * @param[in] ptimer  Pointer to the periodic timer to setup.
90
 */
91
static void _setupPeriodicTimer(aos_periodictimer_t *ptimer)
92
{
93
  // if the periodic timer is being initialized
94
  if (ptimer->timer.wkuptime == 0) {
95
    aos_timestamp_t uptime;
96

    
97
    // get current system uptime
98
    aosSysGetUptimeX(&uptime);
99
    ptimer->timer.wkuptime = uptime + ptimer->interval;
100
  }
101
  // if the peridic timer is reactivated after it has fired
102
  else {
103
    ptimer->timer.wkuptime += ptimer->interval;
104
  }
105

    
106
  // set the callback and parameters
107
  ptimer->timer.callback = _periodicCb;
108
  ptimer->timer.cbparam = ptimer;
109

    
110
  // setup the timer
111
  _setupTimer(&(ptimer->timer));
112

    
113
  return;
114
}
115

    
116
/**
117
 * @brief   Callback function for intermediate interrupts.
118
 * @details This is required if the desired time to fire is too far in the future so that the interval must be split.
119
 *
120
 * @param[in] timer   Pointer to a aos_timer_t to reactivate.
121
 */
122
static void _intermediateCb(void* timer)
123
{
124
  chSysLockFromISR();
125
  _setupTimer((aos_timer_t*)timer);
126
  chSysUnlockFromISR();
127
}
128

    
129
/**
130
 * @brief   Callback function for the final fire event of the timer.
131
 *
132
 * @param[in] timer   Pointer to a aos_timer_t to call its callback.
133
 */
134
static void _fireCb(void *timer)
135
{
136
  chSysLockFromISR();
137
  ((aos_timer_t*)timer)->callback(((aos_timer_t*)timer)->cbparam);
138
  chSysUnlockFromISR();
139
}
140

    
141
/**
142
 * @brief   Callback function for periodic timer interrupts.
143
 * @details This function calls the original callback and reenables the timer afterwards.
144
 *
145
 * @param[in] ptimer  Pointer to a aos_periodictimer_t to reactivate.
146
 */
147
static void _periodicCb(void* ptimer)
148
{
149
  ((aos_periodictimer_t*)ptimer)->callback(((aos_periodictimer_t*)ptimer)->cbparam);
150
  _setupPeriodicTimer((aos_periodictimer_t*)ptimer);
151
}
152

    
153
/******************************************************************************/
154
/* EXPORTED FUNCTIONS                                                         */
155
/******************************************************************************/
156

    
157
/**
158
 * @brief   Initialize a aos_timer_t object.
159
 *
160
 * @param[in] timer   The timer to initialize.
161
 */
162
void aosTimerInit(aos_timer_t* timer)
163
{
164
  aosDbgAssert(timer != NULL);
165

    
166
  chVTObjectInit(&(timer->vt));
167
  timer->wkuptime = 0;
168
  timer->callback = NULL;
169
  timer->cbparam = NULL;
170

    
171
  return;
172
}
173

    
174
/**
175
 * @brief   Set timer to fire at an absolute system time.
176
 *
177
 * @param[in] timer   Pointer to the timer to set.
178
 * @param[in] uptime  Pointer to the absolute system time for the timer to fire.
179
 * @param[in] cb      Pointer to a callback function to be called.
180
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
181
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
182
 * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
183
 */
184
void aosTimerSetAbsoluteI(aos_timer_t *timer, aos_timestamp_t *uptime, vtfunc_t cb, void *par)
185
{
186
  aosDbgCheck(timer != NULL);
187
  aosDbgCheck(uptime != NULL);
188
  aosDbgCheck(cb != NULL);
189

    
190
  timer->wkuptime = *uptime;
191
  timer->callback = cb;
192
  timer->cbparam = par;
193
  _setupTimer(timer);
194

    
195
  return;
196
}
197

    
198
/**
199
 * @brief   Set timer to fire after a relative interval.
200
 *
201
 * @param[in] timer   Pointer to the timer to set.
202
 * @param[in] offset  Relative interval to set for the timer to fire.
203
 * @param[in] cb      Pointer to a callback function to be called.
204
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
205
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
206
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
207
 */
208
void aosTimerSetIntervalI(aos_timer_t *timer, aos_interval_t offset, vtfunc_t cb, void *par)
209
{
210
  aosDbgCheck(timer != NULL);
211
  aosDbgCheck(cb != NULL);
212

    
213
  aos_timestamp_t uptime;
214

    
215
  aosSysGetUptimeX(&uptime);
216
  timer->wkuptime = uptime + offset;
217
  timer->callback = cb;
218
  timer->cbparam = par;
219
  _setupTimer(timer);
220

    
221
  return;
222
}
223

    
224
/**
225
 * @brief   Set timer to fire after a long relative interval.
226
 *
227
 * @param[in] timer   Pointer to the timer to set.
228
 * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
229
 * @param[in] cb      Pointer to a callback function to be called.
230
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
231
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
232
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
233
 */
234
void aosTimerSetLongIntervalI(aos_timer_t *timer, aos_longinterval_t *offset, vtfunc_t cb, void *par)
235
{
236
  aosDbgCheck(timer != NULL);
237
  aosDbgCheck(offset != NULL);
238
  aosDbgCheck(cb != NULL);
239

    
240
  aos_timestamp_t uptime;
241

    
242
  aosSysGetUptimeX(&uptime);
243
  timer->wkuptime = uptime + *offset;
244
  timer->callback = cb;
245
  timer->cbparam = par;
246
  _setupTimer(timer);
247

    
248
  return;
249
}
250

    
251
/**
252
 * @brief   Initialize a aos_periodictimer_t object.
253
 *
254
 * @param[in] timer   The periodic timer to initialize.
255
 */
256
void aosPeriodicTimerInit(aos_periodictimer_t *ptimer)
257
{
258
  aosDbgAssert(ptimer != NULL);
259

    
260
  aosTimerInit(&(ptimer->timer));
261
  ptimer->interval = 0;
262

    
263
  return;
264
}
265

    
266
/**
267
 * @brief   Set a periodic timer to fire in the specified interval.
268
 *
269
 * @param[in] ptimer    Pointer to the periodic timer to set.
270
 * @param[in] interval  Interval for the periodic timer to fire,
271
 * @param[in] cb        Pointer to a callback function to be called.
272
 *                      In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
273
 *                      Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
274
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
275
 */
276
void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par)
277
{
278
  aosDbgCheck(ptimer != NULL);
279
  aosDbgCheck(interval > TIME_IMMEDIATE);
280
  aosDbgCheck(cb != NULL);
281

    
282
  ptimer->timer.wkuptime = 0;
283
  ptimer->interval = interval;
284
  ptimer->callback = cb;
285
  ptimer->cbparam = par;
286
  _setupPeriodicTimer(ptimer);
287

    
288
  return;
289
}
290

    
291
/**
292
 * @brief   Set a periodic timer to fire in the specified interval.
293
 *
294
 * @param[in] ptimer    Pointer to the periodic timer to set.
295
 * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
296
 * @param[in] cb        Pointer to a callback function to be called.
297
 *                      In contrast to other callback functions, this get called from an already ISR locked context.
298
 *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
299
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
300
 */
301
void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
302
{
303
  aosDbgCheck(ptimer != NULL);
304
  aosDbgCheck(*interval > TIME_IMMEDIATE);
305
  aosDbgCheck(cb != NULL);
306

    
307
  ptimer->timer.wkuptime = 0;
308
  ptimer->interval = *interval;
309
  ptimer->callback = cb;
310
  ptimer->cbparam = par;
311
  _setupPeriodicTimer(ptimer);
312

    
313
  return;
314
}
315

    
316
/** @} */