Statistics
| Branch: | Tag: | Revision:

amiro-os / core / src / aos_timer.c @ 1dd7edc7

History | View | Annotate | Download (8.928 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2018  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 <aos_timer.h>
29

    
30
#include <aos_system.h>
31

    
32
/*
33
 * Forward declarations.
34
 */
35
static inline void _setupTimer(aos_timer_t* timer);
36
static inline void _setupPeriodicTimer(aos_periodictimer_t* ptimer);
37
static void _intermediateCb(void* timer);
38
static void _fireCb(void* timer);
39
static void _periodicCb(void* ptimer);
40

    
41
/**
42
 * @brief   Setup a timer according to its configuration.
43
 *
44
 * @param[in] timer   Pointer to the timer to setup.
45
 */
46
static inline void _setupTimer(aos_timer_t* timer)
47
{
48
  aos_timestamp_t uptime;
49

    
50
  // get current system uptime
51
  aosSysGetUptimeX(&uptime);
52

    
53
  // if the wakeup time is more than TIME_IMMEDIATE in the future
54
  if ( (timer->wkuptime > uptime) && ((timer->wkuptime - uptime) > TIME_IMMEDIATE) ) {
55
    // split the time delta if necessary
56
    if ((timer->wkuptime - uptime) > AOS_TIMER_MAX_INTERVAL_US) {
57
      chVTSetI(&(timer->vt), chTimeUS2I(AOS_TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
58
    } else {
59
      chVTSetI(&(timer->vt), chTimeUS2I(timer->wkuptime - uptime), _fireCb, timer);
60
    }
61
  } else {
62
    vtfunc_t fn = timer->callback;
63
    timer->callback = NULL;
64
    fn(timer->cbparam);
65
  }
66

    
67
  return;
68
}
69

    
70
/**
71
 * @brief   Setup a periodic timer according to its configuration.
72
 *
73
 * @param[in] ptimer  Pointer to the periodic timer to setup.
74
 */
75
static inline void _setupPeriodicTimer(aos_periodictimer_t *ptimer)
76
{
77
  // if the periodic timer is being initialized
78
  if (ptimer->timer.wkuptime == 0) {
79
    aos_timestamp_t uptime;
80

    
81
    // get current system uptime
82
    aosSysGetUptimeX(&uptime);
83
    ptimer->timer.wkuptime = uptime + ptimer->interval;
84
  }
85
  // if the peridic timer is reactivated after it has fired
86
  else {
87
    ptimer->timer.wkuptime += ptimer->interval;
88
  }
89

    
90
  // set the callback and parameters
91
  ptimer->timer.callback = _periodicCb;
92
  ptimer->timer.cbparam = ptimer;
93

    
94
  // setup the timer
95
  _setupTimer(&(ptimer->timer));
96

    
97
  return;
98
}
99

    
100
/**
101
 * @brief   Callback function for intermediate interrupts.
102
 * @details This is required if the desired time to fire is too far in the future so that the interval must be split.
103
 *
104
 * @param[in] timer   Pointer to a aos_timer_t to reactivate.
105
 */
106
static void _intermediateCb(void* timer)
107
{
108
  chSysLockFromISR();
109
  _setupTimer((aos_timer_t*)timer);
110
  chSysUnlockFromISR();
111
}
112

    
113
/**
114
 * @brief   Callback function for the final fire event of the timer.
115
 *
116
 * @param[in] timer   Pointer to a aos_timer_t to call its callback.
117
 */
118
static void _fireCb(void *timer)
119
{
120
  chSysLockFromISR();
121
  ((aos_timer_t*)timer)->callback(((aos_timer_t*)timer)->cbparam);
122
  chSysUnlockFromISR();
123
}
124

    
125
/**
126
 * @brief   Callback function for periodic timer interrupts.
127
 * @details This function calls the original callback and reenables the timer afterwards.
128
 *
129
 * @param[in] ptimer  Pointer to a aos_periodictimer_t to reactivate.
130
 */
131
static void _periodicCb(void* ptimer)
132
{
133
  ((aos_periodictimer_t*)ptimer)->callback(((aos_periodictimer_t*)ptimer)->cbparam);
134
  _setupPeriodicTimer((aos_periodictimer_t*)ptimer);
135
}
136

    
137
/**
138
 * @brief   Initialize a aos_timer_t object.
139
 *
140
 * @param[in] timer   The timer to initialize.
141
 */
142
void aosTimerInit(aos_timer_t* timer)
143
{
144
  aosDbgAssert(timer != NULL);
145

    
146
  chVTObjectInit(&(timer->vt));
147
  timer->wkuptime = 0;
148
  timer->callback = NULL;
149
  timer->cbparam = NULL;
150

    
151
  return;
152
}
153

    
154
/**
155
 * @brief   Set timer to fire at an absolute system time.
156
 *
157
 * @param[in] timer   Pointer to the timer to set.
158
 * @param[in] uptime  Pointer to the absolute system time for the timer to fire.
159
 * @param[in] cb      Pointer to a callback function to be called.
160
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
161
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
162
 * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
163
 */
164
void aosTimerSetAbsoluteI(aos_timer_t *timer, aos_timestamp_t *uptime, vtfunc_t cb, void *par)
165
{
166
  aosDbgCheck(timer != NULL);
167
  aosDbgCheck(uptime != NULL);
168
  aosDbgCheck(cb != NULL);
169

    
170
  timer->wkuptime = *uptime;
171
  timer->callback = cb;
172
  timer->cbparam = par;
173
  _setupTimer(timer);
174

    
175
  return;
176
}
177

    
178
/**
179
 * @brief   Set timer to fire after a relative interval.
180
 *
181
 * @param[in] timer   Pointer to the timer to set.
182
 * @param[in] offset  Relative interval to set for the timer to fire.
183
 * @param[in] cb      Pointer to a callback function to be called.
184
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
185
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
186
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
187
 */
188
void aosTimerSetIntervalI(aos_timer_t *timer, aos_interval_t offset, vtfunc_t cb, void *par)
189
{
190
  aosDbgCheck(timer != NULL);
191
  aosDbgCheck(cb != NULL);
192

    
193
  aos_timestamp_t uptime;
194

    
195
  aosSysGetUptimeX(&uptime);
196
  timer->wkuptime = uptime + offset;
197
  timer->callback = cb;
198
  timer->cbparam = par;
199
  _setupTimer(timer);
200

    
201
  return;
202
}
203

    
204
/**
205
 * @brief   Set timer to fire after a long relative interval.
206
 *
207
 * @param[in] timer   Pointer to the timer to set.
208
 * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
209
 * @param[in] cb      Pointer to a callback function to be called.
210
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
211
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
212
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
213
 */
214
void aosTimerSetLongIntervalI(aos_timer_t *timer, aos_longinterval_t *offset, vtfunc_t cb, void *par)
215
{
216
  aosDbgCheck(timer != NULL);
217
  aosDbgCheck(offset != NULL);
218
  aosDbgCheck(cb != NULL);
219

    
220
  aos_timestamp_t uptime;
221

    
222
  aosSysGetUptimeX(&uptime);
223
  timer->wkuptime = uptime + *offset;
224
  timer->callback = cb;
225
  timer->cbparam = par;
226
  _setupTimer(timer);
227

    
228
  return;
229
}
230

    
231
/**
232
 * @brief   Initialize a aos_periodictimer_t object.
233
 *
234
 * @param[in] timer   The periodic timer to initialize.
235
 */
236
void aosPeriodicTimerInit(aos_periodictimer_t *ptimer)
237
{
238
  aosDbgAssert(ptimer != NULL);
239

    
240
  aosTimerInit(&(ptimer->timer));
241
  ptimer->interval = 0;
242

    
243
  return;
244
}
245

    
246
/**
247
 * @brief   Set a periodic timer to fire in the specified interval.
248
 *
249
 * @param[in] ptimer    Pointer to the periodic timer to set.
250
 * @param[in] interval  Interval for the periodic timer to fire,
251
 * @param[in] cb        Pointer to a callback function to be called.
252
 *                      In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
253
 *                      Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
254
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
255
 */
256
void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par)
257
{
258
  aosDbgCheck(ptimer != NULL);
259
  aosDbgCheck(interval > TIME_IMMEDIATE);
260
  aosDbgCheck(cb != NULL);
261

    
262
  ptimer->timer.wkuptime = 0;
263
  ptimer->interval = interval;
264
  ptimer->callback = cb;
265
  ptimer->cbparam = par;
266
  _setupPeriodicTimer(ptimer);
267

    
268
  return;
269
}
270

    
271
/**
272
 * @brief   Set a periodic timer to fire in the specified interval.
273
 *
274
 * @param[in] ptimer    Pointer to the periodic timer to set.
275
 * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
276
 * @param[in] cb        Pointer to a callback function to be called.
277
 *                      In contrast to other callback functions, this get called from an already ISR locked context.
278
 *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
279
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
280
 */
281
void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
282
{
283
  aosDbgCheck(ptimer != NULL);
284
  aosDbgCheck(*interval > TIME_IMMEDIATE);
285
  aosDbgCheck(cb != NULL);
286

    
287
  ptimer->timer.wkuptime = 0;
288
  ptimer->interval = *interval;
289
  ptimer->callback = cb;
290
  ptimer->cbparam = par;
291
  _setupPeriodicTimer(ptimer);
292

    
293
  return;
294
}
295

    
296
/** @} */