Search code examples
csimulinkmexs-function

Share data between multiple c mex s-functions


I am implementing several c s-functions. They have to rely on the same pointers and variables, inedependet of the current s-function.

Basically I want to instantiate all variabels and pointers in one "setup" s-function (inside mdlInitialize) and then be able to use these variables an pointers in different s-functions in their mdlOutputs function. Every s-function will be written in c.

I could not find any usefull hint in the mathworks help. Do you have any idea? Thanks.


Solution

  • There are several ways this can be done, although none of them are clearly the best approach.

    One approach is to define everything in a dll and have that loaded by each of the S-Functions. That is outlined in the question How to share a C struct among C S-Functions?.

    Another (and my preferred) approach is to create a custom data type, which is a C-struct containing all of the shared data, and have that passed as a signal between the S-Functions in the model. This is outlined in the section Using Opaque Data Types in C S-Functions of the doc Configure Custom Data Types.

    The doc shows various (relatively simple) things that need to be done in the S-Function that creates a custom structure. In this S-Functions MdlOutputs method, the custom struct would then just be made the output of the block in the usual way. For example, if the custom struct containing your data is defined as,

    typedef struct{
        real_T sig0;
        real_T sig1;
    }myStruct;
    

    Then in mdlInitializeSizes you need something like,

    myStruct tmp;
    
    /* Register the user-defined data types */
    id = ssRegisterDataType(S, "customDataType");
    if(id == INVALID_DTYPE_ID) return;
    
    /* Set the size of the user-defined data type */
    status = ssSetDataTypeSize(S, id, sizeof(tmp));
    if(status == 0) return;
    
    /* Set the zero representation */
    tmp.sig0 = 0;
    tmp.sig1 = 0;
    status = ssSetDataTypeZero(S, id, &tmp);
    

    And to output this as a signal, in the mdlOutputs method you'd have something like

    myStruct *pY0 = (myStruct *)ssGetOutputPortSignal(S, 0);
    
    pY0[0].sig0 = 'value of this param';
    pY0[0].sig1 = 'value of this param';
    

    Then in the mdlInitializeSizes of any S-Function that needs to use this signal you need

    DTypeId  id;
    id = ssRegisterDataType(S, "customDataType");
    if(id == INVALID_DTYPE_ID) return;
    

    which then gives you access to the custom struct within any of the other methods by using,

    myStruct **uPtrs = (myStruct **) ssGetInputPortSignalPtrs(S,0);
    

    The elements of the struct then get accessed in the usual way,

    firstVar = uPtrs[0]->sig0;
    secondVar = uPtrs[0]->sig1;
    

    The primary drawback of this approach is that the model cannot be used in code generation (using Simulink Coder).