## Elementary Work Vectors

### Description of Elementary Work Vector

In addition to DWork vectors, the Simulink^{®} software provides
a simplified set of work vectors. In some S-functions, these elementary
work vectors can provide an easier solution than using DWork vectors:

**IWork vectors**store integer data.**Mode vectors**model zero crossings or other features that require a single mode vector.**PWork vectors**store pointers to data structures, such as those that interface the S-function to legacy code, another software application, or a hardware application.**RWork vectors**store floating-point (real) data.

### Relationship to DWork Vectors

The following table compares each type of work vector to a DWork vector.

Work Vector Type | Comparison to DWork Vector | How to create equivalent DWork vector |
---|---|---|

IWork | IWork vectors cannot be customized in the generated code. Also, you are allowed only one IWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_INT8); |

Mode | Mode vectors require more memory than DWork vectors since the
mode vector is always stored with an `integer` data
type. Also, you are allowed only one Mode vector. | ssSetNumDWork(S,1); ssSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_MODE); ssSetDWorkDataType(S, 0, SS_INT8); |

PWork | Unlike DWork vectors, PWork vectors cannot be named in the generated code. Also, you are allowed only one PWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_POINTER); |

RWork | RWork vectors cannot be customized in the generated code. Also, you are allowed only one RWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_DOUBLE); |

### Using Elementary Work Vectors

The process for using elementary work vectors is similar to that for DWork vectors (see Using DWork Vectors in C MEX S-Functions.) The elementary work vectors have fewer properties, so the initialization process is simpler. However, if you need to generate code for the S-function, the S-function becomes more involved than when using DWork vectors.

The following steps show how to set up and use elementary work vectors. See Additional Work Vector Macros for a list of macros related to each step in the following process.

In

`mdlInitializeSizes`

, specify the size of the work vectors using the`ssSetNum`

macro, for example:Work`X`

ssSetNumPWork(S, 2);

This macro indicates how many elements the work vector contains, however, the Simulink engine does not allocate memory, at this time.

An S-function can defer specifying the length of the work vectors until all information about the S-function inputs is available by passing the value

`DYNAMICALLY_SIZED`

to the`ssSetNum`

macro. If an S-function defers specifying the length of the work vectors inWork`X`

`mdlInitializeSizes`

, it must provide a`mdlSetWorkWidths`

method to set up the work vectors.**Note**If an S-function uses

`mdlSetWorkWidths`

, all work vectors used in the S-function must be set to`DYNAMICALLY_SIZED`

in`mdlInitializeSizes`

, even if the exact value is known before`mdlInitializeSizes`

is called. The sizes to be used by the S-function are than specified in`mdlSetWorkWidths`

.For an example, see

`sfun_dynsize.c`

.In

`mdlStart`

, assign values to the work vectors that are initialized only at the start of the simulation. Use the`ssGet`

macro to retrieve a pointer to each work vector and use the pointer to initialize the work vector values. Alternatively, use theWork`X`

`ssGet`

to assign values to particular elements of the work vector.WorkValues`X`

The Simulink engine calls the

`mdlStart`

method once at the beginning of the simulation. Before calling this method, the engine allocates memory for the work vectors. Do not use the`mdlStart`

method for data that needs to be reinitialized over the course of the simulation, for example, data that needs to be reinitialized when an enabled subsystem containing the S-function is enabled.In

`mdlInitializeConditions`

, initialize the values of any work vectors that might need to be reinitialized at certain points in the simulation. The engine executes`mdlInitializeConditions`

at the beginning of the simulation and any time an enabled subsystem containing the S-function is reenabled.In

`mdlOutputs`

,`mdlUpdate`

, etc., use the`ssGet`

macro to retrieve a pointer to the work vector and use the pointer to access or update the work vector values.Work`X`

Write an

`mdlRTW`

method to allow the Target Language Compiler (TLC) to access the work vector. This step is not necessary if the S-function uses DWork vectors. For information on writing parameter data in an`mdlRTW`

method, see`ssWriteRTWParamSettings`

. For more information on generating code using an`mdlRTW`

method, see Write Fully Inlined S-Functions with mdlRTW Routine (Simulink Coder).

### Additional Work Vector Macros

Macro | Description |
---|---|

`ssSetNumRWork` | Specify the width of the real work vector. |

`ssGetNumRWork` | Query the width of the real work vector. |

`ssSetNumIWork` | Specify the width of the integer work vector. |

`ssGetNumIWork` | Query the width of the integer work vector. |

`ssSetNumPWork` | Specify the width of the pointer work vector. |

`ssGetNumPWork` | Query the width of the pointer work vector. |

`ssSetNumModes` | Specify the width of the mode work vector. |

`ssGetNumModes` | Query the width of the mode work vector. |

`ssGetIWork` | Get a pointer to the integer work vector. |

`ssGetIWorkValue` | Get an element of the integer work vector. |

`ssGetModeVector` | Get a pointer to the mode work vector. |

`ssGetModeVectorValue` | Get an element of the mode work vector. |

`ssGetPWork` | Get a pointer to the pointer work vector. |

`ssGetPworkValue` | Get one element from the pointer work vector. |

`ssGetRWork` | Get a pointer to the floating-point work vector. |

`ssGetRWorkValue` | Get an element of the floating-point work vector. |

