diff --git a/rtwsfcnfmi/CMakeLists.txt b/rtwsfcnfmi/CMakeLists.txt index 6b98295..78f7828 100644 --- a/rtwsfcnfmi/CMakeLists.txt +++ b/rtwsfcnfmi/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required (VERSION 3.22) set(MODEL_NAME "" CACHE STRING "Model name") set(SOLVER "ode1" CACHE STRING "Solver") set_property(CACHE SOLVER PROPERTY STRINGS ode1 ode2 ode3 ode4 ode5 ode8 ode14x) -set(MATLAB_ROOT "C:/Program Files/MATLAB/R2019b" CACHE STRING "MATLAB install directory") -set(MATLAB_VERSION "MATLAB_R2017b_" CACHE STRING "MATLAB version for conditional compilation") +set(MATLAB_ROOT "C:/Program Files/MATLAB/R2022b" CACHE STRING "MATLAB install directory") +set(MATLAB_VERSION "913" CACHE STRING "MATLAB version for conditional compilation") set(RTW_DIR "" CACHE STRING "RTW generated model directory") set(CUSTOM_INCLUDE "" CACHE STRING "Additional include directories") set(CUSTOM_SOURCE "" CACHE STRING "Additional source files") @@ -72,7 +72,7 @@ if (EXISTS "${RTW_DIR}/rt_zcfcn.c") endif () if (NOT LOAD_MEX) - set (MODEL_SOURCES ${MODEL_SOURCES} "${MATLAB_ROOT}/rtw/c/src/rt_matrx.c") + set (MODEL_SOURCES ${MODEL_SOURCES} rt_matrx_wrapper.c) endif () add_library(${MODEL_NAME} SHARED @@ -112,7 +112,7 @@ target_compile_definitions(${MODEL_NAME} PRIVATE rt_matrx_h RT_MALLOC NDEBUG - ${MATLAB_VERSION} + MATLAB_VERSION=${MATLAB_VERSION} ) # don't add the "lib" prefix to the shared library diff --git a/rtwsfcnfmi/rt_matrx_wrapper.c b/rtwsfcnfmi/rt_matrx_wrapper.c new file mode 100644 index 0000000..42cb20c --- /dev/null +++ b/rtwsfcnfmi/rt_matrx_wrapper.c @@ -0,0 +1,4 @@ +#include "rtwtypes.h" /* needed for real_T */ +#include "rt_mxclassid.h" /* needed for mxClassID */ + +#include "rt_matrx.c" diff --git a/rtwsfcnfmi/rtwsfcnfmi_make_rtw_hook.m b/rtwsfcnfmi/rtwsfcnfmi_make_rtw_hook.m index 45bd32d..fdcc83a 100644 --- a/rtwsfcnfmi/rtwsfcnfmi_make_rtw_hook.m +++ b/rtwsfcnfmi/rtwsfcnfmi_make_rtw_hook.m @@ -53,20 +53,21 @@ function rtwsfcnfmi_make_rtw_hook(hookMethod, modelName, rtwRoot, templateMakefi command = get_param(modelName, 'CMakeCommand'); command = grtfmi_find_cmake(command); generator = get_param(modelName, 'CMakeGenerator'); - toolset = get_param(modelName, 'CMakeToolset'); + toolset = get_param(modelName, 'CMakeToolset'); build_configuration = get_param(modelName, 'CMakeBuildConfiguration'); + version = str2double(ver('MATLAB').Version); + + major_version = floor(version); + minor_version = num2str((version - major_version) * 100); + % MATLAB version for conditional compilation - if verLessThan('matlab', '7.12') - matlab_version = ''; % do nothing - elseif verLessThan('matlab', '8.5') - matlab_version = 'MATLAB_R2011a_'; % R2011a - R2014b - elseif verLessThan('matlab', '9.3') - matlab_version = 'MATLAB_R2015a_'; % R2015a - R2017a - elseif verLessThan('matlab', '9.8') - matlab_version = 'MATLAB_R2017b_'; % R2017b - R2019b + matlab_version = num2str(major_version); + + if strcmp(minor_version(2), '0') + matlab_version = [matlab_version '0' minor_version(1)]; else - matlab_version = 'MATLAB_R2020a_'; % R2020a and later + matlab_version = [matlab_version minor_version]; end solver = get_param(modelName, 'Solver'); diff --git a/rtwsfcnfmi/sfunction.c b/rtwsfcnfmi/sfunction.c index 58e09f2..12a52e6 100644 --- a/rtwsfcnfmi/sfunction.c +++ b/rtwsfcnfmi/sfunction.c @@ -14,6 +14,10 @@ #include "sfunction.h" #include "model_interface.h" +// MATLAB versions for conditional compilation +#define R2020b 908 +#define R2017b 903 + Model* currentModel = NULL; const char* _SFCN_FMI_MATLAB_BIN = NULL; @@ -207,45 +211,50 @@ Model *InstantiateModel(const char* instanceName, logMessageCallback logMessage, currentModel = model; } - model->S = CreateSimStructForFMI(model->instanceName); - if (model->S == NULL) { + SimStruct* S = CreateSimStructForFMI(model->instanceName); + + if (S == NULL) { goto fail; } + model->S = S; + /* Register model callback functions in Simstruct */ - sfcn_fmi_registerMdlCallbacks_(model->S); + sfcn_fmi_registerMdlCallbacks_(S); /* Initialize sizes and create vectors */ - sfcnInitializeSizes(model->S); + sfcnInitializeSizes(S); allocateSimStructVectors(model); /* Create solver data and ZC vector */ - rt_CreateIntegrationData(model->S); - model->S->mdlInfo->solverInfo->zcSignalVector = (real_T*)calloc(SFCN_FMI_ZC_LENGTH + 1, sizeof(real_T)); - model->S->states.nonsampledZCs = model->S->mdlInfo->solverInfo->zcSignalVector; + rt_CreateIntegrationData(S); + S->mdlInfo->solverInfo->numContStatesPtr = ssGetNumContStatesPtr(S); + S->mdlInfo->solverInfo->zcSignalVector = (real_T*)calloc(SFCN_FMI_ZC_LENGTH + 1, sizeof(real_T)); + S->states.nonsampledZCs = S->mdlInfo->solverInfo->zcSignalVector; + /* Register model callback for ODE solver */ - sfcn_fmi_registerRTModelCallbacks_(model->S); + sfcn_fmi_registerRTModelCallbacks_(S); /* Initialize sample times and sample flags */ - sfcnInitializeSampleTimes(model->S); + sfcnInitializeSampleTimes(S); setSampleStartValues(model); /* non-finites */ rt_InitInfAndNaN(sizeof(real_T)); /* Create and initialize global tunable parameters */ - sfcn_fmi_mxGlobalTunable_(model->S, 1, 0); + sfcn_fmi_mxGlobalTunable_(S, 1, 0); /* Call mdlStart */ - if (ssGetmdlStart(model->S) != NULL) { - sfcnStart(model->S); + if (ssGetmdlStart(S) != NULL) { + sfcnStart(S); } /* Allocate model vectors */ model->oldZC = (real_T*)calloc(SFCN_FMI_ZC_LENGTH + 1, sizeof(real_T)); - model->numSampleHits = (int_T*)calloc(model->S->sizes.numSampleTimes + 1, sizeof(int_T)); + model->numSampleHits = (int_T*)calloc(S->sizes.numSampleTimes + 1, sizeof(int_T)); // model->inputDerivatives = (real_T*)calloc(SFCN_FMI_NBR_INPUTS + 1, sizeof(real_T)); /* Check Simstruct error status and stop requested */ - if ((ssGetErrorStatus(model->S) != NULL) || (ssGetStopRequested(model->S) != 0)) { + if ((ssGetErrorStatus(S) != NULL) || (ssGetStopRequested(S) != 0)) { goto fail; } @@ -277,14 +286,29 @@ Model *InstantiateModel(const char* instanceName, logMessageCallback logMessage, SimStruct *CreateSimStructForFMI(const char* instanceName) { SimStruct *S = (SimStruct*)calloc(1, sizeof(SimStruct)); + if (S == NULL) { return NULL; } + S->mdlInfo = (struct _ssMdlInfo*)calloc(1, sizeof(struct _ssMdlInfo)); + if (S->mdlInfo == NULL) { return NULL; } + S->blkInfo.blkInfo2 = (struct _ssBlkInfo2*)calloc(1, sizeof(struct _ssBlkInfo2)); + + if (S->blkInfo.blkInfo2 == NULL) { + return NULL; + } + + S->blkInfo.blkInfo2->mdlInfoSLSize = (struct _ssMdlInfoSLSize*)calloc(1, sizeof(struct _ssMdlInfoSLSize)); + + if (S->blkInfo.blkInfo2->mdlInfoSLSize == NULL) { + return NULL; + } + _ssSetRootSS(S, S); _ssSetSimMode(S, SS_SIMMODE_SIZES_CALL_ONLY); _ssSetSFcnParamsCount(S, 0); @@ -316,12 +340,8 @@ SimStruct *CreateSimStructForFMI(const char* instanceName) S->blkInfo.block = NULL; /* Accessed by ssSetOutputPortBusMode in mdlInitializeSizes */ S->regDataType.setNumDWorkFcn = setNumDWork_FMI; -#if defined(MATLAB_R2011a_) || defined(MATLAB_R2015a_) || defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) S->states.statesInfo2 = (struct _ssStatesInfo2 *) calloc(1, sizeof(struct _ssStatesInfo2)); -#if defined(MATLAB_R2015a_) || defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) S->states.statesInfo2->periodicStatesInfo = (ssPeriodicStatesInfo *)calloc(1, sizeof(ssPeriodicStatesInfo)); -#endif -#endif return(S); } @@ -367,14 +387,10 @@ void FreeSimStruct(SimStruct *S) { sfcn_fmi_mxGlobalTunable_(S, 0, 0); free(S->sfcnParams.dlgParams); -#if defined(MATLAB_R2011a_) || defined(MATLAB_R2015a_) || defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) free(S->states.statesInfo2->absTol); free(S->states.statesInfo2->absTolControl); -#if defined(MATLAB_R2015a_) || defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) free(S->states.statesInfo2->periodicStatesInfo); -#endif free(S->states.statesInfo2); -#endif if (S->mdlInfo != NULL) { if (S->mdlInfo->dataTypeAccess != NULL) { @@ -501,26 +517,26 @@ static size_t getDataTypeSize(SimStruct *S, BuiltInDTypeId dataTypeId) { } void allocateSimStructVectors(Model* m) { - int_T i; - size_t dtypeSize; + SimStruct* S = m->S; - S->states.contStates = (real_T*)calloc(S->sizes.numContStates + 1, sizeof(real_T)); - S->states.dX = (real_T*)calloc(S->sizes.numContStates + 1, sizeof(real_T)); - /* store pointer, since it will be changed to point to ODE integration data */ - m->dX = S->states.dX; - S->states.contStateDisabled = (boolean_T*)calloc(S->sizes.numContStates + 1, sizeof(boolean_T)); - S->states.discStates = (real_T* )calloc(S->sizes.numDiscStates + 1, sizeof(real_T)); -#if defined(MATLAB_R2011a_) || defined(MATLAB_R2015a_) || defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) - S->states.statesInfo2->absTol = (real_T* )calloc(S->sizes.numContStates + 1, sizeof(real_T)); - S->states.statesInfo2->absTolControl = (uint8_T*)calloc(S->sizes.numContStates + 1, sizeof(uint8_T)); -#endif - S->stInfo.sampleTimes = (time_T*)calloc(S->sizes.numSampleTimes + 1, sizeof(time_T)); - S->stInfo.offsetTimes = (time_T*)calloc(S->sizes.numSampleTimes + 1, sizeof(time_T)); - S->stInfo.sampleTimeTaskIDs = (int_T* )calloc(S->sizes.numSampleTimes + 1, sizeof(int_T)); -#if defined(MATLAB_R2020a_) + S->states.contStates = (real_T* )calloc(S->sizes.numContStates + 1, sizeof(real_T)); + S->states.dX = (real_T* )calloc(S->sizes.numContStates + 1, sizeof(real_T)); + S->states.contStateDisabled = (boolean_T*)calloc(S->sizes.numContStates + 1, sizeof(boolean_T)); + S->states.discStates = (real_T* )calloc(S->sizes.numDiscStates + 1, sizeof(real_T)); + S->states.statesInfo2->absTol = (real_T* )calloc(S->sizes.numContStates + 1, sizeof(real_T)); + S->states.statesInfo2->absTolControl = (uint8_T* )calloc(S->sizes.numContStates + 1, sizeof(uint8_T)); +#if MATLAB_VERSION >= R2020b S->states.statesInfo2->jacPerturbBounds = (ssJacobianPerturbationBounds*)calloc(1, sizeof(ssJacobianPerturbationBounds)); #endif + + /* store pointer, since it will be changed to point to ODE integration data */ + m->dX = S->states.dX; + + S->stInfo.sampleTimes = (time_T*)calloc(S->sizes.numSampleTimes + 1, sizeof(time_T)); + S->stInfo.offsetTimes = (time_T*)calloc(S->sizes.numSampleTimes + 1, sizeof(time_T)); + S->stInfo.sampleTimeTaskIDs = (int_T* )calloc(S->sizes.numSampleTimes + 1, sizeof(int_T)); + /* allocate per-task sample hit matrix */ S->mdlInfo->sampleHits = (int_T* )calloc(S->sizes.numSampleTimes*S->sizes.numSampleTimes + 1, sizeof(int_T)); S->mdlInfo->perTaskSampleHits = S->mdlInfo->sampleHits; @@ -529,14 +545,17 @@ void allocateSimStructVectors(Model* m) { S->work.iWork = (int_T* )calloc(S->sizes.numIWork + 1, sizeof(int_T)); S->work.pWork = (void** )calloc(S->sizes.numPWork + 1, sizeof(void*)); S->work.rWork = (real_T*)calloc(S->sizes.numRWork + 1, sizeof(real_T)); - for (i = 0; i < S->sizes.in.numInputPorts; i++) { + + for (int_T i = 0; i < S->sizes.in.numInputPorts; i++) { SetInputPortDimensionInfoFcn_FMI(S, i); } - for (i = 0; i < S->sizes.out.numOutputPorts; i++) { + + for (int_T i = 0; i < S->sizes.out.numOutputPorts; i++) { SetOutputPortDimensionInfoFcn_FMI(S, i); } - for (i = 0; i < S->sizes.numDWork; i++) { - dtypeSize = getDataTypeSize(S, S->work.dWork.sfcn[i].dataTypeId); + + for (int_T i = 0; i < S->sizes.numDWork; i++) { + size_t dtypeSize = getDataTypeSize(S, S->work.dWork.sfcn[i].dataTypeId); S->work.dWork.sfcn[i].array = calloc(S->work.dWork.sfcn[i].width + 1, dtypeSize); } } @@ -886,7 +905,7 @@ void NewDiscreteStates(Model *model, int *valuesOfContinuousStatesChanged, real_ model->shouldRecompute = 1; -#if defined(MATLAB_R2017b_) || defined(MATLAB_R2020a_) +#if MATLAB_VERSION >= R2017b if (model->S->mdlInfo->mdlFlags.blockStateForSolverChangedAtMajorStep) { model->S->mdlInfo->mdlFlags.blockStateForSolverChangedAtMajorStep = 0U; #else diff --git a/rtwsfcnfmi/sfunction.h b/rtwsfcnfmi/sfunction.h index da0d137..49526b1 100644 --- a/rtwsfcnfmi/sfunction.h +++ b/rtwsfcnfmi/sfunction.h @@ -10,6 +10,20 @@ #define SFCN_FMI_MAX_TIME 1e100 #define SFCN_FMI_EPS 2e-13 /* Not supported with discrete sample times smaller than this */ +#ifndef ssSetRegInputPortDimensionInfoFcn +#define ssSetRegInputPortDimensionInfoFcn(S, fcn) \ + (S)->blkInfo.blkInfo2->mdlInfoSLSize->regInputPortDimsInfo = (fcn) +#endif + +#ifndef ssSetRegOutputPortDimensionInfoFcn +#define ssSetRegOutputPortDimensionInfoFcn(S, fcn) \ + (S)->blkInfo.blkInfo2->mdlInfoSLSize->regOutputPortDimsInfo = (fcn) +#endif + +#ifndef ssGetNumContStatesPtr +#define ssGetNumContStatesPtr(S) &((S)->sizes.numContStates) +#endif + /* Model status */ typedef enum {