📄 freeportcomms_txd.c
字号:
}
#endif /* VERBOSE */
temp = buf[0];
buf[0] = buf[3];
buf[3] = temp;
temp = buf[1];
buf[1] = buf[2];
buf[2] = temp;
#ifdef VERBOSE
{
mexPrintf("%d:%d:%d:%d\n", buf[0], buf[1], buf[2], buf[3]);
}
#endif /* VERBOSE */
return (void *)buf;
}
/* Function: ReverseOrder2 =================================================
*
* Reverse the order of bytes in a 2-tuple
*/
void *ReverseOrder2(unsigned char *buf) {
unsigned char temp;
#ifdef VERBOSE
{
mexPrintf("ReverseOrder2 %d:%d >> ", buf[0], buf[1]);
}
#endif /* VERBOSE */
temp = buf[0];
buf[0] = buf[1];
buf[1] = temp;
#ifdef VERBOSE
{
mexPrintf("%d:%d\n", buf[0], buf[1]);
}
#endif /* VERBOSE */
return (void *)buf;
}
// ----------------------------------------------------------------------------------------------------
// S-Function methods
// ----------------------------------------------------------------------------------------------------
/* 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, 1)) abort_LED(39); // block has a single input...
if(!ssSetNumOutputPorts(S, 0)) abort_LED(39); // ... and no output (-> sink)
ssSetInputPortWidth(S, 0, NUM_ELEMENTS); // input width: number of elements
//mexPrintf("Data type: %d\n", DATA_TYPE);
ssSetInputPortDataType(S, 0, DATA_TYPE); // block initialization code (mbc_userteltxd.m) adjusts this to '1' ... (no '0' = 'double')
ssSetInputPortDirectFeedThrough(S, 0, 1); // direct feedthrough (only executs after update of inputs)
ssSetInputPortRequiredContiguous(S, 0, 1); // ports to be stored contiguously in memory
}
/* 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) {
/* check if this instance relates 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' ('single') -> 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_txd|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;
}
else {
/* 'FreePortAdminVar' already exists -> get pointer to data in FreePortAdminVar */
myPtr = (myCOMPort **)mxGetPr(FreePortAdminVar);
}
/* 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_txd: 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_txd: 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_txd|mdlStart: OUT\n");
#endif /* VERBOSE */
}
}
/*
* 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) {
/* check if this instance relates to a COM port -> host model (PORT = 3 -> COM1, PORT = 4 -> COM2, etc.) */
if(PORT > 2) {
uint_T *IWork = ssGetIWork(S); /* channel number */
myUsrBuf *admin = freecomTelBuf[IWork[0]];
uint_T size = admin->buf_size;
uint8_T *buf = admin->buf;
uint8_T *blockInput = (uint8_T *)ssGetInputPortSignal(S, 0);
myCOMPort *adminP = ssGetPWorkValue(S, 0);
/* buffer empty -> check if new user data has arrived */
if(memcmp(buf+4, blockInput, (uint16_T)size) != 0) {
/* new data available -> copy to data buffer */
memcpy(buf+4, blockInput, (uint16_T)size);
/* copy data to transmission buffer */
{
unsigned int fi;
unsigned int mydType = DATA_TYPE-1;
unsigned char *pbuf = sendbuf;
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+4);
float tData = (float)pData[fi];
*((float *)pbuf) = *(float *)(ReverseOrder4((unsigned char *)&tData));
pbuf += BuiltInDTypeSize[mydType];
}
break;
case tINT8:
*((int8_T *)pbuf) = (int8_T)(buf[4+fi]);
pbuf += BuiltInDTypeSize[mydType];
break;
case tUINT8:
*((uint8_T *)pbuf) = (uint8_T)(buf[4+fi]);
pbuf += BuiltInDTypeSize[mydType];
break;
case tINT16:
{
int16_T *pData = (int16_T *)(buf+4);
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+4);
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+4);
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+4);
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+4);
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 */
} /* copy elements to transmission buffer */
/* download data to the target */
if(FORMAT == 0) {
/* formatted telegram */
#ifdef VERBOSE
{
uint_T i;
mexPrintf("TxD > Channel[%d] ", IWork[0]);
/* new buffer... */
for(i=4; i<size+4; i++)
mexPrintf(":%d", sendbuf[i]);
mexPrintf(":\n");
}
#endif /* VERBOSE */
#ifdef VERBOSE
mexPrintf("Sending header... ");
#endif /* VERBOSE */
Send(adminP->hCom, buf, (DWORD)4, no_echo, &SendTimeoutFlag, with_to_messages);
}
/* raw data */
#ifdef VERBOSE
mexPrintf("sending data (%d bytes).\n", size);
#endif /* VERBOSE */
Send(adminP->hCom, sendbuf, (DWORD)size, no_echo, &SendTimeoutFlag, with_to_messages);
} /* if : new user data available */
} /* 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) {
/* check if this instance relates 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_txd: 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_txd.c as non-inlined S-function"
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -