📄 s0_usertel_rxd.c
字号:
/******************************************************************************/
/* */
/* Name: s0_userTel_rxd.c - S-Function for the communication using the */
/* asynchronous serial interface S0 */
/* */
/******************************************************************************/
// =============================================================================
// FW-01-03
//
// level 2 s-function
//
// To recompile this s-function into a Windows DLL use: 'recompile(name_of_the_mod_to_be_comp)'
// (==> <toolbox>\C167\MC\recomp.m)
//
// error numbers: 34 -> 39
// =============================================================================
#define S_FUNCTION_NAME s0_userTel_rxd
#define S_FUNCTION_LEVEL 2
/* undefine VERBOSE to run this DLL in silent mode */
//#define VERBOSE
#include <string.h> /* memcpy, memcmp */
#include <simstruc.h>
#ifdef MATLAB_MEX_FILE
#define abort_LED(x) return
#else
#include "reg167_sfr.h" /* adapted for GCC-166 (HighTec), C167CR, FW-06-01 */
#include "reg167_sbit.h" /* adapted for GCC-166 (HighTec), C167CR, FW-06-01 */
#include "mc_signal.h" /* abort_LED, etc. */
#endif
// -------------------------------------------------------------------------------
// Number of S-function Parameters and macros to access from the SimStruct
// -------------------------------------------------------------------------------
#define SAMPLE_TIME_ARG ssGetSFcnParam(S,0) /* Sample time in seconds */
#define CHANNEL_NO_ARG ssGetSFcnParam(S,1) /* communication channel number (up to MAX_UCOM_CHANNELS) */
#define NUM_ELEMENTS_ARG ssGetSFcnParam(S,2) /* block output width -> # of elements */
#define DATA_TYPE_ARG ssGetSFcnParam(S,3) /* data type to be expected at block input */
#define NUMBER_OF_ARG 4 /* Number of input arguments */
// -------------------------------------------------------------------------------
// Macros to access the S-function parameter values
// -------------------------------------------------------------------------------
#define SAMPLE_TIME ((real_T) mxGetPr (SAMPLE_TIME_ARG)[0])
#define CHANNEL_NO ((uint_T) mxGetPr (CHANNEL_NO_ARG)[0])
#define NUM_ELEMENTS ((uint_T) mxGetPr (NUM_ELEMENTS_ARG)[0])
#define DATA_TYPE ((int_T) mxGetPr (DATA_TYPE_ARG)[0])
// ----------------------------------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------------------------------
// input signals may have the following bytes per element
const int_T BuiltInDTypeSizeR[8] = {
4, /* real32_T */
1, /* int8_T */
1, /* uint8_T */
2, /* int16_T */
2, /* uint16_T */
4, /* int32_T */
4, /* uint32_T */
2 /* boolean_T */
};
// ----------------------------------------------------------------------------------------------------
// local methods
// ----------------------------------------------------------------------------------------------------
// declaration of global user communication admin variables (only relevant for the target module, defined in ext_srv.h)
#include "s0_usertel.h"
/* allocate and initialise the communication variables associated with a particular channel (buffer, admin, ... ) */
static myUsrBuf *AllocateUserBuffer(uint_T channel, uint_T bufsize, uint8_T data_type_len) {
uint8_T *buf;
static myUsrBuf *admin = NULL;
/* allocate memory for admin structure of this instance's data buffer */
if((admin = (myUsrBuf *)calloc(1, sizeof(myUsrBuf))) == NULL) return NULL;
/* allocate memory for the buffer itself (buf_size '+ 4' -> telegram size, channel number, '0 0' [reserved]) */
/* the additional '+3' has been introduced to allow safe byte-swapping -- required on the 9S12... fw-03-05 */
/* (the order of every group of 4 bytes gets reversed -> uint8_T transmissions might just end up on '+1' -> '+3' makes it dword aligned) */
if((buf = (uint8_T *)calloc(bufsize + 4 + 3, sizeof(uint8_T))) == NULL) return NULL;
/* store pointer to buf in the admin structure */
admin->buf = buf;
/* store size of the actual data buffer */
admin->buf_size = bufsize;
/* initialise the access_count field */
admin->access_count = 1;
/* initialise the buffer_full flag */
admin->buffer_full = 0;
/* initialise buffer */
/* set first field of the buffer to the number of bytes per user telegram (remains invariant)... */
buf[0] = (uint8_T)(bufsize + 4);
/* set second field of the buffer to the channel number (remains invariant)... */
buf[1] = (uint8_T)channel;
/* set third field of the buffer to the channel data type length: 1, 2, 4) (remains invariant)... */
buf[2] = data_type_len;
/* ... and clear the reserved byte (buf[3]) as well as the local data buffer */
memset(&buf[3], 0, bufsize + 1);
/* return access pointer */
return admin;
}
// ----------------------------------------------------------------------------------------------------
// S-Function methods
// ----------------------------------------------------------------------------------------------------
/* Function: mdlCheckParameters ===============================================
*
*/
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS)
static void mdlCheckParameters(SimStruct *S)
{
// check common parameter (SAMPLE_TIME, S1BAUDRATE)
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_UCOM_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) ||
(BuiltInDTypeSizeR[DATA_TYPE-1] * NUM_ELEMENTS > MAX_BUF_SIZE)) abort_LED(38); // inadmissible buffer size
}
#endif /* MDL_CHECK_PARAMETERS */
/* Function: mdlInitializeSizes ===============================================
*
*/
static void mdlInitializeSizes (SimStruct *S)
{
int 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, 0); // no instance-local integer values
//ssSetNumRWork (S, 0); // no instance-local real values
ssSetNumPWork (S, 1); // instance-local pointer: access to this channel's buffer 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 no input...
if(!ssSetNumOutputPorts(S, 1)) abort_LED(39); // ... and a single output (-> source)
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)
{
void **PWork = ssGetPWork(S);
uint8_T data_type = BuiltInDTypeSizeR[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;
#ifdef MATLAB_MEX_FILE
/* host S-Function (DLL) */
{
mxArray *BufferAdminVar;
myUsrBuf *admin, **myPtr;
int_T i;
/* all admin variables associated with a buffer are communicated via the workspace variable 'BufferAdminVar' */
//mexPrintf("s0_usertel_rxd: mdlStart.\n");
/* check if variable 'BufferAdminVar' exists in the base workspace */
if((BufferAdminVar = mexGetVariable("base", "BufferAdminVar")) == NULL) {
/* BufferAdminVar doesn't exist -> create & initialise it */
BufferAdminVar = mxCreateNumericMatrix(MAX_UCOM_CHANNELS, 1, mxUINT32_CLASS, mxREAL);
/* initialise the array to be stored in variable BufferAdminVar */
myPtr = (myUsrBuf **)mxGetPr(BufferAdminVar);
/* initialise all pointers with NULL */
for(i=0; i<MAX_UCOM_CHANNELS; i++) myPtr[i] = NULL;
/* allocate memory for buffer (buf_size bytes) and its admin structure, returns the access pointer */
if((admin = AllocateUserBuffer(CHANNEL_NO, buf_size, data_type)) == NULL) {
mexErrMsgTxt("s0_usertel_rxd: Problem during memory allocation [insufficient memory].\n");
}
//mexPrintf("Channel %d access count: %d\n", CHANNEL_NO, admin->access_count);
/* store the access pointer in the workspace variable */
myPtr[CHANNEL_NO] = admin;
/* retain a local copy for fast access */
PWork[0] = admin;
/* export variable BufferAdminVar to the base workspace */
mexPutVariable("base", "BufferAdminVar", BufferAdminVar);
}
else {
/* BufferAdminVar exist */
myPtr = (myUsrBuf **)mxGetPr(BufferAdminVar);
/* check if the buffer has already been initialised */
if(myPtr[CHANNEL_NO] == NULL) {
/* this channel has not been initialised yet -> do so now... */
if((admin = AllocateUserBuffer(CHANNEL_NO, buf_size, data_type)) == NULL) {
mexErrMsgTxt("s0_usertel_rxd: Problem during memory allocation [insufficient memory].\n");
}
//mexPrintf("Channel %d access count: %d\n", CHANNEL_NO, admin->access_count);
/* store the access pointer in the workspace variable */
myPtr[CHANNEL_NO] = admin;
/* retain a local copy for fast access */
PWork[0] = admin;
/* export variable BufferAdminVar to the base workspace */
mexPutVariable("base", "BufferAdminVar", BufferAdminVar);
}
else {
/* channel already initialised (rxd side) -> fetch it from there... */
admin = myPtr[CHANNEL_NO];
/* ... and increase access count (to '2') */
admin->access_count++;
//mexPrintf("Channel %d access count: %d\n", CHANNEL_NO, admin->access_count);
/* retain a local copy for fast access */
PWork[0] = admin;
}
}
} /* context */
#else
/* target S-Function */
{
myUsrBuf *admin;
/* allocate memory for buffer (BUF_SIZE bytes) and its admin structure, returns the access pointer */
if((admin = AllocateUserBuffer(CHANNEL_NO, buf_size)) == NULL) abort_LED(34);
/* store the access pointer in the workspace variable */
userTelBuf[CHANNEL_NO] = admin;
/* retain a local copy for fast access */
PWork[0] = admin;
}
#endif
}
/*
* 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)
{
myUsrBuf *admin = ssGetPWorkValue(S, 0);
/* check 'buffer full' flag */
if(admin->buffer_full == 1) {
uint_T size = admin->buf_size;
uint8_T *buf = (uint8_T *)&(admin->buf[4]);
uint8_T *blockOutput = (uint8_T *)ssGetOutputPortSignal(S, 0);
/* new data for this instance available -> copy data to the block outputs (data begins at index 4) */
memcpy(blockOutput, buf, size);
/* reset 'buffer full flag' */
admin->buffer_full = 0;
#ifdef MATLAB_MEX_FILE
#ifdef VERBOSE
/* host DLL -> echo... */
{
uint_T i;
mexPrintf("RxD < Channel[%d] ", (uint_T)(admin->buf[1]));
/* new buffer... */
for(i=0; i<size; i++)
mexPrintf(":%d", (uint_T)buf[i]);
mexPrintf(":\n");
}
#endif /* VERBOSE */
#endif /* MATLAB_MEX_FILE */
}
}
/*
* 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)
{
myUsrBuf *admin = ssGetPWorkValue(S, 0);
#ifdef MATLAB_MEX_FILE
/* host S-Function (DLL) */
{
mxArray *BufferAdminVar;
myUsrBuf **myPtr;
/* check if this is the last remaining access to this channel */
if(admin->access_count == 1) {
/* yep -> close channel and free memory */
free(admin->buf);
free(admin);
/* update workspace variable 'BufferAdminVar' */
if((BufferAdminVar = mexGetVariable("base", "BufferAdminVar")) == NULL) {
mexErrMsgTxt("s0_usrtel_rxd: Error accessing workspace variable BufferAdminVar (mdlTerminate).\n");
}
else {
/* get base access pointer */
myPtr = (myUsrBuf **)mxGetPr(BufferAdminVar);
/* reset the channel specific access pointer */
myPtr[CHANNEL_NO] = NULL;
/* re-export variable BufferAdminVar to the base workspace */
mexPutVariable("base", "BufferAdminVar", BufferAdminVar);
}
}
else {
/* decrease access counter, channel will be closed from the other side */
admin->access_count--;
//mexPrintf("Channel %d access count: %d\n", CHANNEL_NO, admin->access_count);
}
}
#else
/* target S-Function */
{
/* free instance local data buffer */
free(admin->buf);
free(admin);
/* reset global buffer access pointer to NULL */
userTelBuf[CHANNEL_NO] = NULL;
}
#endif
}
// the define 'MATLAB_MEX_FILE' has to be specified when recompiling this module to a DLL.
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -