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