]> rtime.felk.cvut.cz Git - pes-rpp/rpp-simulink.git/blob - rpp/blocks/header.c
Change license to MIT
[pes-rpp/rpp-simulink.git] / rpp / blocks / header.c
1 /* Copyright (C) 2013, 2015 Czech Technical University in Prague
2  *
3  * Authors:
4  *     - Carlos Jenkins <carlos@jenkins.co.cr>
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * File : header.c
28  * Abstract:
29  *     Common header for all RPP S-Functions.
30  *     This file should be included at the beginning of a C-MEX S-Function block
31  *     implementation after defining S_FUNCTION_NAME. It include refactored and
32  *     commonly repeated structures that pollute S-Functions implementations
33  *     (in conjunction with trailer.c). This file include basic includes,
34  *     required definitions, macro definitions and documentation and commented
35  *     prototypes for optional model calls/hooks.
36  *
37  * References:
38  *     mdlInitializeSizes()       : sfunctions.pdf p. 441 [Required]
39  *     mdlInitializeSampleTimes() : sfunctions.pdf p. 436 [Required]
40  *     mdlOutputs()               : sfunctions.pdf p. 447 [Required]
41  *     mdlTerminate()             : sfunctions.pdf p. 493 [Required]
42  *
43  *                          .: S-Function callback methods :.
44  *
45  *                              ***********************
46  *                              * Start of simulation *
47  *                              ***********************
48  *                                         |
49  *                        _               \_/
50  *                       |      +--------------------+
51  *                       |      | mdlInitializeSizes |
52  *                       |      +--------------------+
53  *      Initialization  -|                 |
54  *                       |                \_/
55  *                       |   +--------------------------+
56  *                       |   | mdlInitializeSampleTimes |
57  *                       |_  +--------------------------+
58  *                                         |
59  *                        _______________\ |
60  *                       |               /\_/
61  *                       |          +------------+
62  *      Simulation loop -|          | mdlOutputs |
63  *                       |          +------------+
64  *                       |_________________|
65  *                                         |
66  *                                        \_/
67  *                                 +--------------+
68  *                                 | mdlTerminate |
69  *                                 +--------------+
70  *
71  *     mdlCheckParameters()       : sfunctions.pdf p. 421 [Optional]
72  *     mdlRTW()                   : sfunctions.pdf p. 458 [Optional]
73  *     mdlSetWorkWidths()         : sfunctions.pdf p. 489 [Optional]
74  *     mdlStart()                 : sfunctions.pdf p. 492 [Optional]
75  *
76  *     trailer.c
77  */
78
79
80 #ifndef S_FUNCTION_NAME
81 #error 'Please include this file inside an S-Function implementation.'
82 #endif
83
84 #define S_FUNCTION_LEVEL 2
85
86 #include "config_rm48_hdk.h"
87
88
89 /*
90  * Include C numerics library in order to use floor() and other nice goodies.
91  */
92 #include <math.h>
93
94 /*
95  * Need to include simstruc.h for the definition of the SimStruct and
96  * its associated macro definitions.
97  */
98 #include "simstruc.h"
99 #define EDIT_OK(S, P_IDX) \
100  (!((ssGetSimMode(S)==SS_SIMMODE_SIZES_CALL_ONLY) && mxIsEmpty(ssGetSFcnParam(S, P_IDX))))
101 #define SAMPLE_TIME (ssGetSFcnParam(S, 1))
102
103
104 /* Function: isRealMatrix ======================================================
105  * Abstract:
106  *     Utility function to verify that the mxArray is a real (double) finite
107  *     matrix.
108  */
109 static bool isRealMatrix(const mxArray * const m)
110 {
111     if (mxIsNumeric(m) && mxIsDouble(m) && !mxIsLogical(m) && !mxIsComplex(m) &&
112        !mxIsSparse(m) && !mxIsEmpty(m) && mxGetNumberOfDimensions(m) == 2) {
113
114         const double * const data = mxGetPr(m);
115         const size_t numEl = mxGetNumberOfElements(m);
116         size_t i;
117
118         for (i = 0; i < numEl; i++) {
119             if (!mxIsFinite(data[i])) {
120                 return(false);
121             }
122         }
123
124         return(true);
125
126     } else {
127
128         return(false);
129
130     }
131 }
132
133
134 /* Function: checkSampleTime ===================================================
135  * Abstract:
136  *     Utility function to verify that sample time (for variable sample time
137  *     blocks) is valid.
138  */
139 static bool checkSampleTime(SimStruct* S, int paramNum)
140 {
141     if (EDIT_OK(S, paramNum)) {
142
143         const real_T* sampleTime = NULL;
144         const size_t stArraySize = mxGetM(SAMPLE_TIME) * mxGetN(SAMPLE_TIME);
145
146         /* Sample time must be a real scalar value or 2 element array. */
147         if (isRealMatrix(SAMPLE_TIME) &&
148            (stArraySize == 1 || stArraySize == 2)) {
149
150             sampleTime = (real_T*) mxGetPr(SAMPLE_TIME);
151
152         } else {
153             ssSetErrorStatus(S,
154                 "Invalid sample time. Sample time must be a "
155                 "real scalar value or an array of two real values.");
156             return false;
157         }
158
159         if (sampleTime[0] < 0.0 && sampleTime[0] != -1.0) {
160             ssSetErrorStatus(S,
161                 "Invalid sample time. Period must be non-negative or "
162                 "-1 (for inherited).");
163             return false;
164         }
165
166         if (stArraySize == 2 && sampleTime[0] > 0.0 &&
167            sampleTime[1] >= sampleTime[0]) {
168             ssSetErrorStatus(S,
169                 "Invalid sample time. Offset must be smaller than period.");
170             return false;
171         }
172
173         if (stArraySize == 2 && sampleTime[0] == -1.0 && sampleTime[1] != 0.0) {
174             ssSetErrorStatus(S,
175                 "Invalid sample time. When period is -1, offset must be 0.");
176             return false;
177         }
178
179         if (stArraySize == 2 && sampleTime[0] == 0.0 &&
180            !(sampleTime[1] == 1.0)) {
181             ssSetErrorStatus(S,
182                 "Invalid sample time. When period is 0, offset must be 1.");
183             return false;
184         }
185     }
186     return true;
187 }
188
189
190 /* Function: rppSetNumParams ===================================================
191  * Abstract:
192  *     Utility function to set the number of expected parameters, verify that
193  *     the number of expected parameters is equal to the number of parameters
194  *     entered in the dialog box return, and that the values entered are correct
195  *     (by calling S-Function specific mdlCheckParameters() function).
196  */
197 static void mdlCheckParameters(SimStruct* S);
198 static bool rppSetNumParams(SimStruct* S, int_T numParams)
199 {
200     int i;
201
202     ssSetNumSFcnParams(S, numParams);
203
204     #ifdef MATLAB_MEX_FILE
205     if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
206
207         mdlCheckParameters(S);
208         if (ssGetErrorStatus(S) != NULL) {
209             return false;
210         }
211     } else {
212         /* Return if number of expected != number of actual parameters */
213         return false;
214     }
215     #endif
216
217     /* Set the parameters tunable status */
218     for (i = 0; i < numParams; i++) {
219         ssSetSFcnParamTunable(S, i, false);
220     }
221
222     return true;
223 }
224
225
226 /* Function: rppAddInputPort ===================================================
227  * Abstract:
228  *     Utility function to add an standard single width input port.
229  */
230 static bool rppAddInputPort(SimStruct* S, int_T port, DTypeId type)
231 {
232     ssSetInputPortWidth(S, port, 1);
233     ssSetInputPortDataType(S, port, type);
234     ssSetInputPortComplexSignal(S, port, COMPLEX_NO);
235     ssSetInputPortDirectFeedThrough(S, port, true);
236     ssSetInputPortRequiredContiguous(S, port, true);
237 }
238
239 /* Function: rppAddInputVectorPort ===================================================
240  * Abstract:
241  *     Utility function to add an standard vector width input port.
242  */
243 static bool rppAddInputVectorPort(SimStruct* S, int_T port, DTypeId type, int_T size)
244 {
245     ssSetInputPortWidth(S, port, size);
246     ssSetInputPortDataType(S, port, type);
247     ssSetInputPortComplexSignal(S, port, COMPLEX_NO);
248     ssSetInputPortDirectFeedThrough(S, port, true);
249     ssSetInputPortRequiredContiguous(S, port, true);
250 }
251
252
253 /* Function: rppAddOutputPort ==================================================
254  * Abstract:
255  *     Utility function to add an standard single width output port.
256  */
257 static bool rppAddOutputPort(SimStruct* S, int_T port, DTypeId type)
258 {
259     ssSetOutputPortWidth(S, port, 1);
260     ssSetOutputPortDataType(S, port, type);
261     ssSetOutputPortComplexSignal(S, port, COMPLEX_NO);
262 }
263
264 /* Function: rppAddOutputVectorPort ==================================================
265  * Abstract:
266  *     Utility function to add an standard vector width output port.
267  */
268 static bool rppAddOutputVectorPort(SimStruct* S, int_T port, DTypeId type, int_T size)
269 {
270     ssSetOutputPortWidth(S, port, size);
271     ssSetOutputPortDataType(S, port, type);
272     ssSetOutputPortComplexSignal(S, port, COMPLEX_NO);
273 }
274
275
276 /* Function: rppSetStandardOptions =============================================
277  * Abstract:
278  *     Common / standard options for RPP blocks.
279  */
280 static void rppSetStandardOptions(SimStruct* S)
281 {
282     /* Specify the sim state compliance to be same as a built-in block */
283     ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
284
285     /* Set the number of sample time. */
286     ssSetNumSampleTimes(S, 1);
287
288     /*
289      * All options have the form SS_OPTION_<name> and are documented in
290      * <matlabroot>/simulink/include/simstruc.h. The options should be
291      * combined with bitwise OR as in
292      *   ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2))
293      */
294     ssSetOptions(S,
295         SS_OPTION_WORKS_WITH_CODE_REUSE |
296         SS_OPTION_CAN_BE_CALLED_CONDITIONALLY |
297         /*SS_OPTION_EXCEPTION_FREE_CODE |*/
298         SS_OPTION_USE_TLC_WITH_ACCELERATOR);
299 }
300
301
302 /* Function: rppValidParamRange ================================================
303  * Abstract:
304  *     Validate that given parameter is scalar, numeric and between given range.
305  */
306 static bool rppValidParamRange(SimStruct* S, int_T parIdx, int_T mn, int_T mx)
307 {
308     double num;
309     const mxArray* raw = ssGetSFcnParam(S, parIdx);
310     if (mxGetNumberOfElements(raw) != 1) {
311         ssSetErrorStatus(S, "Parameter to S-function must be a scalar.");
312         return false;
313     }
314
315     if (!mxIsDouble(raw)) {
316         ssSetErrorStatus(S, "Parameter to S-function must be numeric.");
317         return false;
318     }
319
320     num = (mxGetPr(raw))[0];
321     if (floor(num) != num) {
322         /* printf("Num      : %2.6f\n", num); */
323         /* printf("Num floor: %2.6f\n", floor(num)); */
324         ssSetErrorStatus(S, "Parameter to S-function must be an integer.");
325         return false;
326     }
327
328     if ((num < mn) || (num > mx)) {
329         ssSetErrorStatus(S, "Parameter to S-function must be "
330                             "between specified range.");
331         return false;
332     }
333
334     return true;
335 }
336
337
338 /* Function: rppValidParamBoolean ==============================================
339  * Abstract:
340  *     Validate that given parameter is boolean (logical).
341  */
342 static bool rppValidParamBoolean(SimStruct* S, int_T parIdx)
343 {
344     const mxArray* raw = ssGetSFcnParam(S, parIdx);
345     if (!mxIsLogicalScalar(raw)) {
346         ssSetErrorStatus(S, "Parameter to S-function must be a scalar.");
347         return false;
348     }
349
350     return true;
351 }
352
353
354 /*
355  *==============================================================================
356  *=           BEGIN EXAMPLE CODE AND FUNCTIONS DOCUMENTATION                   =
357  *==============================================================================
358  */
359 #ifdef NEVER_DEFINED
360
361
362 /* Function: mdlCheckParameters ================================================
363  * Abstract:
364  *     mdlCheckParameters verifies new parameter settings whenever parameter
365  *     change or are re-evaluated during a simulation. When a simulation is
366  *     running, changes to S-function parameters can occur at any time during
367  *     the simulation loop.
368  *
369  *     See http://www.mathworks.com/help/simulink/sfg/mdlcheckparameters.html
370  */
371 #ifdef MATLAB_MEX_FILE
372 #define MDL_CHECK_PARAMETERS
373 static void mdlCheckParameters(SimStruct* S)
374 {
375     /* Check the parameter 1 */
376     if (!rppValidParamRange(S, 0, 1, 20)) {
377         return;
378     }
379 }
380 #endif
381
382
383 /* Function: mdlRTW ============================================================
384  * Abstract:
385  *     This function is called when the Real-Time Workshop is generating
386  *     the model.rtw file.
387  *
388  *     See http://www.mathworks.com/help/simulink/sfg/mdlrtw.html
389  */
390 #ifdef MATLAB_MEX_FILE
391 #define MDL_RTW
392 static void mdlRTW(SimStruct* S)
393 {
394     UNUSED_PARAMETER(S);
395 }
396 #endif
397
398
399 /* Function: mdlSetWorkWidths ==================================================
400  * Abstract:
401  *     The optional method, mdlSetWorkWidths is called after input port
402  *     width, output port width, and sample times of the S-function have
403  *     been determined to set any state and work vector sizes which are
404  *     a function of the input, output, and/or sample times.
405  *
406  *     Run-time parameters are registered in this method using methods
407  *     ssSetNumRunTimeParams, ssSetRunTimeParamInfo, and related methods.
408  *
409  *     See http://www.mathworks.com/help/simulink/sfg/mdlsetworkwidths.html
410  */
411 #ifdef MATLAB_MEX_FILE
412 #define MDL_SET_WORK_WIDTHS
413 static void mdlSetWorkWidths(SimStruct* S)
414 {
415     /* Set number of run-time parameters */
416     if (!ssSetNumRunTimeParams(S, 1)) {
417         return;
418     }
419
420     /* Register the run-time parameter 1 */
421     ssRegDlgParamAsRunTimeParam(S, 0, 0, "p1", SS_UINT8);
422 }
423 #endif
424
425
426 /* Function: mdlStart ==========================================================
427  * Abstract:
428  *     This function is called once at start of model execution. If you
429  *     have states that should be initialized once, this is the place
430  *     to do it.
431  *
432  *     See http://www.mathworks.com/help/simulink/sfg/mdlstart.html
433  */
434 #define MDL_START
435 static void mdlStart(SimStruct* S)
436 {
437     UNUSED_PARAMETER(S);
438 }
439
440 #endif /* NEVER_DEFINED */