📄 freeportcomms_rxd.c
字号:
/******************************************************************************/
/* */
/* Name: freePortComms_rxd.c - S-Function for the communication using the */
/* second asynchronous serial interface SCI0/1 */
/* */
/******************************************************************************/
// =============================================================================
// fw-04-05
//
// level 2 s-function
//
// =============================================================================
#define S_FUNCTION_NAME freePortComms_rxd
#define S_FUNCTION_LEVEL 2
/* undefine VERBOSE to run this DLL in silent mode */
//#define VERBOSE
#include <simstruc.h>
#include <windows.h> // BuildCommDCB, CloseHandle, CreateFile, EscapeCommFunction, GetCommState,
// GetLastError, ReadFile, SetCommState, SetCommTimeouts, WriteFile, FlushFileBuffers
// Sleep
#include <stdio.h> // sprintf
#include <stdlib.h> // malloc, calloc
#include <string.h> // memcpy
#ifdef MATLAB_MEX_FILE
#define abort_LED(x) return
#else
#include "mc_signal.h" /* abort_LED, etc. */
#endif
// declaration of global user communication admin variables (only relevant for the target module, defined in ext_srv.h)
#include "freePortComms.h"
// DEFINE global user communication admin variables ( initialised in mc_main->Init_ComVars() )
myUsrBuf *freecomTelBuf[MAX_FREECOM_CHANNELS]; /* pointer to the data buffer admin structures of all user telegrams */
/* receive */
BOOL ReceiveTimeoutFlag;
// flag : communication with/without echo?
#define with_echo TRUE
#define no_echo FALSE
// flag : display on-screen timeout messages?
#define with_to_messages TRUE
#define no_to_messages FALSE
// -------------------------------------------------------------------------------
// 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_FREECOM_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 PORT_ARG ssGetSFcnParam(S,4) /* communication port ([COM]1 - [COM]4) */
#define BAUDRATE_ARG ssGetSFcnParam(S,5) /* baudrate (300 [bps] - 115200 [bps]) */
#define FORMAT_ARG ssGetSFcnParam(S,6) /* format (0: formatted, 1: unformatted */
#define NUMBER_OF_ARG 7 /* 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 ((uint_T) mxGetPr (DATA_TYPE_ARG)[0])
#define PORT ((uint_T) mxGetPr (PORT_ARG)[0])
#define BAUDRATE ((uint32_T) mxGetPr (BAUDRATE_ARG)[0])
#define FORMAT ((uint_T) mxGetPr (FORMAT_ARG)[0])
// ----------------------------------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------------------------------
// input signals may have the following bytes per element
const int_T BuiltInDTypeSize[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 */
};
#define tSINGLE 0
#define tINT8 1
#define tUINT8 2
#define tINT16 3
#define tUINT16 4
#define tINT32 5
#define tUINT32 6
#define tBOOLEAN 7
// map BAUDRATE parameter (1 - 10) to true baudrates
const DWORD BaudRates[10] = {
300,
600,
1200,
2400,
4800,
9600,
19200,
38400,
57600,
115200
};
/* descramble buffer ... (fw-09-06) */
unsigned char receivebuf[MAX_FREECOM_BUF_SIZE + 10];
// ----------------------------------------------------------------------------------------------------
// local methods
// ----------------------------------------------------------------------------------------------------
/* 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, data type length, '0' [reserved]) */
if((buf = (uint8_T *)calloc(bufsize + 4, 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;
//mexPrintf("Setting channel %d data type length to: %d\n", channel, 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;
}
/* Function: checkCOMforData ===================================================
* check if there's data in the COM buffer (FW-09-02)
*/
static int checkCOMforData(HANDLE hCom) {
COMSTAT cs;
DWORD error;
/* only check port if 'hCom' is valid... */
if (hCom != INVALID_HANDLE_VALUE) {
// reset error status (returns structure COMSTAT [winbase.h])
if(!ClearCommError(hCom, (LPDWORD)&error, (LPCOMSTAT)&cs)) {
// error during call to ClearCommError
mexPrintf("checkCOM4data: Error during call to ClearCommError.\n");
// flag error to the calling function
return -1;
}
else {
// debug
//mexPrintf("FreePort: checkCOMforData detected %d data bytes in COM buffer\n", (int)cs.cbInQue);
// return number of bytes in the buffer
return (int)cs.cbInQue;
}
} else {
/* port handle not valid (not a COM port) */
return -1;
}
} /* end checkCOMforData */
/* Function: FreePortOpenConnection =================================================
*
* Open the connection with the target using the free communication port.
*/
HANDLE FreePortOpenConnection(SimStruct *S) {
HANDLE hCom = INVALID_HANDLE_VALUE;
static char COMxString[5]; // serial interface designator
char COMxStringParam[16];
DCB dcb;
COMMTIMEOUTS CommTimeouts;
char tmp[512]; // error messages
// default communication parameters (dummy)
#define DefaultComParam ":9600,n,8,1"
// default timeout value (ms) - send and receive
#define DefaultTimeout 10000
#ifdef VERBOSE
mexPrintf("freePortComms_rxd|FreePortOpenConnection: IN\n");
#endif /* VERBOSE */
// open serial interface 'COMxString' (PORT = 3 -> COM1, PORT = 4 -> COM2, etc.)
sprintf(COMxString, "COM%1d", (uint8_T)(PORT - 2));
hCom = CreateFile (COMxString, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hCom == INVALID_HANDLE_VALUE) {
sprintf(tmp, "Error while trying to open serial interface %s:\n", COMxString);
mexErrMsgTxt(tmp);
}
// initialise 'DCB' structure
dcb.DCBlength = sizeof (DCB);
if (!GetCommState (hCom, &dcb)) {
mexErrMsgTxt("Error while trying to determine current state of the COM interface.\n");
}
sprintf (COMxStringParam, "%s%s", COMxString, DefaultComParam);
if (!BuildCommDCB (COMxStringParam, &dcb)) {
mexErrMsgTxt("Error while generating DCB data structure,\n");
}
// set transmission parameters
dcb.BaudRate = BaudRates[BAUDRATE-1]; // transmission speed (bps)
dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS = 'low' (mis-used to generate a software 'reset'...
dcb.fOutX = FALSE; // disable XON/XOFF protocol
dcb.fInX = FALSE; // (both for TX and RX)
// initialise serial interface 'hCom'
if (!SetCommState (hCom, &dcb)) {
sprintf(tmp, "Error during initialisation of the serial interface %s:\n", COMxString);
mexErrMsgTxt(tmp);
}
// reset 'hCom' and set length of input/output buffer to FREEPORT_HOST_BUF_SIZE (default: 1200) bytes (each)
if (!SetupComm (hCom, FREEPORT_HOST_BUF_SIZE, FREEPORT_HOST_BUF_SIZE)) {
sprintf(tmp, "Error during reset of the serial interface %s:\n", COMxString);
mexErrMsgTxt(tmp);
}
// initialise all timeouts (send/receive) as 'DefaultTimeout' (1000 ms)
CommTimeouts.ReadIntervalTimeout = DefaultTimeout;
CommTimeouts.ReadTotalTimeoutMultiplier = DefaultTimeout;
CommTimeouts.ReadTotalTimeoutConstant = DefaultTimeout;
CommTimeouts.WriteTotalTimeoutMultiplier = DefaultTimeout;
CommTimeouts.WriteTotalTimeoutConstant = DefaultTimeout;
SetCommTimeouts(hCom, &CommTimeouts);
/* make sure we start with an empty buffer... */
if(!FlushFileBuffers(hCom)) {
/* flushing of the output buffer returns unsuccessful... */
mexPrintf ("freePortComms_rxd|FreePortOpenConnection: Error whilst flushing output buffers (FlushFileBuffers).\n");
{
DWORD err = GetLastError();
mexPrintf("Error code: %ld\n", err);
}
}
#ifdef VERBOSE
mexPrintf("freePortComms_rxd|FreePortOpenConnection: OUT\n");
#endif /* VERBOSE */
return hCom;
} /* end ExtOpenConnection */
/* Function: FreePortCloseConnection ================================================
*
* Close the connection via the free comms port.
*/
void FreePortCloseConnection(HANDLE hCom) {
#ifdef VERBOSE
mexPrintf("FreePortCloseConnection: IN\n");
#endif
if (hCom != INVALID_HANDLE_VALUE) {
// close serial interface 'hCom'
if(!CloseHandle(hCom)) {
mexErrMsgTxt("Error when closing the serial interface.\n");
}
}
#ifdef VERBOSE
mexPrintf("FreePortCloseConnection: OUT\n");
#endif
} /* end FreePortCloseConnection */
// =====================================================================================================
// Receive... receive a string from the serial interface 'hCom'
// =====================================================================================================
// CALL-UP PARAMETERS:
//
// '&r_zeichen': store received characters here...
// 'z_len_toread': number of characters to be read
// 'ReceiveTimeoutFlag': TRUE (timeout occurred), FALSE (no timeout)
// 'TimeoutMessageFlag': TRUE (onscreen timeout messages) / FALSE (no messages)
//
// RETURN VALUE: TRUE (successful reception) / FALSE ('reception error' or 'timeout')
BOOL Receive (HANDLE hCom, BYTE r_zeichen[], DWORD z_len_toread,
BOOL *ReceiveTimeoutFlag, BOOL TimeoutMessageFlag)
{
DWORD z_len_read;
*ReceiveTimeoutFlag = FALSE;
if (ReadFile(hCom, (LPSTR) r_zeichen, z_len_toread, &z_len_read, NULL))
{
if (z_len_read == z_len_toread)
{
// successful reception
return (TRUE);
}
else
{
// timeout occurred during reception of data
if (TimeoutMessageFlag == with_to_messages)
ssPrintf ("Receive: Timeout during data reception.\n");
*ReceiveTimeoutFlag = TRUE;
return (FALSE);
}
}
else
{
// unspecified error during data reception
ssPrintf ("Receive: Unspecified error during data reception.\n");
return (FALSE);
}
}
/* Function: ReverseOrder4 =================================================
*
* Reverse the order of bytes in a 4-tuple
*/
void *ReverseOrder4(unsigned char *buf) {
unsigned char temp;
#ifdef VERBOSE
{
mexPrintf("ReverseOrder4 %d:%d:%d:%d >> ", buf[0], buf[1], buf[2], buf[3]);
}
#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
// ----------------------------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -