4 %% This TLC script generates ert_main.c
7 %% authors: Michal Sojka <sojkam1@fel.cvut.cz>
8 %% Lukas Hamacek <hamacl1@fel.cvut.cz>
10 %% Department of Control Engineering
11 %% Faculty of Electrical Engineering
12 %% Czech Technical University in Prague
15 %% GENERATEDECLARATIONS
16 %% This function generates main function declarations.
19 %assign ::tid01Eq = LibGetTID01EQ()
21 %function generateDeclarations() Output
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 */
34 #include <sys/mman.h> /* For mlockall() */
36 #include "%<modelName>.h" /* Model's header file */
37 #include "rtwtypes.h" /* MathWorks types */
39 #include "ext_work.h" /* External mode header file */
52 # error Must specify a model name. Define MODEL=name.
54 /* create generic macros that work with any model */
55 # define EXPAND_CONCAT(name1,name2) name1 ## name2
56 # define CONCAT(name1,name2) EXPAND_CONCAT(name1,name2)
57 # define MODEL_INITIALIZE CONCAT(MODEL,_initialize)
58 # define MODEL_STEP CONCAT(MODEL,_step)
59 # define MODEL_TERMINATE CONCAT(MODEL,_terminate)
60 # define RT_MDL CONCAT(MODEL,_M)
64 #define STRINGIZE(num) #num
65 #define POS(line) __FILE__ ":" STRINGIZE(line)
66 #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);
67 #define CHECKE(expr) do { if ((expr) == -1) { perror(#expr " at " POS(__LINE__)); exit(1); } } while (0);
70 * Maximal priority used by base rate thread.
72 #define MAX_PRIO (sched_get_priority_min(SCHED_FIFO) + %<numSampleTimes>)
75 * Thread handle of the base rate thread.
76 * Fundamental sample time = %<fundamentalStepSize>s
78 pthread_t base_rate_thread;
81 * Thread handles of and semaphores for sub rate threads. The array
82 * is indexed by TID, i.e. the first one or two elements are unused.
83 %foreach i = numSampleTimes
84 %if i == 0 || i == 1 && tid01Eq
87 %assign s = sampleTime%<i>
88 %assign o = offset%<i>
89 * TID%<i>: sample time = %<s>s, offset = %<o>s
95 } sub_rate[%<numSampleTimes>];
98 * Flag if the simulation has been terminated.
100 int simulationFinished = 0;
103 /* Indication that the base rate thread has started */
104 sem_t ext_mode_ready;
108 %function printfunc() Output
109 /% printf("%s\n", __func__); %/
112 %function generateRtOneStep() Output
113 %foreach j = numSampleTimes - 1
115 %if i == 1 && tid01Eq
118 void *sub_rate%<i>(void *arg)
120 while(!simulationFinished) {
121 sem_wait(&sub_rate[%<i>].sem); /* sem_val = 1 */
123 %<modelName>_step%<i>();
124 sem_wait(&sub_rate[%<i>].sem); /* sem_val = 0 */
133 %% This function generates code of the main function function.
135 %function generateMain() Output
137 * This is the thread function of the base rate loop.
138 * Fundamental sample time = %<fundamentalStepSize>s
140 void * base_rate(void *param_unused)
142 %assign sec = FEVAL("uint32", fundamentalStepSize)
143 %assign nsec = FEVAL("uint32", (fundamentalStepSize - FEVAL("floor", fundamentalStepSize))*1000000000)
144 struct timespec now, next;
145 struct timespec period = { %<sec>, %<nsec> }; /* %<fundamentalStepSize> seconds */
146 boolean_T eventFlags[%<numSampleTimes>]; /* Model has %<numSampleTimes> rates */
147 int_T taskCounter[%<numSampleTimes>] = %<FcnInitializeTaskCounter()>;
148 int_T OverrunFlags[%<numSampleTimes>];
155 %<SLibGenERTExtModeInit()>
156 CHECKE(sem_post(&ext_mode_ready));
159 clock_gettime(CLOCK_MONOTONIC, &next);
161 /* Main loop, running until all the threads are terminated */
162 while(rtmGetErrorStatus(%<modelName>_M) == NULL && !rtmGetStopRequested(%<modelName>_M)) {
164 /* Check subrate overrun, set rates that need to run this time step*/
165 %<LibCallSetEventForThisBaseStep("eventFlags")>\
167 /* Trigger sub-rate threads */
168 %foreach i = numSampleTimes
169 %if i == 0 || i == 1 && tid01Eq
172 %assign s = sampleTime%<i>
173 %assign o = offset%<i>
174 /* Sampling rate %<i>, sample time = %<s>, offset = %<o> */
175 if (eventFlags[%<i>]) {
176 eventFlags[%<i>] = FALSE;
177 sem_getvalue(&sub_rate[%<i>].sem, &step_sem_value);
178 if (step_sem_value) {
179 rtmSetErrorStatus(%<modelName>_M, "Overrun");
180 printf("Sub rate %<i> overrun, sample time=%<s>s, offset=%<o>s is too fast\n");
183 sem_post(&sub_rate[%<i>].sem);
184 sem_post(&sub_rate[%<i>].sem);
188 /* Execute base rate step */
189 %if solverMode == "SingleTasking"
192 %<modelName>_step0();
196 rtExtModeCheckEndTrigger();
200 next.tv_sec += period.tv_sec;
201 next.tv_nsec += period.tv_nsec;
202 if (next.tv_nsec >= 1000000000) {
204 next.tv_nsec -= 1000000000;
206 clock_gettime(CLOCK_MONOTONIC, &now);
207 if (now.tv_sec > next.tv_sec ||
208 (now.tv_sec == next.tv_sec && now.tv_nsec > next.tv_nsec)) {
209 uint32_T usec = (now.tv_sec - next.tv_sec) * 1000000 + (now.tv_nsec - next.tv_nsec)/1000;
210 fprintf(stderr, "Base rate (%<fundamentalStepSize>s) overrun by %d us\n", usec);
215 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
219 simulationFinished = 1;
221 for (i = %<1 + tid01Eq>; i < %<numSampleTimes>; i++) {
222 sem_post(&sub_rate[i].sem);
223 sem_post(&sub_rate[i].sem);
229 * Signal handler for ABORT during simulation
231 void abort_signal_handler(int sig) {
232 fprintf(stderr, "Simulation aborted by pressing CTRL+C\n");
233 rtmSetStopRequested(%<modelName>_M, 1);
237 * This is the main function of the model.
238 * Multirate - Multitasking case main file
240 int_T main(int_T argc, const char_T *argv[])
242 const char_T *errStatus;
245 struct sched_param sched_param;
249 /* rtERTExtModeParseArgs(argc, argv); */
250 rtExtModeParseArgs(argc, argv, NULL);
251 CHECKE(sem_init(&ext_mode_ready, 0, 0));
257 CHECKE(mlockall(MCL_CURRENT | MCL_FUTURE));
259 /* Initialize model */
260 %<modelName>_initialize();
261 simulationFinished = 0;
263 /* Prepare task attributes */
264 CHECK0(pthread_attr_init(&attr));
265 CHECK0(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED));
266 CHECK0(pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
268 %foreach i = numSampleTimes
269 %if i == 0 || i == 1 && tid01Eq
272 %assign s = sampleTime%<i>
273 %assign o = offset%<i>
275 /* Initializing the step semaphore of the loop %<i> */
276 CHECKE(sem_init(&sub_rate[%<i>].sem, 0, 0));
278 /* Starting loop %<i> thread for sample time = %<s>s, offset = %<o>s. */
279 sched_param.sched_priority = MAX_PRIO - %<i>;
280 CHECK0(pthread_attr_setschedparam(&attr, &sched_param));
281 CHECK0(pthread_create(&sub_rate[%<i>].thread, &attr, sub_rate%<i>, (void*)%<i>));
285 /* Starting the base rate thread */
286 sched_param.sched_priority = MAX_PRIO;
287 CHECK0(pthread_attr_setschedparam(&attr, &sched_param));
288 CHECK0(pthread_create(&base_rate_thread, &attr, base_rate, NULL));
289 CHECK0(pthread_attr_destroy(&attr));
293 CHECKE(sem_wait(&ext_mode_ready));
295 signal(SIGINT, abort_signal_handler); /* important for letting the destructor be called. */
297 while(rtmGetErrorStatus(%<modelName>_M) == NULL && !rtmGetStopRequested(%<modelName>_M)) {
298 rtExtModeOneStep(rtmGetRTWExtModeInfo(RT_MDL), NUMST, (boolean_T *)&rtmGetStopRequested(RT_MDL));
299 usleep(%<FEVAL("uint32", fundamentalStepSize * 1000000)>);
303 /* Wait for threads to finish */
304 pthread_join(base_rate_thread, NULL);
305 %foreach i = numSampleTimes
306 %if i == 0 || i == 1 && tid01Eq
309 pthread_join(sub_rate[%<i>].thread, NULL);
313 rtExtModeShutdown(%<numSampleTimes>);
316 /* Terminate model */
317 %<modelName>_terminate();
319 errStatus = rtmGetErrorStatus(%<modelName>_M);
320 if(errStatus != NULL && strcmp(errStatus, "Simulation finished")) {
321 %%printf("%s\n", rtmGetErrorStatus(%<modelName>_M));
322 if(!strcmp(errStatus, "Overrun")) {
323 printf("ISR overrun - sampling rate too fast\n");
330 /* Local Variables: */
331 /* compile-command: "make -f %<modelName>.mk" */