]> rtime.felk.cvut.cz Git - ert_linux.git/blob - ert_linux/ert_linux_multitasking_main.tlc
a934620862fefd3aca78f62de04c2073c3c8b317
[ert_linux.git] / ert_linux / ert_linux_multitasking_main.tlc
1 %%\r
2 %% linux_ert_target_multitasking_main.tlc\r
3 %%\r
4 %% description:\r
5 %%  This TLC script generates ert_main for multi-rate / multi-tasking\r
6 %%  case.\r
7 %%\r
8 %% date: 3nd Feb 2009\r
9 %%\r
10 %% author: Lukas Hamacek, Michal Sojka\r
11 %% e-mail: hamacl1@fel.cvut.cz\r
12 %% Department of Control Engineering\r
13 %% Faculty of Electrical Engineering\r
14 %% Czech Technical University in Prague\r
15 %%\r
16 %% modifications:\r
17 %%  2009/2/3 - Lukas Hamacek\r
18 %%      creation of the file\r
19 %%\r
20 \r
21 %% GENERATEDECLARATIONS\r
22 %%  This function generates main function declarations.\r
23 %%\r
24 \r
25 %assign ::tid01Eq = LibGetTID01EQ()\r
26 \r
27 %function generateDeclarations() Output\r
28 \r
29   /* Multirate - Multitasking case main file */\r
30   #define _BSD_SOURCE                    /* For usleep() */\r
31   #define _POSIX_C_SOURCE 200112L        /* For clock_gettime() & clock_nanosleep() */\r
32   #include <stdio.h>                     /* This ert_main.c example uses printf/fflush */\r
33   #include <pthread.h>                   /* Thread library header file */\r
34   #include <sched.h>                     /* OS scheduler header file */\r
35   #include <semaphore.h>                 /* Semaphores library header file */\r
36   #include <time.h>\r
37   #include <stdlib.h>\r
38   #include <unistd.h>\r
39   #include "%<modelName>.h"              /* Model's header file */\r
40   #include "rtwtypes.h"                  /* MathWorks types */\r
41   %if extMode == 1\r
42     #include "ext_work.h"                  /* External mode header file */\r
43   %endif\r
44 \r
45   /*==================*\r
46    * Required defines *\r
47    *==================*/\r
48 \r
49   #ifndef MODEL\r
50   # error Must specify a model name.  Define MODEL=name.\r
51   #else\r
52   /* create generic macros that work with any model */\r
53   # define EXPAND_CONCAT(name1,name2) name1 ## name2\r
54   # define CONCAT(name1,name2) EXPAND_CONCAT(name1,name2)\r
55   # define MODEL_INITIALIZE CONCAT(MODEL,_initialize)\r
56   # define MODEL_STEP       CONCAT(MODEL,_step)\r
57   # define MODEL_TERMINATE  CONCAT(MODEL,_terminate)\r
58   # define RT_MDL           CONCAT(MODEL,_M)\r
59   #endif\r
60 \r
61   /* Error checking */\r
62   #define STRINGIZE(num) #num\r
63   #define POS(line) __FILE__ ":" STRINGIZE(line)\r
64   #define CHECK0(expr) do { int __err = (expr); if (__err) { fprintf(stderr, "Error: %s returned '%s' at " POS(__LINE__) "\n", #expr, strerror(__err)); exit(1); } } while (0);\r
65   #define CHECKE(expr) do { if ((expr) == -1) { perror(#expr " at " POS(__LINE__)); exit(1); } } while (0);\r
66 \r
67   /**\r
68    * Maximal priority used by base rate thread.\r
69    */\r
70   #define MAX_PRIO (sched_get_priority_min(SCHED_FIFO) + %<numSampleTimes>)\r
71 \r
72   /**\r
73    * Thread handle of the base rate thread.\r
74    * Fundamental sample time = %<fundamentalStepSize>s\r
75    */\r
76   pthread_t base_rate_thread;\r
77 \r
78   /**\r
79    * Thread handles of and semaphores for sub rate threads. The array\r
80    * is indexed by TID, i.e. the first one or two elements are unused.\r
81   %foreach i = numSampleTimes\r
82       %if i == 0 || i == 1 && tid01Eq\r
83       %continue\r
84     %endif\r
85     %assign s = sampleTime%<i>\r
86     %assign o = offset%<i>\r
87    * TID%<i>: sample time = %<s>s, offset = %<o>s\r
88   %endforeach\r
89    */\r
90   struct sub_rate {\r
91   pthread_t thread;\r
92   sem_t     sem;\r
93   } sub_rate[%<numSampleTimes>];\r
94 \r
95   /**\r
96    * Flag if the simulation has been terminated.\r
97    */\r
98   int simulationFinished = 0;\r
99 \r
100 %endfunction\r
101 \r
102 %function printfunc() Output\r
103   /% printf("%s\n", __func__); %/\r
104 %endfunction\r
105 \r
106 %function generateRtOneStep() Output\r
107   %foreach j = numSampleTimes - 1\r
108     %assign i = j + 1\r
109     %if i == 1 && tid01Eq\r
110       %continue\r
111     %endif\r
112     void *sub_rate%<i>(void *arg)\r
113     {\r
114       while(!simulationFinished) {\r
115         sem_wait(&sub_rate[%<i>].sem);    /* sem_val = 1 */\r
116         %<printfunc()>\r
117         %<modelName>_step%<i>();\r
118         sem_wait(&sub_rate[%<i>].sem);    /* sem_val = 0 */\r
119       }\r
120     }\r
121   %endforeach\r
122 %endfunction\r
123 \r
124 \r
125 %% GENERATEMAIN\r
126 %%  This function generates code of the main function function.\r
127 %%\r
128 %function generateMain() Output\r
129   /**\r
130    * This is the thread function of the base rate loop.\r
131    * Fundamental sample time = %<fundamentalStepSize>s\r
132    */\r
133   void * base_rate()\r
134   {\r
135     %assign  sec = FEVAL("uint32", fundamentalStepSize)\r
136     %assign nsec = FEVAL("uint32", (fundamentalStepSize - FEVAL("floor", fundamentalStepSize))*1000000000)\r
137     struct timespec now, next;\r
138     struct timespec period = { %<sec>, %<nsec> }; /* %<fundamentalStepSize> seconds */\r
139     boolean_T eventFlags[%<numSampleTimes>];             /* Model has %<numSampleTimes> rates */\r
140     int_T taskCounter[%<numSampleTimes>] = %<FcnInitializeTaskCounter()>;\r
141     int_T OverrunFlags[%<numSampleTimes>];\r
142     int step_sem_value;\r
143     int_T i;\r
144 \r
145     %if extMode == 1\r
146       %<SLibGenERTExtModeInit()>\r
147     %endif\r
148 \r
149     clock_gettime(CLOCK_MONOTONIC, &next);\r
150 \r
151     /* Main loop, running until all the threads are terminated */\r
152     while(rtmGetErrorStatus(%<modelName>_M) == NULL && !rtmGetStopRequested(%<modelName>_M)) {\r
153       %<printfunc()>\r
154       /* Check subrate overrun, set rates that need to run this time step*/\r
155       %<LibCallSetEventForThisBaseStep("eventFlags")>\\r
156 \r
157       /* Trigger sub-rate threads */\r
158       %foreach i = numSampleTimes\r
159         %if i == 0 || i == 1 && tid01Eq\r
160           %continue\r
161         %endif\r
162         %assign s = sampleTime%<i>\r
163         %assign o = offset%<i>\r
164         /* Sampling rate %<i>, sample time = %<s>, offset = %<o> */\r
165         if (eventFlags[%<i>]) {\r
166           eventFlags[%<i>] = FALSE;\r
167           sem_getvalue(&sub_rate[%<i>].sem, &step_sem_value);\r
168           if (step_sem_value) {\r
169             rtmSetErrorStatus(%<modelName>_M, "Overrun");\r
170             printf("Sub rate %<i> overrun, sample time=%<s>s, offset=%<o>s is too fast\n");\r
171             break;\r
172           }\r
173           sem_post(&sub_rate[%<i>].sem);\r
174           sem_post(&sub_rate[%<i>].sem);\r
175         }\r
176       %endforeach\r
177 \r
178       /* Execute base rate step */\r
179       %if solverMode == "SingleTasking"\r
180         %<modelName>_step();\r
181       %else\r
182         %<modelName>_step0();\r
183       %endif\r
184 \r
185       %if extMode == 1\r
186         rtExtModeCheckEndTrigger();\r
187       %endif\r
188 \r
189       do {\r
190         next.tv_sec += period.tv_sec;\r
191         next.tv_nsec += period.tv_nsec;\r
192         if (next.tv_nsec >= 1000000000) {\r
193           next.tv_sec++;\r
194           next.tv_nsec -= 1000000000;\r
195         }\r
196         clock_gettime(CLOCK_MONOTONIC, &now);\r
197         if (now.tv_sec > next.tv_sec ||\r
198             (now.tv_sec == next.tv_sec && now.tv_nsec > next.tv_nsec)) {\r
199           uint32_T usec = (now.tv_sec - next.tv_sec) * 1000000 + (now.tv_nsec - next.tv_nsec)/1000;\r
200           fprintf(stderr, "Base rate (%<fundamentalStepSize>s) overrun by %d us\n", usec);\r
201           next = now;\r
202           continue;\r
203         }\r
204       } while (0);\r
205       clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);\r
206 \r
207     }\r
208 \r
209     simulationFinished = 1;\r
210     /* Final step */\r
211     for (i = %<1 + tid01Eq>; i < %<numSampleTimes>; i++) {\r
212       sem_post(&sub_rate[i].sem);\r
213       sem_post(&sub_rate[i].sem);\r
214     }\r
215   }\r
216 \r
217   /**\r
218    * This is the main function of the model.\r
219    * Multirate - Multitasking case main file\r
220    */\r
221   int_T main(int_T argc, const char_T *argv[])\r
222   {\r
223     const char_T *errStatus;\r
224     int_T i;\r
225     pthread_attr_t attr;\r
226     struct sched_param sched_param;\r
227 \r
228     %if extMode == 1\r
229       /* External mode */\r
230       rtERTExtModeParseArgs(argc, argv);\r
231     %else\r
232       (void)(argc);\r
233       (void *)(argv);\r
234     %endif\r
235 \r
236     /* Initialize model */\r
237     %<modelName>_initialize();\r
238     simulationFinished = 0;\r
239 \r
240     /* Prepare task attributes */\r
241     CHECK0(pthread_attr_init(&attr));\r
242     CHECK0(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED));\r
243     CHECK0(pthread_attr_setschedpolicy(&attr, SCHED_FIFO));\r
244 \r
245     %foreach i = numSampleTimes\r
246       %if i == 0 || i == 1 && tid01Eq\r
247         %continue\r
248       %endif\r
249       %assign s = sampleTime%<i>\r
250       %assign o = offset%<i>\r
251 \r
252       /* Initializing the step semaphore of the loop %<i> */\r
253       CHECKE(sem_init(&sub_rate[%<i>].sem, 0, 0));\r
254 \r
255       /* Starting loop %<i> thread for sample time = %<s>s, offset = %<o>s. */\r
256       sched_param.sched_priority = MAX_PRIO - %<i>;\r
257       CHECK0(pthread_attr_setschedparam(&attr, &sched_param));\r
258       CHECK0(pthread_create(&sub_rate[%<i>].thread, &attr, sub_rate%<i>, (void*)%<i>));\r
259 \r
260     %endforeach\r
261 \r
262     /* Starting the base rate thread */\r
263     sched_param.sched_priority = MAX_PRIO;\r
264     CHECK0(pthread_attr_setschedparam(&attr, &sched_param));\r
265     CHECK0(pthread_create(&base_rate_thread, &attr, base_rate, NULL));\r
266     CHECK0(pthread_attr_destroy(&attr));\r
267 \r
268     %if extMode == 1\r
269       /* External mode */\r
270       while(rtmGetErrorStatus(%<modelName>_M) == NULL && !rtmGetStopRequested(%<modelName>_M)) {\r
271         rtExtModeOneStep(rtmGetRTWExtModeInfo(RT_MDL), NUMST, (boolean_T *)&rtmGetStopRequested(RT_MDL));\r
272         usleep(%<FEVAL("uint32", fundamentalStepSize * 1000000)>);\r
273       }\r
274     %endif\r
275 \r
276     /* Wait for threads to finish */\r
277     pthread_join(base_rate_thread, NULL);\r
278     %foreach i = numSampleTimes\r
279       %if i == 0 || i == 1 && tid01Eq\r
280         %continue\r
281       %endif\r
282       pthread_join(sub_rate[%<i>].thread, NULL);\r
283     %endforeach\r
284 \r
285     %if extMode == 1\r
286       rtExtModeShutdown(%<numSampleTimes>);\r
287     %endif\r
288 \r
289     /* Terminate model */\r
290     %<modelName>_terminate();\r
291 \r
292     errStatus = rtmGetErrorStatus(%<modelName>_M);\r
293     if(errStatus != NULL && strcmp(errStatus, "Simulation finished")) {\r
294       %%printf("%s\n", rtmGetErrorStatus(%<modelName>_M));\r
295       if(!strcmp(errStatus, "Overrun")) {\r
296         printf("ISR overrun - sampling rate too fast\n");\r
297       }\r
298       return(1);\r
299     }\r
300     return 0;\r
301   }\r
302 \r
303 /* Local Variables: */\r
304 /* compile-command: "make -f %<modelName>.mk" */\r
305 /* End: */\r
306 \r
307 %endfunction\r