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