]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/alarm.c
More application changes
[arc.git] / system / kernel / alarm.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 #include <assert.h>\r
17 #include <stdlib.h>\r
18 #include "Os.h"\r
19 #include "application.h"\r
20 #include "internal.h"\r
21 #include "alarm_i.h"\r
22 #include "sys.h"\r
23 \r
24 #if (OS_ALARM_CNT!=0)\r
25 #define COUNTER_MAX(x)                  (x)->counter->alarm_base.maxallowedvalue\r
26 #define COUNTER_MIN_CYCLE(x)    (x)->counter->alarm_base.mincycle\r
27 #define ALARM_CHECK_ID(x)                               \\r
28         if( (x) > OS_ALARM_CNT) { \\r
29                 rv = E_OS_ID;                                   \\r
30                 goto err;                                               \\r
31         }\r
32 \r
33 \r
34 /**\r
35  * The system service  GetAlarmBase  reads the alarm base\r
36  * characteristics. The return value <Info> is a structure in which\r
37  * the information of data type AlarmBaseType is stored.\r
38  *\r
39  * @param alarm_id  Reference to alarm\r
40  * @param info Reference to structure with constants of the alarm base.\r
41  * @return\r
42  */\r
43 StatusType GetAlarmBase( AlarmType AlarmId, AlarmBaseRefType Info ) {\r
44     StatusType rv = Os_AlarmGetBase(AlarmId,Info);\r
45     if (rv != E_OK) {\r
46         goto err;\r
47     }\r
48     OS_STD_END_2(OSServiceId_GetAlarmBase,AlarmId, Info);\r
49 }\r
50 \r
51 \r
52 /**\r
53  * The system service GetAlarm returns the relative value in ticks\r
54  * before the alarm <AlarmID> expires.\r
55 \r
56  * @param AlarmId       Reference to an alarm\r
57  * @param Tick[out]     Relative value in ticks before the alarm <AlarmID> expires.\r
58  * @return\r
59  */\r
60 StatusType GetAlarm(AlarmType AlarmId, TickRefType Tick) {\r
61     StatusType rv = E_OK;\r
62     OsAlarmType *aPtr;\r
63     long flags;\r
64 \r
65     ALARM_CHECK_ID(AlarmId);\r
66     aPtr = Os_AlarmGet(AlarmId);\r
67 \r
68         Irq_Save(flags);\r
69         if( aPtr->active == 0 ) {\r
70                 rv = E_OS_NOFUNC;\r
71                 Irq_Restore(flags);\r
72                 goto err;\r
73         }\r
74 \r
75         *Tick = Os_CounterDiff(         aPtr->expire_val,\r
76                                                                 Os_CounterGetValue(aPtr->counter),\r
77                                                                 Os_CounterGetMaxValue(aPtr->counter) );\r
78 \r
79         Irq_Restore(flags);\r
80 \r
81         OS_STD_END_2(OSServiceId_GetAlarm,AlarmId, Tick);\r
82 }\r
83 \r
84 \r
85 \r
86 \r
87 /**\r
88  * The system service occupies the alarm <AlarmID> element.\r
89  * After <increment> ticks have elapsed, the task assigned to the\r
90  * alarm <AlarmID> is activated or the assigned event (only for\r
91  * extended tasks) is set or the alarm-callback routine is called.\r
92  *\r
93  * @param alarm_id Reference to the alarm element\r
94  * @param increment Relative value in ticks\r
95  * @param cycle Cycle value in case of cyclic alarm. In case of single alarms, cycle shall be zero.\r
96  * @return\r
97  */\r
98 \r
99 StatusType SetRelAlarm(AlarmType AlarmId, TickType Increment, TickType Cycle){\r
100         StatusType rv = E_OK;\r
101         OsAlarmType *aPtr;\r
102 \r
103         ALARM_CHECK_ID(AlarmId);\r
104 \r
105         aPtr = Os_AlarmGet(AlarmId);\r
106 \r
107         OS_DEBUG(D_ALARM,"SetRelAlarm id:%d inc:%u cycle:%u\n",\r
108                                         AlarmId,\r
109                                         (unsigned)Increment,\r
110                                         (unsigned)Cycle);\r
111 \r
112 #if     (OS_APPLICATION_CNT > 1)\r
113 \r
114         rv = Os_ApplHaveAccess( Os_AlarmGet(AlarmId)->accessingApplMask );\r
115         if( rv != E_OK ) {\r
116                 goto err;\r
117         }\r
118 \r
119 #endif\r
120 \r
121         if( (Increment == 0) || (Increment > COUNTER_MAX(aPtr)) ) {\r
122                 /** @req OS304 */\r
123                 rv =  E_OS_VALUE;\r
124                 goto err;\r
125         } else {\r
126                 if( Cycle != 0 &&\r
127                         ( (Cycle < COUNTER_MIN_CYCLE(aPtr)) ||\r
128                           (Cycle > COUNTER_MAX(aPtr)) ) ) {\r
129                         /** @req OS304 */\r
130                         rv =  E_OS_VALUE;\r
131                         goto err;\r
132                 }\r
133         }\r
134 \r
135         {\r
136                 Irq_Disable();\r
137                 if( aPtr->active == 1 ) {\r
138                         Irq_Enable();\r
139                         rv = E_OS_STATE;\r
140                         goto err;\r
141                 }\r
142 \r
143                 aPtr->active = 1;\r
144 \r
145                 aPtr->expire_val = Os_CounterAdd(\r
146                                                                 Os_CounterGetValue(aPtr->counter),\r
147                                                                 COUNTER_MAX(aPtr),\r
148                                                                 Increment);\r
149                 aPtr->cycletime = Cycle;\r
150 \r
151                 Irq_Enable();\r
152                 OS_DEBUG(D_ALARM,"  expire:%u cycle:%u\n",\r
153                                 (unsigned)aPtr->expire_val,\r
154                                 (unsigned)aPtr->cycletime);\r
155         }\r
156 \r
157         OS_STD_END_3(OSServiceId_SetRelAlarm,AlarmId, Increment, Cycle);\r
158 }\r
159
160 /**
161  * The  system  service  occupies  the  alarm  <AlarmID>  element.
162  * When <start> ticks are reached, the task assigned to the alarm
163  *
164  * If the absolute value <start> is very close to the current counter
165  * value, the alarm may expire, and the task may become ready or
166  * the  alarm-callback  may  be  called  before  the  system  service
167  * returns to the user.
168  * If  the  absolute  value  <start>  already  was  reached  before  the
169  * system call, the alarm shall only expire when the absolute value
170  * <start>  is  reached  again,  i.e.  after  the  next  overrun  of  the
171  * counter.
172  *
173  * If <cycle> is unequal zero, the alarm element is logged on again
174  * immediately after expiry with the relative value <cycle>.
175  *
176  * The alarm <AlarmID> shall not already be in use.
177  * To  change  values  of  alarms  already  in  use  the  alarm  shall  be
178  * cancelled first.
179  *
180  * If  the  alarm  is  already  in  use,  this  call  will  be  ignored  and  the
181  * error E_OS_STATE is returned.
182  *
183  * Allowed on task level and in ISR, but not in hook routines.
184  *
185  * @param AlarmId
186  * @param Start
187  * @param Cycle
188  * @return
189  */
190 \r
191 StatusType SetAbsAlarm(AlarmType AlarmId, TickType Start, TickType Cycle) {\r
192 \r
193         OsAlarmType *aPtr;\r
194         long flags;\r
195         StatusType rv = E_OK;\r
196 \r
197         ALARM_CHECK_ID(AlarmId);\r
198 \r
199         aPtr = Os_AlarmGet(AlarmId);\r
200 \r
201 #if     (OS_APPLICATION_CNT > 1)\r
202 \r
203         rv = Os_ApplHaveAccess( aPtr->accessingApplMask );\r
204         if( rv != E_OK ) {\r
205                 goto err;\r
206         }\r
207 \r
208 #endif\r
209 \r
210         if( Start > COUNTER_MAX(aPtr) ) {\r
211                 /** @req OS304 */\r
212                 rv =  E_OS_VALUE;\r
213                 goto err;\r
214         }\r
215 \r
216         if( Cycle != 0 &&\r
217                 ( (Cycle < COUNTER_MIN_CYCLE(aPtr)) ||\r
218                   (Cycle > COUNTER_MAX(aPtr)) ) ) {\r
219                 /** @req OS304 */\r
220                 rv =  E_OS_VALUE;\r
221                 goto err;\r
222         }\r
223 \r
224         Irq_Save(flags);\r
225         if( aPtr->active == 1 ) {\r
226                 rv = E_OS_STATE;
227                 Irq_Restore(flags);\r
228                 goto err;\r
229         }\r
230 \r
231         aPtr->active = 1;\r
232 \r
233         aPtr->expire_val = Start;\r
234         aPtr->cycletime = Cycle;\r
235 \r
236         Irq_Restore(flags);\r
237 \r
238         OS_DEBUG(D_ALARM,"  expire:%u cycle:%u\n",\r
239                                         (unsigned)aPtr->expire_val,\r
240                                         (unsigned)aPtr->cycletime);\r
241 \r
242         OS_STD_END_3(OSServiceId_SetAbsAlarm,AlarmId, Start, Cycle);\r
243 }\r
244 \r
245 StatusType CancelAlarm(AlarmType AlarmId) {\r
246         StatusType rv = E_OK;\r
247         OsAlarmType *aPtr;\r
248         long flags;\r
249 \r
250         ALARM_CHECK_ID(AlarmId);\r
251 \r
252         aPtr = Os_AlarmGet(AlarmId);\r
253 \r
254         Irq_Save(flags);\r
255         if( aPtr->active == 0 ) {\r
256                 rv = E_OS_NOFUNC;\r
257                 Irq_Restore(flags);\r
258                 goto err;\r
259         }\r
260 \r
261         aPtr->active = 0;\r
262 \r
263         Irq_Restore(flags);\r
264 \r
265         OS_STD_END_1(OSServiceId_CancelAlarm,AlarmId);\r
266 }\r
267 \r
268 \r
269 \r
270 /**\r
271  *\r
272  * @param a_obj\r
273  */\r
274 static void AlarmProcess( OsAlarmType *aPtr ) {\r
275         if( aPtr->cycletime == 0 ) {\r
276                 aPtr->active = 0;\r
277         } else {\r
278                 // Calc new expire value..\r
279                 aPtr->expire_val = Os_CounterAdd( Os_CounterGetValue(aPtr->counter),\r
280                                                                                         Os_CounterGetMaxValue(aPtr->counter),\r
281                                                                                         aPtr->cycletime);\r
282         }\r
283 }\r
284 \r
285 void Os_AlarmCheck( OsCounterType *c_p ) {\r
286         OsAlarmType *a_obj;\r
287         StatusType rv;\r
288 \r
289         SLIST_FOREACH(a_obj,&c_p->alarm_head,alarm_list) {\r
290                 if( a_obj->active && (c_p->val == a_obj->expire_val) ) {\r
291                         /* Check if the alarms have expired */\r
292                         OS_DEBUG(D_ALARM,"expired %s id:%u val:%u\n",\r
293                                                                                         a_obj->name,\r
294                                                                                         (unsigned)a_obj->counter_id,\r
295                                                                                         (unsigned)a_obj->expire_val);\r
296 \r
297                         switch( a_obj->action.type ) {\r
298                         case ALARM_ACTION_ACTIVATETASK:\r
299                                 if( ActivateTask(a_obj->action.task_id) != E_OK ) {\r
300                                         /* We actually do thing here, See 0S321 */\r
301                                 }\r
302                                 AlarmProcess(a_obj);\r
303                                 break;\r
304                         case ALARM_ACTION_SETEVENT:\r
305                                 rv =  SetEvent(a_obj->action.task_id,a_obj->action.event_id);\r
306                                 if( rv != E_OK ) {\r
307                                         ERRORHOOK(rv);\r
308                                 }\r
309                                 AlarmProcess(a_obj);\r
310                                 break;\r
311                         case ALARM_ACTION_ALARMCALLBACK:\r
312                                 /* TODO: not done */\r
313                                 break;\r
314 \r
315                         case ALARM_ACTION_INCREMENTCOUNTER:\r
316                                 /** @req OS301 */\r
317                                 /* Huh,, recursive....*/\r
318                                 IncrementCounter(a_obj->action.counter_id);\r
319                                 break;\r
320                         default:\r
321                                 assert(0);\r
322                         }\r
323                 }\r
324         }\r
325 }\r
326 \r
327 void Os_AlarmAutostart(void) {\r
328         int j;\r
329         for (j = 0; j < OS_ALARM_CNT; j++) {\r
330                 OsAlarmType *alarmPtr;\r
331                 alarmPtr = Os_AlarmGet(j);\r
332                 if (alarmPtr->autostartPtr != NULL) {\r
333                         const OsAlarmAutostartType *autoPtr = alarmPtr->autostartPtr;\r
334 \r
335                         if (Os_Sys.appMode & autoPtr->appModeRef) {\r
336                                 if (autoPtr->autostartType == ALARM_AUTOSTART_ABSOLUTE) {\r
337                                         SetAbsAlarm(j, autoPtr->alarmTime, autoPtr->cycleTime);\r
338                                 } else {\r
339                                         SetRelAlarm(j, autoPtr->alarmTime, autoPtr->cycleTime);\r
340                                 }\r
341                         }\r
342                 }\r
343         }\r
344 }\r
345 #endif\r
346 \r
347 \r