Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (8.734 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
#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
    if ((timer->wkuptime - uptime) > TIMER_MAX_INTERVAL_US) {
48
      chVTSetI(&(timer->vt), US2ST(TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
49
    } else {
50
      chVTSetI(&(timer->vt), US2ST(timer->wkuptime - uptime), _fireCb, timer);
51
    }
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
}