S-Function Passing input array to c-function
16 views (last 30 days)
Show older comments
Hello!
I’m trying to reproduce the example described in https://nl.mathworks.com/help/rtw/tlc/inlining-s-functions.html, but with a function that takes all the input arrays from the block. Here is my code:
wrapsfnc.c
#define S_FUNCTION_NAME wrapsfcn
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
extern void times_two(const real_T *inPtr, real_T *outPtr, const int_T numEls); /* Declare times_two as extern */
/*
* mdlInitializeSizes - initialize the sizes array
*/
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0); // Number of expected parameters
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; // Parameter mismatch will be reported by Simulink
}
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetInputPortDataType(S, 0, SS_DOUBLE);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetOutputPortDataType(S, 0, SS_DOUBLE);
ssSetNumSampleTimes(S, 1);
ssSetOptions(S, 0);
}
/*
* mdlInitializeSampleTimes - indicate that this S-function runs
* at the rate of the source (driving block)
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
/*
* mdlOutputs - compute the outputs by calling times_two, which
* resides in another module, times_two.c
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
const real_T *uPtrs = ssGetInputPortRealSignal(S, 0);
real_T *y = ssGetOutputPortRealSignal(S, 0);
const int_T width = ssGetOutputPortWidth(S, 0);
times_two(uPtrs, y, width); /* Call times_two in mdlOutputs */
}
/*
* mdlTerminate - called when the simulation is terminated.
*/
static void mdlTerminate(SimStruct *S)
{
// No termination needed
}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
times_two.c
#ifdef MATLAB_MEX_FILE
#include "tmwtypes.h"
#else
#include "rtwtypes.h"
#endif
void times_two(const real_T *inPtr, real_T *outPtr, const int_T numEls)
{
for (int_T i = 0; i < numEls; i++)
outPtr[i] = 2.0*inPtr[i];
}
for compiling, I've used a command
mex wrapsfcn.c times_two.c
The result of the running the Simulink model was quite weird:

To by-pass this problem, I've created a temporary array and copied-by-value the input array:
InputPtrsType uPtrs = ssGetInputPortSignalPtrs(S, 0); // instead of ssGetInputPortRealSignal(S, 0);
...
real_T dblTemp[width];
for(int_T i = 0; i < width; i++)
dblTemp[i] = *(real_T *)uPtrs[i];
times_two(dblTemp, y, width); /* Call times_two in mdlOutputs */
and the result was OK:

Could you please explain my initial error and why my by-pass solution finally worked?
Please find attached the simulink files in the Inlined.zip
0 Comments
Answers (1)
Tridib
ongeveer 7 uur ago
Your first implementation read the input as a single contiguous real_T* using ssGetInputPortRealSignal, but you never told Simulink that the input elements are guaranteed to be contiguous. By default, RequiredContiguous is false, so the engine may provide a non‑contiguous layout, and indexing u[i] then walks arbitrary memory, hence the tiny “garbage” doubles you observed, which is a symptom of reading the wrong addresses. The “bypass” worked because ssGetInputPortSignalPtrs returns one pointer per element specifically for the non‑contiguous case, so dereferencing each uPtrs[i] accesses the correct element regardless of layout, producing the expected results.
Hope this helps!
0 Comments
See Also
Categories
Find more on Simulink Coder in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!