`ssSetIWorkValue` | Set the value of one element of the integer work vector. |

`ssSetModeVectorValue` | Set the value of one element of the mode work vector. |

`ssSetPWorkValue` | Set the value of one element of the pointer work vector. |

`ssSetRWorkValue` | Set the value of one element of the floating-point work vector. |

### Elementary Work Vector Examples

The following sections provide examples of the four types of elementary work vectors.

#### Pointer Work Vector

This example opens a file and stores the `FILE`

pointer
in the pointer work vector.

The following statement, included in the `mdlInitializeSizes`

function,
indicates that the pointer work vector is to contain one element.

ssSetNumPWork(S, 1) /* pointer-work vector */

The following code uses the pointer work vector to store a `FILE`

pointer,
returned from the standard I/O function `fopen`

.

#define MDL_START /* Change to #undef to remove function. */ #if defined(MDL_START) static void mdlStart(real_T *x0, SimStruct *S) { FILE *fPtr; void **PWork = ssGetPWork(S); fPtr = fopen("file.data", "r"); PWork[0] = fPtr; } #endif /* MDL_START */

The following code retrieves the `FILE`

pointer
from the pointer work vector and passes it to `fclose`

in
order to close the file.

static void mdlTerminate(SimStruct *S) { if (ssGetPWork(S) != NULL) { FILE *fPtr; fPtr = (FILE *) ssGetPWorkValue(S,0); if (fPtr != NULL) { fclose(fPtr); } ssSetPWorkValue(S,0,NULL); } }

**Note**

Although the Simulink engine handles deallocating the PWork
vector, the `mdlTerminate`

method must always free
the memory stored in the PWork vector.

#### Real and Integer Work Vectors

The S-function `stvctf.c`

uses
RWork and IWork vectors to model a time-varying continuous transfer
function. For a description of this S-function, see the example Discontinuities in Continuous States.

#### Mode Vector

The following example implements a switch block using a mode
work vector. The `mdlInitializeSizes`

method configures
two input ports with direct feedthrough and one output port. The mode
vector element indicates if the signal from the first or second input
port is propagated to the output. The S-function uses one S-function
parameter and a corresponding run-time parameter to store the mode
value and allow the switch to be toggled during simulation.

static void mdlInitializeSizes(SimStruct *S) { /* Initialize one S-function parameter to toggle the mode value */ ssSetNumSFcnParams(S, 1); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* Return if number of expected != number of actual parameters */ return; } { int iParam = 0; int nParam = ssGetNumSFcnParams(S); for ( iParam = 0; iParam < nParam; iParam++ ) { ssSetSFcnParamTunable( S, iParam, SS_PRM_TUNABLE ); } } /* Initialize two input ports with direct feedthrough */ if (!ssSetNumInputPorts(S, 2)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortWidth(S, 1, 1); ssSetInputPortDataType( S, 0, SS_DOUBLE); ssSetInputPortDataType( S, 1, SS_DOUBLE); ssSetInputPortDirectFeedThrough( S, 0, 1); ssSetInputPortDirectFeedThrough( S, 1, 1); /* Initialize one output port */ if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetOutputPortDataType( S, 0, SS_DOUBLE); /* Initialize one element in the mode vector */ ssSetNumSampleTimes(S, 1); ssSetNumModes(S,1); ssSetOptions(S, SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME | SS_OPTION_NONVOLATILE); }

The `mdlInitializeConditions`

method initializes
the mode vector value using the current value of the S-function dialog
parameter.

#define MDL_INITIALIZE_CONDITIONS /* Function: mdlInitializeConditions ============================= * Abstract: * Initialize the mode vector value. */ static void mdlInitializeConditions(SimStruct *S) { int_T *mv = ssGetModeVector(S); real_T param = mxGetScalar(ssGetSFcnParam(S,0)); mv[0] = (int_T)param; }

The `mdlProcessParameters`

and `mdlSetWorkWidths`

methods
initialize and update the run-time parameter. As the simulation runs,
changes to the S-function dialog parameter are mapped to the run-time
parameter.

/* Function: mdlSetWorkWidths ============================================= * Abstract: * Sets the number of runtime parameters. */ #define MDL_SET_WORK_WIDTHS static void mdlSetWorkWidths(SimStruct *S) { ssSetNumRunTimeParams(S,1); ssRegDlgParamAsRunTimeParam(S,0,0,"P1",SS_INT16); } /* Function: mdlProcessParameters =========================================== * Abstract: * Update run-time parameters. */ #define MDL_PROCESS_PARAMETERS static void mdlProcessParameters(SimStruct *S) { ssUpdateDlgParamAsRunTimeParam(S,0); }

The `mdlOutputs`

method updates the mode vector
value with the new run-time parameter value at every major time step.
It then uses the mode vector value to determine which input signal
to pass through to the output.

static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); InputRealPtrsType u2Ptrs = ssGetInputPortRealSignalPtrs(S,1); real_T *y = ssGetOutputPortSignal(S,0); int_T *mode = ssGetModeVector(S); real_T param = mxGetScalar(ssGetSFcnParam(S,0)); if (ssIsMajorTimeStep(S)) { mode[0] = (int_T)param; } if (!mode[0]) { /* first input */ y[0] = (*uPtrs[0]); } if (mode[0]) { /* second input */ y[0] = (*u2Ptrs[0]); } }