]> rtime.felk.cvut.cz Git - arc.git/blob - system/EcuM/EcuM_Main.c
EcuM: Added more on the statemachine
[arc.git] / system / EcuM / EcuM_Main.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 //lint -emacro(904,VALIDATE,VALIDATE_RV,VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).\r
17 \r
18 #include "Std_Types.h"\r
19 #include "EcuM.h"\r
20 #include "EcuM_Generated_Types.h"\r
21 #include "EcuM_Internals.h"\r
22 \r
23 #if defined(USE_DEM)\r
24 #include "Dem.h"\r
25 #endif\r
26 #if defined(USE_NVM)\r
27 #include "NvM.h"\r
28 #endif\r
29 \r
30 static uint32 internal_data_run_state_timeout = 0;\r
31 #if defined(USE_NVM)\r
32 static uint32 internal_data_go_off_one_state_timeout = 0;\r
33 static NvM_RequestResultType writeAllResult;\r
34 #endif\r
35 \r
36 static uint32 internal_data_go_sleep_state_timeout = 0;\r
37 \r
38 #ifdef CFG_ECUM_USE_SERVICE_COMPONENT\r
39 /** @req EcuM2749 */\r
40 static Rte_ModeType_EcuM_Mode currentMode;\r
41 \r
42 void set_current_state(EcuM_StateType state) {\r
43         /* Update the state */\r
44         internal_data.current_state = state;\r
45 \r
46         Rte_ModeType_EcuM_Mode newMode = currentMode;\r
47         switch( state ) {\r
48         case ECUM_STATE_WAKEUP:\r
49         case ECUM_STATE_WAKEUP_ONE:\r
50         case ECUM_STATE_WAKEUP_VALIDATION:\r
51         case ECUM_STATE_WAKEUP_REACTION:\r
52         case ECUM_STATE_WAKEUP_TWO:\r
53         case ECUM_STATE_SLEEP:\r
54         case ECUM_STATE_SHUTDOWN:\r
55                 newMode = RTE_MODE_EcuM_Mode_SLEEP;\r
56                 break;\r
57         case ECUM_STATE_GO_SLEEP:\r
58                 if( internal_data.shutdown_target == ECUM_STATE_SLEEP ) {\r
59                         newMode = RTE_MODE_EcuM_Mode_SLEEP; /** @req EcuM2752 */\r
60                 }\r
61                 break;\r
62         case ECUM_STATE_GO_OFF_ONE:\r
63         case ECUM_STATE_GO_OFF_TWO:\r
64                 newMode = RTE_MODE_EcuM_Mode_SHUTDOWN;\r
65                 break;\r
66         case ECUM_STATE_WAKEUP_TTII:\r
67                 if( internal_data.shutdown_target == ECUM_STATE_SLEEP ) {\r
68                         newMode = RTE_MODE_EcuM_Mode_WAKE_SLEEP; /** @req EcuM2752 */\r
69                 }\r
70                 break;\r
71         case ECUM_STATE_PREP_SHUTDOWN:\r
72         case ECUM_STATE_APP_POST_RUN: /* Assuming this is same as RUN_III */\r
73                 newMode = RTE_MODE_EcuM_Mode_POST_RUN;\r
74                 break;\r
75         case ECUM_STATE_APP_RUN: /* Assuming this is same as RUN_II */\r
76                 newMode = RTE_MODE_EcuM_Mode_RUN;\r
77                 break;\r
78         case ECUM_STATE_STARTUP_TWO:\r
79                 newMode = RTE_MODE_EcuM_Mode_STARTUP;\r
80                 break;\r
81         default:\r
82                 /* Do nothing */\r
83                 break;\r
84         }\r
85 \r
86         if( newMode != currentMode ) {\r
87                 currentMode = newMode;\r
88                 Rte_Switch_EcuM_CurrentMode_currentMode(currentMode); /** @req EcuM2750 */\r
89         }\r
90 }\r
91 #endif\r
92 \r
93 \r
94 /**\r
95  * RUN II entry\r
96  * - Called from EcuM_StartupTwo()\r
97  * - Called from\r
98  *\r
99  *\r
100  */\r
101 void EcuM_enter_run_mode(void){\r
102         set_current_state(ECUM_STATE_APP_RUN);\r
103         EcuM_OnEnterRun(); /** @req EcuM2308 */\r
104 \r
105 #if defined(USE_WDGM)\r
106         /* This seems strange, should be in FW instead */\r
107         WdgM_SetMode(TODO_MODE);\r
108 #endif\r
109 \r
110 #if defined(USE_COMM)\r
111         /*\r
112          * Loop over all channels that have requested run,\r
113          * ie EcuM_ComM_RequestRUN()\r
114          */\r
115         {\r
116                 uint32 cMask = internal_data.run_comm_requests;\r
117                 uint8  channel;\r
118 \r
119                 for (; cMask; cMask &= ~(1ul << channel)) {\r
120                         channel = ilog2(cMask);\r
121                         ComM_EcuM_RunModeIndication(channel);\r
122                 }\r
123         }\r
124 #endif\r
125 \r
126         /* We have a configurable minimum time (EcuMRunMinimumDuration)\r
127          * we have to stay in RUN state  */\r
128         internal_data_run_state_timeout = internal_data.config->EcuMRunMinimumDuration / ECUM_MAIN_FUNCTION_PERIOD; /** @req EcuM2310 */\r
129 }\r
130 \r
131 \r
132 //--------- Local functions ------------------------------------------------------------------------------------------------\r
133 \r
134 \r
135 \r
136 /**\r
137  * Enter GO SLEEP state ( soon in state ECUM_STATE_GO_SLEEP)\r
138  */\r
139 static inline void enter_go_sleep_mode(void){\r
140         EcuM_WakeupSourceType wakeupSource;\r
141         set_current_state(ECUM_STATE_GO_SLEEP);\r
142 \r
143         EcuM_OnGoSleep();\r
144 \r
145 #if defined(USE_NVM)\r
146         NvM_WriteAll();\r
147 \r
148         /* Start timer */\r
149         internal_data_go_sleep_state_timeout = internal_data.config->EcuMNvramWriteAllTimeout / ECUM_MAIN_FUNCTION_PERIOD;\r
150 \r
151         wakeupSource = EcuM_GetPendingWakeupEvents();\r
152 #else\r
153         wakeupSource = EcuM_GetPendingWakeupEvents();\r
154 #endif\r
155 }\r
156 \r
157 /**\r
158   In GO SLEEP state (in state ECUM_STATE_GO_SLEEP)\r
159  */\r
160 static void in_state_goSleep( void ) {\r
161 \r
162         /* We only wait for NvM_WriteAll() for so long */\r
163         if (internal_data_go_sleep_state_timeout){\r
164                 internal_data_go_sleep_state_timeout--;\r
165         }\r
166 \r
167         if( (internal_data_go_sleep_state_timeout == 0) ) {\r
168                 /*\r
169                  * We should go to sleep , enable source that should wake us\r
170                  * */\r
171                 uint32 cMask;\r
172                 uint8  source;\r
173                 const EcuM_SleepModeType *sleepModePtr;\r
174 \r
175                 /* Get the current sleep mode */\r
176 \r
177                 sleepModePtr = &internal_data.config->EcuMSleepModeConfig[internal_data.sleep_mode];\r
178 \r
179                 cMask = sleepModePtr->EcuMWakeupSourceMask;\r
180 \r
181                 /* Loop over the WKSOURCE for this sleep mode */\r
182                 for (; cMask; cMask &= ~(1ul << source)) {\r
183                         source = ilog2(cMask);\r
184                         /* @req 3.1.5/ECUM2389 */\r
185                         EcuM_EnableWakeupSources( 1<< source );\r
186 \r
187 #if defined(WDGM)\r
188                         WdgM_SetMode(sleepModePtr->EcuMSleepModeWdgMMode);\r
189 #endif\r
190 \r
191                         /* Let no one else run */\r
192                         GetResource(RES_SCHEDULER);\r
193                 }\r
194 \r
195         } else if( EcuM_GetPendingWakeupEvents() != 0 ) {\r
196                 /* We have pending wakeup events, need to startup again */\r
197 #if defined(USE_NVM)\r
198                 NvM_CancelWriteAll();\r
199 #endif\r
200         }\r
201 }\r
202 \r
203 \r
204 /**\r
205  * In "Sleep Sequence I"  (in state ECUM_STATE_SLEEP)\r
206  */\r
207 static void in_state_sleep ( void ) {\r
208         const EcuM_SleepModeType *sleepModePtr;\r
209         sleepModePtr = &internal_data.config->EcuMSleepModeConfig[internal_data.sleep_mode];\r
210 \r
211         EcuM_GenerateRamHash();\r
212 \r
213         Mcu_SetMode(sleepModePtr->EcuMSleepModeMcuMode);\r
214 \r
215         /* @req 3.1.5/ECUM2863 */\r
216         if( EcuM_CheckRamHash() == 0) {\r
217 #if defined(USE_DEM)\r
218                 //\r
219                 EcuM_ErrorHook(ECUM_E_RAM_CHECK_FAILED);\r
220 #endif\r
221         }\r
222 \r
223         set_current_state(ECUM_STATE_WAKEUP_ONE);\r
224 }\r
225 \r
226 static inline void enter_go_off_one_mode(void){\r
227         set_current_state(ECUM_STATE_GO_OFF_ONE);\r
228         EcuM_OnGoOffOne();\r
229 \r
230 #if defined(USE_COMM)\r
231         ComM_DeInit();\r
232 #endif\r
233 \r
234 #if defined(USE_NVM)\r
235 \r
236         // Start NvM_WriteAll and timeout timer\r
237         NvM_WriteAll();\r
238 \r
239         internal_data_go_off_one_state_timeout = internal_data.config->EcuMNvramWriteAllTimeout / ECUM_MAIN_FUNCTION_PERIOD;\r
240 #endif\r
241 }\r
242 \r
243 \r
244 static inline boolean hasRunRequests(void){\r
245         uint32 result = internal_data.run_requests;\r
246 \r
247 #if defined(USE_COMM)\r
248         result |= internal_data.run_comm_requests;\r
249 #endif\r
250 \r
251         return (result != 0);\r
252 }\r
253 \r
254 static inline boolean hasPostRunRequests(void){\r
255         return (internal_data.postrun_requests != 0);\r
256 }\r
257 \r
258 \r
259 /**\r
260  * RUN II Loop (in state ECUM_STATE_APP_RUN)\r
261  * - The entry to RUN II is done in\r
262  */\r
263 static inline void in_state_appRun(void){\r
264         if (internal_data_run_state_timeout){\r
265                 internal_data_run_state_timeout--;\r
266         }\r
267 \r
268         if ((!hasRunRequests()) && (internal_data_run_state_timeout == 0)){\r
269                 EcuM_OnExitRun();       /** @req EcuM2865 */\r
270 \r
271 #if defined(USE_WDGM)\r
272                 WdgM_SetMode(FIXME_MODE);\r
273 #endif\r
274 \r
275 #if defined(USE_RTE) && defined(CFG_ECUM_USE_SERVICE_COMPONENT)\r
276                 Rte_Switch_currentMode_currentMode(RTE_MODE_EcuM_Mode_POSTRUN);\r
277 #endif\r
278 \r
279                 set_current_state(ECUM_STATE_APP_POST_RUN);/** @req EcuM2865 */\r
280         }\r
281 }\r
282 \r
283 \r
284 /**\r
285  * RUN III states (in state ECUM_STATE_APP_POST_RUN)\r
286  */\r
287 static inline void in_state_appPostRun(void){\r
288 \r
289         /* @req 3.1.5/ECUM2866 */\r
290         if (hasRunRequests()){\r
291                 /* We have run requests, return to RUN II */\r
292                 EcuM_enter_run_mode();\r
293 \r
294         } else if (!hasPostRunRequests()){\r
295                 EcuM_OnExitPostRun(); /** @req EcuM2761 */\r
296                 set_current_state(ECUM_STATE_PREP_SHUTDOWN);/** @req EcuM2761 */\r
297         } else {\r
298                 /* TODO: We have postrun requests */\r
299         }\r
300 }\r
301 \r
302 \r
303 /**\r
304  * PREP SHUTDOWN state (in state ECUM_STATE_PREP_SHUTDOWN)\r
305  */\r
306 static inline void in_state_prepShutdown(void){\r
307 \r
308         // TODO: The specification does not state what events to clear\r
309         EcuM_ClearWakeupEvent(ECUM_WKSTATUS_NONE);\r
310 \r
311         EcuM_OnPrepShutdown();\r
312 \r
313 #if defined(USE_DEM)\r
314         // DEM shutdown\r
315         Dem_Shutdown();\r
316 #endif\r
317 \r
318         // Switch shutdown mode\r
319         switch(internal_data.shutdown_target){\r
320                 //If in state Off or Reset go into Go_Off_One:\r
321                 case ECUM_STATE_OFF:\r
322                 case ECUM_STATE_RESET:\r
323                         enter_go_off_one_mode();\r
324                         break;\r
325                 case ECUM_STATE_SLEEP:\r
326                         enter_go_sleep_mode();\r
327                         break;\r
328                 default:\r
329                         //TODO: Report error.\r
330                         break;\r
331         }\r
332 }\r
333 \r
334 static inline void in_state_goOffOne(void){\r
335 #if defined(USE_NVM)\r
336                 if (internal_data_go_off_one_state_timeout){\r
337                         internal_data_go_off_one_state_timeout--;\r
338                 }\r
339                 // Wait for the NVM job (NvmWriteAll) to terminate\r
340                 NvM_GetErrorStatus(0, &writeAllResult);\r
341                 if ((writeAllResult != NVM_REQ_PENDING) || (internal_data_go_off_one_state_timeout == 0)){\r
342                         ShutdownOS(E_OK);\r
343                 }\r
344 #else\r
345                 ShutdownOS(E_OK);\r
346 #endif\r
347 }\r
348 \r
349 \r
350 //----- MAIN -----------------------------------------------------------------------------------------------------------------\r
351 void EcuM_MainFunction(void){\r
352         EcuM_WakeupSourceType wMask;\r
353 \r
354         VALIDATE_NO_RV(internal_data.initiated, ECUM_MAINFUNCTION_ID, ECUM_E_NOT_INITIATED);\r
355 \r
356         switch(internal_data.current_state){\r
357 \r
358                 case ECUM_STATE_APP_RUN:\r
359                         /* RUN II state */\r
360                         in_state_appRun();\r
361                         break;\r
362                 case ECUM_STATE_APP_POST_RUN:\r
363                         /* RUN III state */\r
364                         in_state_appPostRun();\r
365                         break;\r
366                 case ECUM_STATE_PREP_SHUTDOWN:\r
367                         in_state_prepShutdown();\r
368                         break;\r
369                 case ECUM_STATE_GO_OFF_ONE:\r
370                         in_state_goOffOne();\r
371                         break;\r
372                 case ECUM_STATE_GO_SLEEP:\r
373                         in_state_goSleep();\r
374                         break;\r
375                 case ECUM_STATE_SLEEP:\r
376                         in_state_sleep();\r
377                         break;\r
378                 case ECUM_STATE_WAKEUP_ONE:\r
379                 {\r
380                         /* TODO: we must have a normal RUN mode.. can't find any\r
381                          * in the A3.1.5 spec. */\r
382                         Mcu_SetMode(MCU_MODE_NORMAL);\r
383 \r
384 #if defined(USE_WDGM)\r
385                         WdgM_SetMode(FIXME_MODE);\r
386 #endif\r
387 \r
388                         wMask = EcuM_GetPendingWakeupEvents();\r
389 \r
390                         EcuM_DisableWakeupSources(wMask);\r
391 \r
392                         EcuM_AL_DriverRestart();\r
393 \r
394                         ReleaseResource(RES_SCHEDULER);\r
395 \r
396                         set_current_state(ECUM_STATE_WAKEUP_VALIDATION);\r
397 \r
398                         break;\r
399                 }\r
400 \r
401                 case ECUM_STATE_WAKEUP_VALIDATION:\r
402                 {\r
403                         wMask = EcuM_GetPendingWakeupEvents();\r
404 \r
405                         EcuM_StartWakeupSources(wMask);\r
406 \r
407                         EcuM_CheckValidation( wMask );\r
408 \r
409                         // TODO:\r
410                         // ComM_EcuM_WakeupIndication( network handle )\r
411 \r
412                         set_current_state(ECUM_STATE_WAKEUP_REACTION);\r
413                         break;\r
414                 }\r
415 \r
416                 case ECUM_STATE_WAKEUP_REACTION:\r
417                 {\r
418                         /*\r
419                          * At this stage we want to know how to react to the wakeup, e.g. go\r
420                          * back to RUN or SHUTDOWN, etc.\r
421                          */\r
422                         EcuM_WakeupReactionType wReaction;\r
423 \r
424                         wMask = EcuM_GetValidatedWakeupEvents();\r
425 \r
426                         /* TODO: We have skipped the TTII timer here */\r
427 \r
428                         /* If the wakeup mask here is != 0 we have a validated wakeup event ->\r
429                          * go back to RUN */\r
430                         wReaction = ( 0 == wMask ) ? ECUM_WKACT_SHUTDOWN : ECUM_WKACT_RUN;\r
431                         wReaction = EcuM_OnWakeupReaction(wReaction);\r
432 \r
433                         if( wReaction == ECUM_WKACT_RUN) {\r
434                                 set_current_state(ECUM_STATE_WAKEUP_TWO);\r
435                         } else {\r
436                                 /* From figure 28 it seems that we should go to SHUTDOWN/GO SLEEP) again from wakeup\r
437                                  * not going up to RUN/RUN II state again. */\r
438                                 set_current_state(ECUM_STATE_GO_SLEEP);\r
439                         }\r
440                         break;\r
441                 }\r
442 \r
443                 case ECUM_STATE_WAKEUP_TWO:\r
444 #if defined(USE_DEM)\r
445                         Dem_Init();\r
446 #endif\r
447                         set_current_state(ECUM_STATE_RUN);\r
448                         break;\r
449 \r
450                 default:\r
451                         //TODO: Report error.\r
452                         break;\r
453         }\r
454 }\r