Как прочитать Bus объект в C struct внутри C S-Function [Matlab]

Я определил объект Bus в Matlab, и я передаю его в C S-функцию, которая будет выполнять некоторую обработку. Я инициализировал ввод, как это внутри 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);

Я также автоматически сгенерировал структуру C, содержащую те же переменные, что и сигналы внутри объекта Bus.

Некоторые сигналы в шине также являются шинами, поэтому структура C была сгенерирована рекурсивно. Например:

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

Теперь я хочу прочитать объект Bus в структуру. Для этого я делаю:

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

Проблема в том, что busData не имеет правильных данных для var4 и следующие переменные. Если я распечатаю необработанные данные, полученные от ssGetInputPortSignal, я могу найти ожидаемые данные, но они не находятся в правильной позиции в массиве; вместо этого у этого есть некоторое дополнение.

Поэтому я хотел бы спросить:

  • Это правильный способ чтения объекта Bus в структуру в C S-функции?
  • Как я могу отключить заполнение, чтобы все данные были смежными?

Заранее спасибо!

2 ответа

У меня такая же проблема. Мне помогли следующие примеры, предоставленные MathWorks:

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

Вот некоторые фрагменты кода, которые показывают, как получить информацию об объекте шины Simulink на основе приведенных выше примеров:

// 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
}

Simulink определенным образом организует данные шины в памяти, которые могут не иметь того же макета, что и соответствующая структура C... например, заполнение может быть другим. В результате единственный способ гарантировать, что данные в шине будут помещены в правильное место в структуре C, — это поэлементное копирование.

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

Другие вопросы по тегам