📄 freeportcomms_rxd.c
字号:
/* Function: mdlCheckParameters ===============================================
*
*/
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS)
static void mdlCheckParameters(SimStruct *S)
{
// check parameter: SAMPLE_TIME
if (mxGetNumberOfElements(SAMPLE_TIME_ARG) != 1) abort_LED(36); // parameter must be a scalar
if ((SAMPLE_TIME < 0) && (SAMPLE_TIME != INHERITED_SAMPLE_TIME)) abort_LED(36); // invalid negative sample time
// check parameter: CHANNEL_NO
if (mxGetNumberOfElements(CHANNEL_NO_ARG) != 1) abort_LED(37); // parameter must be a scalar
if ((CHANNEL_NO < 0) || (CHANNEL_NO >= MAX_FREECOM_CHANNELS)) abort_LED(37); // invalid channel number
// check parameter: NUM_ELEMENTS
if (mxGetNumberOfElements(NUM_ELEMENTS_ARG) != 1) abort_LED(38); // parameter must be a scalar
if ((NUM_ELEMENTS < 1) ||
(BuiltInDTypeSize[DATA_TYPE-1] * NUM_ELEMENTS > MAX_FREECOM_BUF_SIZE)) abort_LED(38); // inadmissible buffer size
}
#endif /* MDL_CHECK_PARAMETERS */
/* Function: mdlInitializeSizes ===============================================
*
*/
static void mdlInitializeSizes (SimStruct *S) {
int_T i;
ssSetNumSFcnParams(S, NUMBER_OF_ARG); // expected number of parameters
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) abort_LED(35); // incorrect number of parameters
else {
#ifdef MDL_CHECK_PARAMETERS
mdlCheckParameters(S); // check all parameters
#endif
}
/* setup sizes of both work vectors and state vectors */
ssSetNumIWork (S, 1); // instance-local integer value: channel number
//ssSetNumRWork (S, 0); // no instance-local real values
ssSetNumPWork (S, 1); // instance-local pointer: access to this channel's port access structure
//ssSetNumDWork (S, 0); // no instance-local user data types used
//ssSetNumContStates (S, 0); // width of the instance-local vector of continuous states
//ssSetNumDiscStates (S, 0); // width of the instance-local vector of discrete states
/* define number of sample times used by this s-function */
ssSetNumSampleTimes (S, 1); // only 'one' sampletime in this S-Function
// None of this s-functions's parameters are tunable during simulation (sample time, channel, buffer size, data type)
for (i=0; i<NUMBER_OF_ARG; i++) ssSetSFcnParamNotTunable(S, i);
if(!ssSetNumInputPorts(S, 0)) abort_LED(39); // block has a single input...
if(!ssSetNumOutputPorts(S, 1)) abort_LED(39); // ... and no output (-> sink)
ssSetOutputPortWidth(S, 0, NUM_ELEMENTS); // block output width : number of elements
ssSetOutputPortDataType(S, 0, DATA_TYPE); // data type: '1' = 'single', '2' = 'int8_T', ... (no '0' -> no 'double')
}
/* Function: mdlInitializeSampleTimes =========================================
*
*/
static void mdlInitializeSampleTimes (SimStruct *S) {
ssSetSampleTime(S, 0, SAMPLE_TIME); // this S-Function only has 'one' sampletime -> index '0'
ssSetOffsetTime(S, 0, 0.0);
}
/* Function: mdlStart =========================================================
*
*/
#define MDL_START
static void mdlStart(SimStruct *S) {
/* make sure this instance relatest to a COM port -> host model (PORT = 3 -> COM1, PORT = 4 -> COM2, etc.) */
if(PORT > 2) {
void **PWork = ssGetPWork(S);
uint8_T data_type = BuiltInDTypeSize[DATA_TYPE-1]; // first possible 'DATA_TYPE' is '1' ('sinle') -> map this to '0' (beginning of array)
uint_T buf_size = data_type * NUM_ELEMENTS;
mxArray *FreePortAdminVar;
myCOMPort **myPtr;
myUsrBuf *admin;
myCOMPort *adminP = NULL;
uint_T i, *IWork = ssGetIWork(S);
#ifdef VERBOSE
mexPrintf("freePortComms_rxd|mdlStart: IN\n");
#endif /* VERBOSE */
/* ensure we're using channel '0' for raw data transmissions */
if(FORMAT == 1) IWork[0] = 0;
else IWork[0] = CHANNEL_NO;
/* create 'FreePortAdminVar' in the base workspace -- if required (first use) */
if((FreePortAdminVar = mexGetVariable("base", "FreePortAdminVar")) == NULL) {
/* FreePortAdminVar doesn't exist -> create & initialise it */
FreePortAdminVar = mxCreateNumericMatrix(MAX_NUM_COM_PORTS, 1, mxUINT32_CLASS, mxREAL);
/* initialise the array to be stored in variable FreePortAdminVar */
myPtr = (myCOMPort **)mxGetPr(FreePortAdminVar);
/* initialise all COM port access pointers with NULL */
for(i=0; i<MAX_NUM_COM_PORTS; i++) myPtr[i] = NULL;
#ifdef VERBOSE
mexPrintf("FreePortAdminVar created\n");
#endif /* VERBOSE */
}
else {
/* 'FreePortAdminVar' already exists -> get pointer to data in FreePortAdminVar */
myPtr = (myCOMPort **)mxGetPr(FreePortAdminVar);
#ifdef VERBOSE
mexPrintf("FreePortAdminVar found in workspace.\n");
#endif /* VERBOSE */
}
/* allocate memory for buffer (buf_size bytes) for channel 'IWork[0]' and its admin structure, returns the access pointer */
if((admin = AllocateUserBuffer(IWork[0], buf_size, data_type)) == NULL) {
mexErrMsgTxt("FreePortComms_rxd: Problem during memory allocation [insufficient memory, admin].\n");
}
/* store the access pointer in the global buffer contents variable */
freecomTelBuf[IWork[0]] = admin; /* IWork[0] = instance local channel number */
/* only open port if it's not already open */
if(myPtr[PORT-3] == NULL) {
/* allocate memory for admin structure of this instance's COM port access */
if((adminP = (myCOMPort *)calloc(1, sizeof(myCOMPort))) == NULL) {
mexErrMsgTxt("FreePortComms_rxd: Problem during memory allocation [insufficient memory, adminP].\n");
}
/* initialize port access structure */
adminP->access_count = 0;
adminP->hCom = FreePortOpenConnection(S);
/* store port access pointer in workspace variable */
myPtr[PORT-3] = adminP;
}
/* initialize instance local pointer to the port access structure */
PWork[0] = myPtr[PORT-3];
/* increase port access pointer */
myPtr[PORT-3]->access_count += 1;
/* export variable FreePortAdminVar to the base workspace */
mexPutVariable("base", "FreePortAdminVar", FreePortAdminVar);
#ifdef VERBOSE
mexPrintf("freePortComms_rxd|mdlStart: OUT\n");
#endif /* VERBOSE */
} /* COM port */
}
/*
* mdlOutputs - compute the outputs
*
* In this function, you compute the outputs of your S-function
* block. The outputs are placed in the y variable.
*/
static void mdlOutputs(SimStruct *S, int_T tid) {
/* make sure this instance relatest to a COM port -> host model (PORT = 3 -> COM1, PORT = 4 -> COM2, etc.) */
if(PORT > 2) {
uint_T *IWork = ssGetIWork(S); /* channel number */
uint16_T channel;
myUsrBuf *admin;
uint16_T size;
uint8_T *buf;
uint8_T *blockOutput = (uint8_T *)ssGetOutputPortSignal(S, 0);
myCOMPort *adminP = ssGetPWorkValue(S, 0);
/* check COM port for newly arrived data */
if(checkCOMforData(adminP->hCom) > 0) {
if(FORMAT == 0) {
/* formatted telegrams -> receive header */
uint8_T myBuf[4];
#ifdef VERBOSE
mexPrintf("%d bytes in buffer\n", checkCOMforData(adminP->hCom));
#endif
/* receive first 4 data bytes from serial port buffer */
if (!Receive (adminP->hCom, myBuf, 4, &ReceiveTimeoutFlag, with_to_messages)) {
mexErrMsgTxt("freePortComms_rxd: Error during reception of first 4 bytes.\n");
}
#ifdef VERBOSE
mexPrintf("Header: %d:%d:%d:%d\n", (uint16_T)myBuf[0], (uint16_T)myBuf[1], (uint16_T)myBuf[2], (uint16_T)myBuf[3]);
#endif /* VERBOSE */
/* determine telegram size, etc. */
channel = myBuf[1];
} else {
/* unformatted data -> take channel number from IWork[0] */
channel = IWork[0];
}
/* all remaining parameters are independent of the telegram format */
admin = freecomTelBuf[channel];
size = admin->buf_size;
buf = admin->buf;
/* receive remaining 'size' data bytes from serial port buffer */
if (!Receive (adminP->hCom, buf, size, &ReceiveTimeoutFlag, with_to_messages)) {
mexErrMsgTxt("freePortComms_rxd: Error during reception of remaining bytes.\n");
}
#ifdef VERBOSE
/* host DLL -> echo... */
{
uint_T i;
mexPrintf("RxD < Channel[%d] ", channel);
/* new buffer... */
for(i=0; i<size; i++)
mexPrintf(":%d", (uint_T)buf[i]);
mexPrintf(":\n");
}
#endif /* VERBOSE */
/* indicate receipt of a telegram */
admin->buffer_full = 1;
} /* checkCOMforData() */
/* check if output of this instance needs updated... */
admin = freecomTelBuf[IWork[0]]; /* IWork[0] : channel number */
if(admin->buffer_full) {
/* new data available -> descramble */
{
unsigned int fi;
unsigned int mydType = DATA_TYPE-1;
unsigned char *pbuf = receivebuf;
for(fi=0; fi<NUM_ELEMENTS; fi++) {
/* single : ID = 0 */
/* int8 : ID = 1 */
/* uint8 : ID = 2 */
/* int16 : ID = 3 */
/* uint16 : ID = 4 */
/* int32 : ID = 5 */
/* uint32 : ID = 6 */
/* boolean : ID = 7 */
switch(mydType) {
case tSINGLE:
{
float *pData = (float *)buf;
float tData = (float)pData[fi];
*((float *)pbuf) = *(float *)(ReverseOrder4((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tINT8:
*((int8_T *)pbuf) = (int8_T)(buf[fi]);
pbuf += BuiltInDTypeSize[mydType];
break;
case tUINT8:
*((uint8_T *)pbuf) = (uint8_T)(buf[fi]);
pbuf += BuiltInDTypeSize[mydType];
break;
case tINT16:
{
int16_T *pData = (int16_T *)buf;
int16_T tData = (int16_T)pData[fi];
*((int16_T *)pbuf) = *(int16_T *)(ReverseOrder2((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tUINT16:
{
uint16_T *pData = (uint16_T *)buf;
uint16_T tData = (uint16_T)pData[fi];
*((uint16_T *)pbuf) = *(uint16_T *)(ReverseOrder2((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tINT32:
{
int32_T *pData = (int32_T *)buf;
int32_T tData = (int32_T)pData[fi];
*((int32_T *)pbuf) = *(int32_T *)(ReverseOrder4((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tUINT32:
{
uint32_T *pData = (uint32_T *)buf;
uint32_T tData = (uint32_T)pData[fi];
*((uint32_T *)pbuf) = *(uint32_T *)(ReverseOrder4((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tBOOLEAN:
{
boolean_T *pData = (boolean_T *)buf;
boolean_T tData = (boolean_T)pData[fi];
*((boolean_T *)pbuf) = *(boolean_T *)(ReverseOrder2((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
//*((boolean *)pbuf) = (boolean)(pData[fi]);
//pbuf += BuiltInDTypeSize[mydType];
break;
} /* switch(mydType) */
} /* for */
} /* descramble */
/* new data might be for this instance -> copy appropriate data to the block outputs */
#ifdef VERBOSE
mexPrintf("Copying %d bytes to output of channel %d\n", admin->buf_size, IWork[0]);
#endif
/* new data available for this instance -> update output */
memcpy(blockOutput, receivebuf, admin->buf_size);
/* clear buffer full flag */
admin->buffer_full = 0;
} /* admin-buffer_full == 1 */
} /* COM port */
}
/*
* mdlTerminate - called when the simulation is terminated.
*
* In this function, you should perform any actions that are necessary
* at the termination of a simulation. For example, if memory was allocated
* in mdlInitializeConditions, this is the place to free it.
*/
static void mdlTerminate (SimStruct *S) {
/* make sure this instance relatest to a COM port -> host model (PORT = 3 -> COM1, PORT = 4 -> COM2, etc.) */
if(PORT > 2) {
mxArray *FreePortAdminVar;
uint_T *IWork = ssGetIWork(S); /* channel number */
/* update workspace variable 'FreePortAdminVar' */
if((FreePortAdminVar = mexGetVariable("base", "FreePortAdminVar")) == NULL) {
// do nothing, just exit
mexErrMsgTxt("freePortComms_rxd: Error accessing workspace variable FreePortAdminVar (mdlTerminate).\n");
}
else {
myUsrBuf *admin = freecomTelBuf[IWork[0]]; /* IWork[0] : channel number */
myCOMPort **myPtr;
/* yep -> close channel and free memory */
free(admin->buf);
free(admin);
/* reset the channel specific access pointer */
freecomTelBuf[IWork[0]] = NULL; /* IWork[0] : channel number */
/* get FreePortAdminVar */
myPtr = (myCOMPort **)mxGetPr(FreePortAdminVar);
/* decrement port access pointer */
myPtr[PORT-3]->access_count -= 1;
/* check access counter */
if(myPtr[PORT-3]->access_count == 0) {
/* close port */
FreePortCloseConnection(myPtr[PORT-3]->hCom);
/* delete port access structure */
free(myPtr[PORT-3]);
myPtr[PORT-3] = NULL;
}
/* export variable FreePortAdminVar to the base workspace */
mexPutVariable("base", "FreePortAdminVar", FreePortAdminVar);
} /* FreePortAdminVar exists */
} /* COM port */
}
// the define 'MATLAB_MEX_FILE' has to be specified when recompiling this module to a DLL.
// this is only required if the format of the call-up parameters is modified... (FW-06-01)
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
# error "Attempt to use freePortComms_rxd.c as non-inlined S-function"
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -