📄 freeportsend.c
字号:
/******************************************************************************/
/* */
/* Name: freePortSend.c - mex function for the communication to the */
/* free asynchronous serial interface SCI0/1 */
/* */
/******************************************************************************/
// =============================================================================
// fw-10-05
// =============================================================================
/* undefine VERBOSE to run this DLL in silent mode */
//#define VERBOSE
#include "mex.h"
#include "matrix.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
#include "freePortComms.h" // macros, struct myUsrBuf
// ----------------------------------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------------------------------
// input signals may have the following bytes per element
#define numDATATYPES 8
const unsigned int BuiltInDTypeSize[numDATATYPES] = {
4, /* single : ID = 0*/
1, /* int8 : ID = 1 */
1, /* uint8 : ID = 2 */
2, /* int16 : ID = 3 */
2, /* uint16 : ID = 4 */
4, /* int32 : ID = 5 */
4, /* uint32 : ID = 6 */
2 /* boolean : ID = 7 */
};
#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
#define numBAUDRATES 10
const unsigned int BaudRates[numBAUDRATES] = {
300,
600,
1200,
2400,
4800,
9600,
19200,
38400,
57600,
115200
};
// DEFINE maximum number of elements per channel transmission
// (inconsistent -> see freePortComms.h, macro MAX_FREECOM_BUF_SIZE -- fw-10-05)
#define maxNUMELEMENTS 100
/* send */
BOOL SendTimeoutFlag;
// 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
// ----------------------------------------------------------------------------------------------------
// 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;
// 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);
}
} /* end checkCOMforData */
/* Function: FreePortOpenConnection =================================================
*
* Open the connection with the target using the free communication port.
*/
HANDLE FreePortOpenConnection(unsigned int port, unsigned int baudrate) {
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("freePortSend|FreePortOpenConnection: IN\n");
#endif /* VERBOSE */
// open serial interface 'COMxString'
sprintf(COMxString, "COM%1d", (uint8_T)port);
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 = baudrate; // 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);
#ifdef VERBOSE
mexPrintf("freePortSend|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 */
// =====================================================================================================
// Send... sends a string via the serial interface 'hCom'
// =====================================================================================================
// CALL-UP PARAMETERS:
//
// '&data': string to be sent is stored here
// 'nToWrite': number of characters to be sent
// 'EchoFlag = TRUE/FALSE': Send() awaits 'echo' / 'no echo'
// 'SendTimeoutFlag': TRUE (timeout occurred), FALSE (no timeout)
// 'TimeoutMessageFlag': TRUE (onscreen timeout messages) / FALSE (no messages)
//
// RETURN VALUE: TRUE (successful transmission) / FALSE ('transmission error' or 'timeout')
BOOL Send(HANDLE hCom, BYTE data[], DWORD nToWrite, BOOL EchoFlag,
BOOL *SendTimeoutFlag, BOOL TimeoutMessageFlag)
{
int i;
DWORD nWritten, z_len_read;
BYTE *myChar;
BYTE r_myChar;
*SendTimeoutFlag = FALSE;
if (EchoFlag == with_echo) {
// send message 'character by character'
// request every character to be sent back (echo)
for (i = 0; i < (int)(nToWrite); i++) {
myChar = &data[i];
if (WriteFile(hCom, (LPSTR) myChar, 1, &nWritten, NULL)) {
if (nWritten == 1) {
// a character has successfully been sent; awaiting echo...
if (ReadFile(hCom, (LPSTR) &r_myChar, 1, &z_len_read, NULL)) {
// ReadFile returns successfully
if (z_len_read == 1) {
// one character has been received
if (r_myChar != *myChar) {
// invalid echo
mexPrintf ("Send: Transmission ('%3d') and reception ('%3d') differ.\n\n", *myChar, r_myChar);
return (FALSE);
}
}
else {
// z_len_read != 1 >> more/less than one character have been received
// -> timeout occurred during reception of the data echo (most likely)
if (TimeoutMessageFlag == with_to_messages)
mexPrintf ("Send: Timeout during reception of data echo.\n");
*SendTimeoutFlag = TRUE; // signal timeout
return (FALSE);
}
}
else {
// error during call to ReadFile()
mexPrintf ("Send: Unspecified error during reception of data echo.\n");
return (FALSE);
}
}
else {
// z_len_write != 1 >> more/less than one character have been sent
// -> timeout occurred during the transmission of the character
if (TimeoutMessageFlag == with_to_messages)
mexPrintf ("Send: Timeout during data transmission (with echo).\n");
*SendTimeoutFlag = TRUE;
return (FALSE);
}
}
else {
// error during call to WriteFile()
mexPrintf ("Send: Unspecified error during transmission (with echo).\n");
return (FALSE);
}
} /* for (i = 0; i < nToWrite; i++) */
return (TRUE);
} /* if (EchoFlag == with_echo) */
else {
// send the entire string 'in one go' -> no echo
if(WriteFile(hCom, (LPSTR) data, nToWrite, &nWritten, NULL)) {
if (nWritten == nToWrite) {
// no errors during transmission :-)
return (TRUE);
}
else {
// Timeout during data transmission
if (TimeoutMessageFlag == with_to_messages)
mexPrintf ("Send: Timeout occurred during data transmission (without echo).\n");
*SendTimeoutFlag = TRUE;
return (FALSE);
}
}
else {
// WriteFile() returned unsuccessfully
mexPrintf ("Send: Unspecified error during data transmission (without echo).\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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -