1 /* Copyright (C) 2013, 2015 Czech Technical University in Prague
4 * - Carlos Jenkins <carlos@jenkins.co.cr>
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
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
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.
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.
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]
43 * .: S-Function callback methods :.
45 * ***********************
46 * * Start of simulation *
47 * ***********************
50 * | +--------------------+
51 * | | mdlInitializeSizes |
52 * | +--------------------+
55 * | +--------------------------+
56 * | | mdlInitializeSampleTimes |
57 * |_ +--------------------------+
62 * Simulation loop -| | mdlOutputs |
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]
80 #ifndef S_FUNCTION_NAME
81 #error 'Please include this file inside an S-Function implementation.'
84 #define S_FUNCTION_LEVEL 2
86 #include "config_rm48_hdk.h"
90 * Include C numerics library in order to use floor() and other nice goodies.
95 * Need to include simstruc.h for the definition of the SimStruct and
96 * its associated macro definitions.
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))
104 /* Function: isRealMatrix ======================================================
106 * Utility function to verify that the mxArray is a real (double) finite
109 static bool isRealMatrix(const mxArray * const m)
111 if (mxIsNumeric(m) && mxIsDouble(m) && !mxIsLogical(m) && !mxIsComplex(m) &&
112 !mxIsSparse(m) && !mxIsEmpty(m) && mxGetNumberOfDimensions(m) == 2) {
114 const double * const data = mxGetPr(m);
115 const size_t numEl = mxGetNumberOfElements(m);
118 for (i = 0; i < numEl; i++) {
119 if (!mxIsFinite(data[i])) {
134 /* Function: checkSampleTime ===================================================
136 * Utility function to verify that sample time (for variable sample time
139 static bool checkSampleTime(SimStruct* S, int paramNum)
141 if (EDIT_OK(S, paramNum)) {
143 const real_T* sampleTime = NULL;
144 const size_t stArraySize = mxGetM(SAMPLE_TIME) * mxGetN(SAMPLE_TIME);
146 /* Sample time must be a real scalar value or 2 element array. */
147 if (isRealMatrix(SAMPLE_TIME) &&
148 (stArraySize == 1 || stArraySize == 2)) {
150 sampleTime = (real_T*) mxGetPr(SAMPLE_TIME);
154 "Invalid sample time. Sample time must be a "
155 "real scalar value or an array of two real values.");
159 if (sampleTime[0] < 0.0 && sampleTime[0] != -1.0) {
161 "Invalid sample time. Period must be non-negative or "
162 "-1 (for inherited).");
166 if (stArraySize == 2 && sampleTime[0] > 0.0 &&
167 sampleTime[1] >= sampleTime[0]) {
169 "Invalid sample time. Offset must be smaller than period.");
173 if (stArraySize == 2 && sampleTime[0] == -1.0 && sampleTime[1] != 0.0) {
175 "Invalid sample time. When period is -1, offset must be 0.");
179 if (stArraySize == 2 && sampleTime[0] == 0.0 &&
180 !(sampleTime[1] == 1.0)) {
182 "Invalid sample time. When period is 0, offset must be 1.");
190 /* Function: rppSetNumParams ===================================================
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).
197 static void mdlCheckParameters(SimStruct* S);
198 static bool rppSetNumParams(SimStruct* S, int_T numParams)
202 ssSetNumSFcnParams(S, numParams);
204 #ifdef MATLAB_MEX_FILE
205 if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
207 mdlCheckParameters(S);
208 if (ssGetErrorStatus(S) != NULL) {
212 /* Return if number of expected != number of actual parameters */
217 /* Set the parameters tunable status */
218 for (i = 0; i < numParams; i++) {
219 ssSetSFcnParamTunable(S, i, false);
226 /* Function: rppAddInputPort ===================================================
228 * Utility function to add an standard single width input port.
230 static bool rppAddInputPort(SimStruct* S, int_T port, DTypeId type)
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);
239 /* Function: rppAddInputVectorPort ===================================================
241 * Utility function to add an standard vector width input port.
243 static bool rppAddInputVectorPort(SimStruct* S, int_T port, DTypeId type, int_T size)
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);
253 /* Function: rppAddOutputPort ==================================================
255 * Utility function to add an standard single width output port.
257 static bool rppAddOutputPort(SimStruct* S, int_T port, DTypeId type)
259 ssSetOutputPortWidth(S, port, 1);
260 ssSetOutputPortDataType(S, port, type);
261 ssSetOutputPortComplexSignal(S, port, COMPLEX_NO);
264 /* Function: rppAddOutputVectorPort ==================================================
266 * Utility function to add an standard vector width output port.
268 static bool rppAddOutputVectorPort(SimStruct* S, int_T port, DTypeId type, int_T size)
270 ssSetOutputPortWidth(S, port, size);
271 ssSetOutputPortDataType(S, port, type);
272 ssSetOutputPortComplexSignal(S, port, COMPLEX_NO);
276 /* Function: rppSetStandardOptions =============================================
278 * Common / standard options for RPP blocks.
280 static void rppSetStandardOptions(SimStruct* S)
282 /* Specify the sim state compliance to be same as a built-in block */
283 ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
285 /* Set the number of sample time. */
286 ssSetNumSampleTimes(S, 1);
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))
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);
302 /* Function: rppValidParamRange ================================================
304 * Validate that given parameter is scalar, numeric and between given range.
306 static bool rppValidParamRange(SimStruct* S, int_T parIdx, int_T mn, int_T mx)
309 const mxArray* raw = ssGetSFcnParam(S, parIdx);
310 if (mxGetNumberOfElements(raw) != 1) {
311 ssSetErrorStatus(S, "Parameter to S-function must be a scalar.");
315 if (!mxIsDouble(raw)) {
316 ssSetErrorStatus(S, "Parameter to S-function must be numeric.");
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.");
328 if ((num < mn) || (num > mx)) {
329 ssSetErrorStatus(S, "Parameter to S-function must be "
330 "between specified range.");
338 /* Function: rppValidParamBoolean ==============================================
340 * Validate that given parameter is boolean (logical).
342 static bool rppValidParamBoolean(SimStruct* S, int_T parIdx)
344 const mxArray* raw = ssGetSFcnParam(S, parIdx);
345 if (!mxIsLogicalScalar(raw)) {
346 ssSetErrorStatus(S, "Parameter to S-function must be a scalar.");
355 *==============================================================================
356 *= BEGIN EXAMPLE CODE AND FUNCTIONS DOCUMENTATION =
357 *==============================================================================
362 /* Function: mdlCheckParameters ================================================
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.
369 * See http://www.mathworks.com/help/simulink/sfg/mdlcheckparameters.html
371 #ifdef MATLAB_MEX_FILE
372 #define MDL_CHECK_PARAMETERS
373 static void mdlCheckParameters(SimStruct* S)
375 /* Check the parameter 1 */
376 if (!rppValidParamRange(S, 0, 1, 20)) {
383 /* Function: mdlRTW ============================================================
385 * This function is called when the Real-Time Workshop is generating
386 * the model.rtw file.
388 * See http://www.mathworks.com/help/simulink/sfg/mdlrtw.html
390 #ifdef MATLAB_MEX_FILE
392 static void mdlRTW(SimStruct* S)
399 /* Function: mdlSetWorkWidths ==================================================
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.
406 * Run-time parameters are registered in this method using methods
407 * ssSetNumRunTimeParams, ssSetRunTimeParamInfo, and related methods.
409 * See http://www.mathworks.com/help/simulink/sfg/mdlsetworkwidths.html
411 #ifdef MATLAB_MEX_FILE
412 #define MDL_SET_WORK_WIDTHS
413 static void mdlSetWorkWidths(SimStruct* S)
415 /* Set number of run-time parameters */
416 if (!ssSetNumRunTimeParams(S, 1)) {
420 /* Register the run-time parameter 1 */
421 ssRegDlgParamAsRunTimeParam(S, 0, 0, "p1", SS_UINT8);
426 /* Function: mdlStart ==========================================================
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
432 * See http://www.mathworks.com/help/simulink/sfg/mdlstart.html
435 static void mdlStart(SimStruct* S)
440 #endif /* NEVER_DEFINED */