Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.752 KB)

1 e545e620 Thomas Schöpping
/*
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
#include <aos_timer.h>
20
21
#include <aos_system.h>
22
23
/*
24
 * Forward declarations.
25
 */
26
static inline void _setupTimer(aos_timer_t* timer);
27
static inline void _setupPeriodicTimer(aos_periodictimer_t* ptimer);
28
static void _intermediateCb(void* timer);
29
static void _fireCb(void* timer);
30
static void _periodicCb(void* ptimer);
31
32
/**
33
 * @brief   Setup a timer according to its configuration.
34
 *
35
 * @param[in] timer   Pointer to the timer to setup.
36
 */
37
static inline void _setupTimer(aos_timer_t* timer)
38
{
39
  aos_timestamp_t uptime;
40
41
  // get current system uptime
42
  aosSysGetUptimeX(&uptime);
43
44
  // if the wakeup time is more than TIME_IMMEDIATE in the future
45
  if ( (timer->wkuptime > uptime) && ((timer->wkuptime - uptime) > TIME_IMMEDIATE) ) {
46
    // split the time delta if necessary
47 512abac1 Thomas Schöpping
    if ((timer->wkuptime - uptime) > AOS_TIMER_MAX_INTERVAL_US) {
48 1e5f7648 Thomas Schöpping
      chVTSetI(&(timer->vt), chTimeUS2I(AOS_TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
49 e545e620 Thomas Schöpping
    } else {
50 1e5f7648 Thomas Schöpping
      chVTSetI(&(timer->vt), chTimeUS2I(timer->wkuptime - uptime), _fireCb, timer);
51 e545e620 Thomas Schöpping
    }
52
  } else {
53
    vtfunc_t fn = timer->callback;
54
    timer->callback = NULL;
55
    fn(timer->cbparam);
56
  }
57
58
  return;
59
}
60
61
/**
62
 * @brief   Setup a periodic timer according to its configuration.
63
 *
64
 * @param[in] ptimer  Pointer to the periodic timer to setup.
65
 */
66
static inline void _setupPeriodicTimer(aos_periodictimer_t *ptimer)
67
{
68
  // if the periodic timer is being initialized
69
  if (ptimer->timer.wkuptime == 0) {
70
    aos_timestamp_t uptime;
71
72
    // get current system uptime
73
    aosSysGetUptimeX(&uptime);
74
    ptimer->timer.wkuptime = uptime + ptimer->interval;
75
  }
76
  // if the peridic timer is reactivated after it has fired
77
  else {
78
    ptimer->timer.wkuptime += ptimer->interval;
79
  }
80
81
  // set the callback and parameters
82
  ptimer->timer.callback = _periodicCb;
83
  ptimer->timer.cbparam = ptimer;
84
85
  // setup the timer
86
  _setupTimer(&(ptimer->timer));
87
88
  return;
89
}
90
91
/**
92
 * @brief   Callback function for intermediate interrupts.
93
 * @details This is required if the desired time to fire is too far in the future so that the interval must be split.
94
 *
95
 * @param[in] timer   Pointer to a aos_timer_t to reactivate.
96
 */
97
static void _intermediateCb(void* timer)
98
{
99
  chSysLockFromISR();
100
  _setupTimer((aos_timer_t*)timer);
101
  chSysUnlockFromISR();
102
}
103
104
/**
105
 * @brief   Callback function for the final fire event of the timer.
106
 *
107
 * @param[in] timer   Pointer to a aos_timer_t to call its callback.
108
 */
109
static void _fireCb(void *timer)
110
{
111
  chSysLockFromISR();
112
  ((aos_timer_t*)timer)->callback(((aos_timer_t*)timer)->cbparam);
113
  chSysUnlockFromISR();
114
}
115
116
/**
117
 * @brief   Callback function for periodic timer interrupts.
118
 * @details This function calls the original callback and reenables the timer afterwards.
119
 *
120
 * @param[in] ptimer  Pointer to a aos_periodictimer_t to reactivate.
121
 */
122
static void _periodicCb(void* ptimer)
123
{
124
  ((aos_periodictimer_t*)ptimer)->callback(((aos_periodictimer_t*)ptimer)->cbparam);
125
  _setupPeriodicTimer((aos_periodictimer_t*)ptimer);
126
}
127
128
/**
129
 * @brief   Initialize a aos_timer_t object.
130
 *
131
 * @param[in] timer   The timer to initialize.
132
 */
133
void aosTimerInit(aos_timer_t* timer)
134
{
135
  aosDbgAssert(timer != NULL);
136
137
  chVTObjectInit(&(timer->vt));
138
  timer->wkuptime = 0;
139
  timer->callback = NULL;
140
  timer->cbparam = NULL;
141
142
  return;
143
}
144
145
/**
146
 * @brief   Set timer to fire at an absolute system time.
147
 *
148
 * @param[in] timer   Pointer to the timer to set.
149
 * @param[in] uptime  Pointer to the absolute system time for the timer to fire.
150
 * @param[in] cb      Pointer to a callback function to be called.
151
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
152
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
153
 * @param[in] par     Pointer to a parameter fpr the callback function (may be NULL).
154
 */
155
void aosTimerSetAbsoluteI(aos_timer_t *timer, aos_timestamp_t *uptime, vtfunc_t cb, void *par)
156
{
157
  aosDbgCheck(timer != NULL);
158
  aosDbgCheck(uptime != NULL);
159
  aosDbgCheck(cb != NULL);
160
161
  timer->wkuptime = *uptime;
162
  timer->callback = cb;
163
  timer->cbparam = par;
164
  _setupTimer(timer);
165
166
  return;
167
}
168
169
/**
170
 * @brief   Set timer to fire after a relative interval.
171
 *
172
 * @param[in] timer   Pointer to the timer to set.
173
 * @param[in] offset  Relative interval to set for the timer to fire.
174
 * @param[in] cb      Pointer to a callback function to be called.
175
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
176
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
177
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
178
 */
179
void aosTimerSetIntervalI(aos_timer_t *timer, aos_interval_t offset, vtfunc_t cb, void *par)
180
{
181
  aosDbgCheck(timer != NULL);
182
  aosDbgCheck(cb != NULL);
183
184
  aos_timestamp_t uptime;
185
186
  aosSysGetUptimeX(&uptime);
187
  timer->wkuptime = uptime + offset;
188
  timer->callback = cb;
189
  timer->cbparam = par;
190
  _setupTimer(timer);
191
192
  return;
193
}
194
195
/**
196
 * @brief   Set timer to fire after a long relative interval.
197
 *
198
 * @param[in] timer   Pointer to the timer to set.
199
 * @param[in] offset  Pointer to a long interval value to set for the timer to fire.
200
 * @param[in] cb      Pointer to a callback function to be called.
201
 *                    In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
202
 *                    Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
203
 * @param[in] par     Pointer to a parameter for the callback function (may be NULL).
204
 */
205
void aosTimerSetLongIntervalI(aos_timer_t *timer, aos_longinterval_t *offset, vtfunc_t cb, void *par)
206
{
207
  aosDbgCheck(timer != NULL);
208
  aosDbgCheck(offset != NULL);
209
  aosDbgCheck(cb != NULL);
210
211
  aos_timestamp_t uptime;
212
213
  aosSysGetUptimeX(&uptime);
214
  timer->wkuptime = uptime + *offset;
215
  timer->callback = cb;
216
  timer->cbparam = par;
217
  _setupTimer(timer);
218
219
  return;
220
}
221
222
/**
223
 * @brief   Initialize a aos_periodictimer_t object.
224
 *
225
 * @param[in] timer   The periodic timer to initialize.
226
 */
227
void aosPeriodicTimerInit(aos_periodictimer_t *ptimer)
228
{
229
  aosDbgAssert(ptimer != NULL);
230
231
  aosTimerInit(&(ptimer->timer));
232
  ptimer->interval = 0;
233
234
  return;
235
}
236
237
/**
238
 * @brief   Set a periodic timer to fire in the specified interval.
239
 *
240
 * @param[in] ptimer    Pointer to the periodic timer to set.
241
 * @param[in] interval  Interval for the periodic timer to fire,
242
 * @param[in] cb        Pointer to a callback function to be called.
243
 *                      In contrast to ChibiOS callback functions, this gets called from an already ISR locked context.
244
 *                      Thus it may not contain any chSysLockX() or chSysUnlockX() calls and so forth.
245
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
246
 */
247
void aosPeriodicTimerSetI(aos_periodictimer_t* ptimer, aos_interval_t interval, vtfunc_t cb, void* par)
248
{
249
  aosDbgCheck(ptimer != NULL);
250
  aosDbgCheck(interval > TIME_IMMEDIATE);
251
  aosDbgCheck(cb != NULL);
252
253
  ptimer->timer.wkuptime = 0;
254
  ptimer->interval = interval;
255
  ptimer->callback = cb;
256
  ptimer->cbparam = par;
257
  _setupPeriodicTimer(ptimer);
258
259
  return;
260
}
261
262
/**
263
 * @brief   Set a periodic timer to fire in the specified interval.
264
 *
265
 * @param[in] ptimer    Pointer to the periodic timer to set.
266
 * @param[in] interval  Pointer to a long interval value for the periodic timer to fire,
267
 * @param[in] cb        Pointer to a callback function to be called.
268
 *                      In contrast to other callback functions, this get called from an already ISR locked context.
269
 *                      This it may not contain any chSysLockX() or chSysUnlockX() calls.
270
 * @param[in] par       Pointer to a parameter for the callback function (may be NULL).
271
 */
272
void aosPeriodicTimerSetLongI(aos_periodictimer_t* ptimer, aos_longinterval_t* interval, vtfunc_t cb, void* par)
273
{
274
  aosDbgCheck(ptimer != NULL);
275
  aosDbgCheck(*interval > TIME_IMMEDIATE);
276
  aosDbgCheck(cb != NULL);
277
278
  ptimer->timer.wkuptime = 0;
279
  ptimer->interval = *interval;
280
  ptimer->callback = cb;
281
  ptimer->cbparam = par;
282
  _setupPeriodicTimer(ptimer);
283
284
  return;
285
}