/* * File: canReceive.c * * * --- THIS FILE GENERATED BY S-FUNCTION BUILDER: 3.0 --- * * This file is an S-function produced by the S-Function * Builder which only recognizes certain fields. Changes made * outside these fields will be lost the next time the block is * used to load, edit, and resave this file. This file will be overwritten * by the S-function Builder block. If you want to edit this file by hand, * you must change it only in the area defined as: * * %%%-SFUNWIZ_defines_Changes_BEGIN * #define NAME 'replacement text' * %%% SFUNWIZ_defines_Changes_END * * DO NOT change NAME--Change the 'replacement text' only. * * For better compatibility with the Simulink Coder, the * "wrapper" S-function technique is used. This is discussed * in the Simulink Coder's Manual in the Chapter titled, * "Wrapper S-functions". * * ------------------------------------------------------------------------- * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | * ------------------------------------------------------------------------- * * Created: Mon Oct 28 13:36:38 2024 */ #define S_FUNCTION_LEVEL 2 #define S_FUNCTION_NAME canReceive /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ /* %%%-SFUNWIZ_defines_Changes_BEGIN --- EDIT HERE TO _END */ #define NUM_INPUTS 3 /* Input Port 0 */ #define IN_PORT_0_NAME id #define INPUT_0_DIMS_ND {1,1} #define INPUT_0_NUM_ELEMS 1 #define INPUT_0_WIDTH 1 #define INPUT_DIMS_0_COL 1 #define INPUT_0_DTYPE uint32_T #define INPUT_0_COMPLEX COMPLEX_NO #define IN_0_BUS_BASED 0 #define IN_0_BUS_NAME #define IN_0_DIMS 1-D #define INPUT_0_FEEDTHROUGH 1 #define IN_0_ISSIGNED 0 #define IN_0_WORDLENGTH 8 #define IN_0_FIXPOINTSCALING 1 #define IN_0_FRACTIONLENGTH 9 #define IN_0_BIAS 0 #define IN_0_SLOPE 0.125 /* Input Port 1 */ #define IN_PORT_1_NAME dlc #define INPUT_1_DIMS_ND {1,1} #define INPUT_1_NUM_ELEMS 1 #define INPUT_1_WIDTH 1 #define INPUT_DIMS_1_COL 1 #define INPUT_1_DTYPE uint8_T #define INPUT_1_COMPLEX COMPLEX_NO #define IN_1_BUS_BASED 0 #define IN_1_BUS_NAME #define IN_1_DIMS 1-D #define INPUT_1_FEEDTHROUGH 1 #define IN_1_ISSIGNED 0 #define IN_1_WORDLENGTH 8 #define IN_1_FIXPOINTSCALING 1 #define IN_1_FRACTIONLENGTH 9 #define IN_1_BIAS 0 #define IN_1_SLOPE 0.125 /* Input Port 2 */ #define IN_PORT_2_NAME data #define INPUT_2_DIMS_ND {8,1} #define INPUT_2_NUM_ELEMS 8 #define INPUT_2_WIDTH 8 #define INPUT_DIMS_2_COL 1 #define INPUT_2_DTYPE uint8_T #define INPUT_2_COMPLEX COMPLEX_NO #define IN_2_BUS_BASED 0 #define IN_2_BUS_NAME #define IN_2_DIMS 2-D #define INPUT_2_FEEDTHROUGH 1 #define IN_2_ISSIGNED 0 #define IN_2_WORDLENGTH 8 #define IN_2_FIXPOINTSCALING 1 #define IN_2_FRACTIONLENGTH 9 #define IN_2_BIAS 0 #define IN_2_SLOPE 0.125 #define NUM_OUTPUTS 1 /* Output Port 0 */ #define OUT_PORT_0_NAME canFrame #define OUTPUT_0_DIMS_ND {1,1} #define OUTPUT_0_NUM_ELEMS 1 #define OUTPUT_0_WIDTH 1 #define OUTPUT_DIMS_0_COL 1 #define OUTPUT_0_DTYPE uint8_T #define OUTPUT_0_COMPLEX COMPLEX_NO #define OUT_0_BUS_BASED 1 #define OUT_0_BUS_NAME CAN_MESSAGE_BUS #define OUT_0_DIMS 1-D #define OUT_0_ISSIGNED 1 #define OUT_0_WORDLENGTH 8 #define OUT_0_FIXPOINTSCALING 1 #define OUT_0_FRACTIONLENGTH 3 #define OUT_0_BIAS 0 #define OUT_0_SLOPE 0.125 #define NPARAMS 0 #define SAMPLE_TIME_0 INHERITED_SAMPLE_TIME #define NUM_DISC_STATES 0 #define DISC_STATES_IC [0] #define NUM_CONT_STATES 0 #define CONT_STATES_IC [0] #define SFUNWIZ_GENERATE_TLC 1 #define SOURCEFILES "__SFB__" #define PANELINDEX N/A #define USE_SIMSTRUCT 0 #define SHOW_COMPILE_STEPS 0 #define CREATE_DEBUG_MEXFILE 0 #define SAVE_CODE_ONLY 0 #define SFUNWIZ_REVISION 3.0 /* %%%-SFUNWIZ_defines_Changes_END --- EDIT HERE TO _BEGIN */ /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ #include "simstruc.h" #include "canReceive_bus.h" /* * Code Generation Environment flag (simulation or standalone target). */ static int_T isSimulationTarget; /* Utility function prototypes. */ static int_T GetRTWEnvironmentMode(SimStruct *S); /* Macro used to check if Simulation mode is set to accelerator */ #define isBusDWorkPresent ( ( ( !ssRTWGenIsCodeGen(S) || isSimulationTarget ) && !ssIsExternalSim(S) ) || ssIsRapidAcceleratorActive(S) ) typedef struct { int_T offset; int_T elemSize; int_T numElems; } busInfoStruct; extern void canReceive_Outputs_wrapper(const uint32_T *id, const uint8_T *dlc, const uint8_T *data, CAN_MESSAGE_BUS *canFrame); /*====================* * S-function methods * *====================*/ /* Function: mdlInitializeSizes =============================================== * Abstract: * Setup sizes of the various vectors. */ static void mdlInitializeSizes(SimStruct *S) { DECL_AND_INIT_DIMSINFO(inputDimsInfo); ssSetNumSFcnParams(S, NPARAMS); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } ssSetArrayLayoutForCodeGen(S, SS_COLUMN_MAJOR); ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT); ssSetNumContStates(S, NUM_CONT_STATES); ssSetNumDiscStates(S, NUM_DISC_STATES); if (!ssSetNumInputPorts(S, NUM_INPUTS)) return; /* Input Port 0 */ ssSetInputPortWidth(S, 0, INPUT_0_NUM_ELEMS); ssSetInputPortDataType(S, 0, SS_UINT32); ssSetInputPortComplexSignal(S, 0, INPUT_0_COMPLEX); ssSetInputPortDirectFeedThrough(S, 0, INPUT_0_FEEDTHROUGH); ssSetInputPortRequiredContiguous(S, 0, 1);/*direct input signal access*/ /* Input Port 1 */ ssSetInputPortWidth(S, 1, INPUT_1_NUM_ELEMS); ssSetInputPortDataType(S, 1, SS_UINT8); ssSetInputPortComplexSignal(S, 1, INPUT_1_COMPLEX); ssSetInputPortDirectFeedThrough(S, 1, INPUT_1_FEEDTHROUGH); ssSetInputPortRequiredContiguous(S, 1, 1);/*direct input signal access*/ /* Input Port 2 */ ssAllowSignalsWithMoreThan2D(S); inputDimsInfo.numDims = 2; inputDimsInfo.width = INPUT_2_NUM_ELEMS; int_T in2Dims[] = INPUT_2_DIMS_ND; inputDimsInfo.dims = in2Dims; ssSetInputPortDimensionInfo(S, 2, &inputDimsInfo); ssSetInputPortDataType(S, 2, SS_UINT8); ssSetInputPortComplexSignal(S, 2, INPUT_2_COMPLEX); ssSetInputPortDirectFeedThrough(S, 2, INPUT_2_FEEDTHROUGH); ssSetInputPortRequiredContiguous(S, 2, 1);/*direct input signal access*/ if (!ssSetNumOutputPorts(S, NUM_OUTPUTS)) return; /* Output Port 0 */ /* Register CAN_MESSAGE_BUS datatype for Output port 0 */ #if defined(MATLAB_MEX_FILE) if (ssGetSimMode(S) != SS_SIMMODE_SIZES_CALL_ONLY) { DTypeId dataTypeIdReg; ssRegisterTypeFromNamedObject(S, "CAN_MESSAGE_BUS", &dataTypeIdReg); if (dataTypeIdReg == INVALID_DTYPE_ID) return; ssSetOutputPortDataType(S, 0, dataTypeIdReg); } #endif ssSetOutputPortWidth(S, 0, OUTPUT_0_NUM_ELEMS); ssSetBusOutputObjectName(S, 0, (void *) "CAN_MESSAGE_BUS"); ssSetOutputPortComplexSignal(S, 0, OUTPUT_0_COMPLEX); ssSetBusOutputAsStruct(S, 0,OUT_0_BUS_BASED); ssSetOutputPortBusMode(S, 0, SL_BUS_MODE); if (ssRTWGenIsCodeGen(S)) { isSimulationTarget = GetRTWEnvironmentMode(S); if (isSimulationTarget == -1) { ssSetLocalErrorStatus(S, " Unable to determine a valid code generation environment mode"); return; } isSimulationTarget |= ssRTWGenIsModelReferenceSimTarget(S); } /* Set the number of dworks */ if (!ssSetNumDWork(S, 1)) return; /* * Configure the dwork 0 (canFrameBUS) */ #if defined(MATLAB_MEX_FILE) if (ssGetSimMode(S) != SS_SIMMODE_SIZES_CALL_ONLY) { DTypeId dataTypeIdReg; ssRegisterTypeFromNamedObject(S, "CAN_MESSAGE_BUS", &dataTypeIdReg); if (dataTypeIdReg == INVALID_DTYPE_ID) return; if (isBusDWorkPresent) { ssSetDWorkDataType(S, 0, dataTypeIdReg); } else { ssSetDWorkDataType(S, 0, SS_POINTER); } } #endif ssSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_DWORK); ssSetDWorkName(S, 0, "canFrameBUS"); ssSetDWorkWidth(S, 0, DYNAMICALLY_SIZED); ssSetDWorkComplexSignal(S, 0, COMPLEX_NO); ssSetNumPWork(S, 0); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetSimulinkVersionGeneratedIn(S, "23.2"); /* Take care when specifying exception free code - see sfuntmpl_doc.c */ ssSetRuntimeThreadSafetyCompliance(S, RUNTIME_THREAD_SAFETY_COMPLIANCE_FALSE); ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_WORKS_WITH_CODE_REUSE)); } #if defined(MATLAB_MEX_FILE) #define MDL_SET_INPUT_PORT_DIMENSION_INFO static void mdlSetInputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo) { if (!ssSetInputPortDimensionInfo(S, port, dimsInfo)) return; } #endif #define MDL_SET_OUTPUT_PORT_DIMENSION_INFO #if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO) static void mdlSetOutputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo) { if (!ssSetOutputPortDimensionInfo(S, port, dimsInfo)) return; } #endif #define MDL_SET_DEFAULT_PORT_DIMENSION_INFO static void mdlSetDefaultPortDimensionInfo(SimStruct *S) { DECL_AND_INIT_DIMSINFO(portDimsInfo); int_T dims[2]; /* Setting default dimensions for input port 2 */ portDimsInfo.width = INPUT_2_NUM_ELEMS; dims[0] = INPUT_2_NUM_ELEMS; dims[1] = 1; portDimsInfo.dims = dims; portDimsInfo.numDims = 2; if (ssGetInputPortWidth(S, 2) == DYNAMICALLY_SIZED) { ssSetInputPortMatrixDimensions(S, 2, 1 , 1); } return; } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * Specifiy the sample time. */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, SAMPLE_TIME_0); ssSetModelReferenceSampleTimeDefaultInheritance(S); ssSetOffsetTime(S, 0, 0.0); } #define MDL_SET_INPUT_PORT_DATA_TYPE static void mdlSetInputPortDataType(SimStruct *S, int port, DTypeId dType) { ssSetInputPortDataType(S, 0, dType); } #define MDL_SET_OUTPUT_PORT_DATA_TYPE static void mdlSetOutputPortDataType(SimStruct *S, int port, DTypeId dType) { ssSetOutputPortDataType(S, 0, dType); } #define MDL_SET_DEFAULT_PORT_DATA_TYPES static void mdlSetDefaultPortDataTypes(SimStruct *S) { ssSetInputPortDataType(S, 0, SS_DOUBLE); ssSetOutputPortDataType(S, 0, SS_DOUBLE); } #define MDL_SET_WORK_WIDTHS #if defined(MDL_SET_WORK_WIDTHS) && defined(MATLAB_MEX_FILE) static void mdlSetWorkWidths(SimStruct *S) { /* Set the width of DWork(s) used for marshalling the IOs */ if (isBusDWorkPresent) { /* Update dwork 0 */ ssSetDWorkWidth(S, 0, ssGetOutputPortWidth(S, 0)); } } #endif #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) /* Function: mdlStart ======================================================= * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is the place * to do it. */ static void mdlStart(SimStruct *S) { /* Bus Information */ slDataTypeAccess *dta = ssGetDataTypeAccess(S); const char *bpath = ssGetPath(S); DTypeId CAN_MESSAGE_BUSId = ssGetDataTypeId(S,"CAN_MESSAGE_BUS"); busInfoStruct *busInfo = (busInfoStruct *)malloc(8*sizeof(busInfoStruct)); if (busInfo==NULL) { ssSetLocalErrorStatus(S, "Memory allocation failure"); return; } /*offsets info for all unique bus structures*/ busInfo[0].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 0); busInfo[0].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT8); busInfo[0].numElems = 1; busInfo[1].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 1); busInfo[1].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT8); busInfo[1].numElems = 1; busInfo[2].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 2); busInfo[2].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT8); busInfo[2].numElems = 1; busInfo[3].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 3); busInfo[3].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT8); busInfo[3].numElems = 1; busInfo[4].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 4); busInfo[4].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT32); busInfo[4].numElems = 1; busInfo[5].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 5); busInfo[5].elemSize = dtaGetDataTypeSize(dta, bpath, SS_DOUBLE); busInfo[5].numElems = 1; busInfo[6].offset = dtaGetDataTypeElementOffset(dta, bpath, CAN_MESSAGE_BUSId, 6); busInfo[6].elemSize = dtaGetDataTypeSize(dta, bpath, SS_UINT8); busInfo[6].numElems = 8; busInfo[7].elemSize = dtaGetDataTypeSize(dta, bpath, CAN_MESSAGE_BUSId); busInfo[7].numElems = ssGetOutputPortWidth(S, 0); ssSetUserData(S, busInfo); /* Allocate memory for arrays or nested arrays of buses DWork pointers */ } #endif /* MDL_START */ /* Function: mdlOutputs ======================================================= * */ static void mdlOutputs(SimStruct *S, int_T tid) { const uint32_T *id = (uint32_T *) ssGetInputPortRealSignal(S, 0); const uint8_T *dlc = (uint8_T *) ssGetInputPortRealSignal(S, 1); const uint8_T *data = (uint8_T *) ssGetInputPortRealSignal(S, 2); char *canFrame = (char *) ssGetOutputPortSignal(S, 0); busInfoStruct* busInfo = (busInfoStruct *) ssGetUserData(S); /* Temporary bus copy declarations */ CAN_MESSAGE_BUS _canFrameBUS; slDataTypeAccess *dta = ssGetDataTypeAccess(S); const char *bpath = ssGetPath(S); /*Copy from Simulink to bus structure*/ canReceive_Outputs_wrapper(id, dlc, data, &_canFrameBUS); /*Copy from bus structure to Simulink*/ /*Copy from _canFrameBUS to Simulink for Output port 0*/ *((uint8_T*)((char *) canFrame + busInfo[0].offset)) = (_canFrameBUS).Extended; *((uint8_T*)((char *) canFrame + busInfo[1].offset)) = (_canFrameBUS).Length; *((uint8_T*)((char *) canFrame + busInfo[2].offset)) = (_canFrameBUS).Remote; *((uint8_T*)((char *) canFrame + busInfo[3].offset)) = (_canFrameBUS).Error; *((uint32_T*)((char *) canFrame + busInfo[4].offset)) = (_canFrameBUS).ID; *((real_T*)((char *) canFrame + busInfo[5].offset)) = (_canFrameBUS).Timestamp; (void) memcpy((char *) canFrame + busInfo[6].offset, (_canFrameBUS).Data, 8* busInfo[6].elemSize); } /* Function: mdlTerminate ===================================================== * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was * allocated in mdlStart, this is the place to free it. */ static void mdlTerminate(SimStruct *S) { /* Free stored bus information */ busInfoStruct *busInfo = (busInfoStruct *) ssGetUserData(S); if (busInfo != NULL) { free(busInfo); } if (!isBusDWorkPresent) { } } static int_T GetRTWEnvironmentMode(SimStruct *S) { int_T status = -1; mxArray *plhs[1]; mxArray *prhs[1]; mxArray * err; /* * Get the name of the Simulink block diagram */ prhs[0] = mxCreateString(ssGetBlockDiagramName(S)); plhs[0] = NULL; /* * Call "isSimulationTarget = rtwenvironmentmode(modelName)" in MATLAB */ err = mexCallMATLABWithTrap(1, plhs, 1, prhs, "rtwenvironmentmode"); mxDestroyArray(prhs[0]); /* * Set the error status if an error occurred */ if (err) { if (plhs[0]) { mxDestroyArray(plhs[0]); plhs[0] = NULL; } ssSetLocalErrorStatus(S, "Unknown error during call to 'rtwenvironmentmode'."); return -1; } /* * Get the value returned by rtwenvironmentmode(modelName) */ if (plhs[0]) { status = (int_T) (mxGetScalar(plhs[0]) != 0); mxDestroyArray(plhs[0]); plhs[0] = NULL; } return (status); } #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