2

I have defined a Bus object in Matlab and I am passing it to a C S-function that will do some processing. I have initialized the input like this inside mdlInitializeSizes:

#if defined(MATLAB_MEX_FILE)
    if (ssGetSimMode(S) != SS_SIMMODE_SIZES_CALL_ONLY)
    {
        DTypeId dataTypeIdReg;

        ssRegisterTypeFromNamedObject(S, BUS_OBJ_NAME, &dataTypeIdReg);
        if(dataTypeIdReg == INVALID_DTYPE_ID) return;
        ssSetInputPortDataType(S, 0, dataTypeIdReg);
    }
#endif
ssSetInputPortWidth(S, 0, 1);
ssSetBusInputAsStruct(S, 0, 1); 
ssSetInputPortDirectFeedThrough(S, 0, 1);
ssSetInputPortRequiredContiguous(S, 0, 1);

I have also auto-generated a C struct containing the same variables as the signals inside the Bus object.

Some of the signals in the Bus are also buses, so the C struct was generated recursively. For example:

struct myStruct
{
   uint8_t var1[8];
   uint32_t var2;
   myOtherStruct1 var3;
   myOtherStruct2 var4;
   ...
}

Now I want to read the Bus object into the struct. For that, I do:

const myStruct *busData = (const myStruct *) ssGetInputPortSignal(S, 0);

The problem is that busData does not have the correct data for var4 and following variables. If I print the raw data received from ssGetInputPortSignal I can find the data that I am expecting, but it is not at the correct position in the array; instead it has some padding.

Therefore I would like to ask:

  • Is this the correct way of reading a Bus object into a struct in a C S-function?
  • How can I disable the padding so that all the data is contiguous?

Thanks in advance!

user1011113
  • 1,114
  • 8
  • 27

2 Answers2

0

I had the same Problem. What helped me was the following examples provided by MathWorks:

open('sldemo_sfun_counterbus.c')
open('counterbus.h')

Here are some code snippets that show how to get the information of an simulink bus object, based on the examples above:

// Defined localy, could also be defined in a header
typedef struct                  
{                               
    uint32_t ui32_header_val;   
    double f64_header_val;      
} YOURSTRUCT;            

static void mdlInitializeSizes(SimStruct *S)
{
    // ... your code

    // Specify I/O
    if (!ssSetNumInputPorts(S,1)) return;

    //Bus inport 
    DTypeId dataTypeIdReg;
    ssRegisterTypeFromNamedObject(S, "YOURBUS", &dataTypeIdReg);
    ssSetInputPortDataType(S, 0, dataTypeIdReg);
    ssSetBusInputAsStruct(S, 0, true);

    ssSetInputPortOverWritable(S, 0, 1);
    ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL);
    // This is important !!! Specifies that the signal elements entering the specified port must occupy contiguous areas of memory
    ssSetInputPortRequiredContiguous(S, 0, 1);

    // Configure the dwork (__dtBusInfo)
    ssSetDWorkDataType(S, 0, SS_INT32);
    ssSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_DWORK);
    ssSetDWorkName(S, 0, "dtBusInfo");

    // This contains the offset and sizes of your struct
    ssSetDWorkWidth(S, 0, 4);
    // The DWorker needs a depth of 4, since it stores the size of each element and its offset

    ssSetDWorkComplexSignal(S, 0, COMPLEX_NO);

    // ... your code
}

static void mdlStart(SimStruct *S)
{
    // ... your code

    // Access bus/struct information
    int32_T* __dtBusInfo = (int32_T*)ssGetDWork(S, 0);

    // Get common data type Id 
    DTypeId __YOURBUSId = ssGetDataTypeId(S, "YOURBUS");
    DTypeId __int32Id = ssGetDataTypeId(S, "int32");
    DTypeId __doubleId = ssGetDataTypeId(S, "double");

    // Get information for accessing YOURBUS.ui32_header_val
    __dtBusInfo[0] = ssGetBusElementOffset(S, __YOURBUSId, 0);
    __dtBusInfo[1] = ssGetDataTypeSize(S, __int32Id);

    // Get information for accessing YOURBUS.f64_header_val
    __dtBusInfo[2] = ssGetBusElementOffset(S, __YOURBUSId, 1);
    __dtBusInfo[3] = ssGetDataTypeSize(S, __doubleId);

    // ... your code                  

static void mdlOutputs(SimStruct *S, int_T tid)
{   
    // ... your code
    char *inputPort = (char*)(ssGetInputPortSignal(S, 0)); // Cast it to an 8Bit long Pointer here char

    YOURSTRUCT yourCStruct;

    memcpy(&yourCStruct.ui32_header_val, inputPort + __dtBusInfo[0], __dtBusInfo[1]);
    memcpy(&yourCStruct.f64_header_val,  inputPort + __dtBusInfo[2], __dtBusInfo[3]);
    // ... your code
}
Nils
  • 382
  • 3
  • 12
0

Simulink organizes bus data a certain way in memory which may not have the same layout as the corresponding C struct ... for example padding could be different. As a result, the only way to ensure the data in the bus gets placed in the proper location in the C structure is an element-by-element copy.

https://www.mathworks.com/matlabcentral/answers/595120-structure-output-from-s-function-getting-memcopy-ed-one-element-at-a-time-when-connecting-to-bus-por

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 04 '23 at 12:17