📄 serialcom.c
字号:
/*******************************************************************************
Copyright (C) Excelpoint System (Pte) Ltd. 2006
FILE: SerialCom.c
DESCRIPTION: This module is a Win32 implementation of a serial communication module.
The module is intended for use in combination with the ABCSP.
*******************************************************************************/
#include <Windows.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include "SerialCom.h"
#define TX_BUF_MAX_SIZE (4000) /* the buffer size for incoming and outgoing characters */
#define RX_BUF_MAX_SIZE (4000)
#define DEBUG_ENABLE //enable uart TX/RX data log
/* the following number can be used to limit the number of bytes send at the time to the YABCSP libray.
If not defined as many bytes as possible are send to the library */
/*#define MAX_BYTES_TO_ABCSP ((uint16_t) 32)*/
#define CLOSE_DOWN_EVENT 0
#define WROTE_DATA_EVENT 1
#define NEW_TX_DATA_EVENT 2
#define NO_OF_TX_EVENTS 3
#define RX_DATA_EVENT 1
#define DATA_READ_EVENT 2
#define NO_OF_RX_EVENTS 3
/* the UART file handler */
//static HANDLE comHandle;
static HANDLE comHandle;
/* internal events used to signal the thread */
static HANDLE newTxDataEvent;
static HANDLE txCloseDownEvent;
static HANDLE txDownEvent;
static HANDLE rxCloseDownEvent;
static HANDLE rxDownEvent;
static HANDLE dataReadEvent;
static HANDLE rxEvents[NO_OF_RX_EVENTS];
static HANDLE txEvents[NO_OF_TX_EVENTS];
/* ensure mutual exclusion for write and read */
static CRITICAL_SECTION txMutex;
static CRITICAL_SECTION rxMutex;
/* the threads for rx and tx */
static HANDLE txThread;
static HANDLE rxThread;
static uint16_t txIn;
static uint16_t txOut;
static uint16_t rxIn;
static uint16_t rxOut;
static uint16_t txSize;
static uint16_t rxSize;
static uint8_t txBuf[TX_BUF_MAX_SIZE];
static uint8_t rxBuf[RX_BUF_MAX_SIZE];
static unsigned long baudRate;
static char comPortString[128];
DCB gDcb1, gDcb2;
void errorHandler(DWORD line, char *file, char *text)
{
#ifdef DEBUG_ENABLE
printf("Serial com error %s in file: %s, line %i\n", text, file, line);
#endif /*DEBUG_ENABLE*/
}
bool_t setComDefault(char *dcbInitString)
{
/* format of the init string must be: baud=1200 parity=N data=8 stop=1 */
bool_t success;
DCB dcb;
COMMTIMEOUTS comTimeouts;
success = TRUE;
if(!GetCommState(comHandle, &dcb))
{
success = FALSE;
errorHandler(__LINE__, __FILE__, "Can not read current DCB");
}
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = 0;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.ByteSize = 8; //8 bit
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY; //non parity
dcb.fBinary = 1;
/* then set baud rate, parity, data size and stop bit */
if (!BuildCommDCB(dcbInitString, &dcb))
{
DWORD lastError;
success = FALSE;
lastError = GetLastError();
printf("BuildCommDCB failed with error code: %ld!\n(device control string: %s)\n", lastError, dcbInitString);
}
comTimeouts.ReadIntervalTimeout = MAXDWORD;
comTimeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
comTimeouts.ReadTotalTimeoutConstant = 300000;
comTimeouts.WriteTotalTimeoutMultiplier = 0;
comTimeouts.WriteTotalTimeoutConstant = 0;
if (!SetCommMask(comHandle, 0))
{
success = FALSE;
errorHandler(__LINE__, __FILE__, "SetCommMask failed during initialisation");
}
if(!SetCommTimeouts(comHandle, &comTimeouts))
{
success = FALSE;
errorHandler(__LINE__, __FILE__, "SetCommTimeouts failed during initialisation");
}
if(!SetCommState(comHandle, &dcb))
{
success = FALSE;
errorHandler(__LINE__, __FILE__, "SetCommState failed during initialisation");
}
if (success == FALSE)
{
CloseHandle(comHandle);
comHandle = INVALID_HANDLE_VALUE;
}
GetCommState(comHandle, &gDcb1);
return(success);
}
bool_t handleRxData(DWORD len, uint8_t *data)
{
uint16_t theRxSize;
EnterCriticalSection(&rxMutex);
theRxSize = rxSize;
rxSize = rxSize + (uint16_t) len;
LeaveCriticalSection(&rxMutex);
if ((rxIn + len) == RX_BUF_MAX_SIZE)
{
rxIn = 0;
}
else
{
rxIn = rxIn + (uint16_t) len;
}
if (memchr(data, 0xC0, len) != NULL)
{
//got data
}
return TRUE;
}
void txThreadFunc(void)
{
OVERLAPPED osWrote = {0};
DWORD bytesWritten;
DWORD event;
bool_t txBusy;
uint16_t size;
uint16_t no2Send;
DWORD dwGetError;
osWrote.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ( osWrote.hEvent == NULL )
{
errorHandler(__LINE__, __FILE__, "Create event failed in tx thread");
exit(0);
}
txEvents[CLOSE_DOWN_EVENT] = txCloseDownEvent;
txEvents[WROTE_DATA_EVENT] = osWrote.hEvent;
txEvents[NEW_TX_DATA_EVENT] = newTxDataEvent;
txBusy = FALSE;
while (TRUE)
{
event = WaitForMultipleObjects(NO_OF_TX_EVENTS, txEvents, FALSE, INFINITE);
switch (event)
{
case WAIT_OBJECT_0 + CLOSE_DOWN_EVENT:
{
/* to do */
ResetEvent(txCloseDownEvent);
break;
}
case WAIT_OBJECT_0 + WROTE_DATA_EVENT:
{
BOOL success;
ResetEvent(osWrote.hEvent);
txBusy = FALSE;
success = GetOverlappedResult(comHandle, &osWrote, &bytesWritten, FALSE);
if (success)
{
if (bytesWritten > 0)
{
txOut = txOut + (uint16_t) bytesWritten;
if (txOut >= TX_BUF_MAX_SIZE)
{
txOut = 0;
}
}
else
{
bytesWritten = 0;
}
EnterCriticalSection(&txMutex);
txSize = txSize - (uint16_t) bytesWritten;
LeaveCriticalSection(&txMutex);
}
else
{
errorHandler(__LINE__, __FILE__, "Error when sending data (wrote complete error - data packet lost)");
}
if (txSize > 0)
{
SetEvent(newTxDataEvent);
}
break;
}
case WAIT_OBJECT_0 + NEW_TX_DATA_EVENT:
{
ResetEvent(newTxDataEvent);
/* do not try to send while busy */
if (!txBusy)
{
EnterCriticalSection(&txMutex);
size = txSize;
LeaveCriticalSection(&txMutex);
if (size == 0)
{
/* no data so take another loop */
break;
}
no2Send = size;
if (size + txOut > TX_BUF_MAX_SIZE)
{
no2Send = TX_BUF_MAX_SIZE - txOut;
}
if (WriteFile(comHandle, &(txBuf[txOut]), no2Send, &bytesWritten, &osWrote))
{
if (bytesWritten > 0)
{
txOut = txOut + (uint16_t) bytesWritten;
if (txOut >= TX_BUF_MAX_SIZE)
{
txOut = 0;
}
}
else
{
bytesWritten = 0;
}
EnterCriticalSection(&txMutex);
txSize = txSize - (uint16_t) bytesWritten;
LeaveCriticalSection(&txMutex);
if (txSize > 0)
{
SetEvent(newTxDataEvent);
}
}
else
{
dwGetError = GetLastError();
if (dwGetError != ERROR_IO_PENDING)
{
printf("\n%d\n", dwGetError);
errorHandler(__LINE__, __FILE__, "Serious error in write file (new data event) in tx thread");
}
else
{
/* write pending */
txBusy = TRUE;
}
}
}
else
{
if (WaitForSingleObject(osWrote.hEvent, 1) == WAIT_TIMEOUT)
{
ResetEvent(osWrote.hEvent);
txBusy = FALSE;
GetCommState(comHandle, &gDcb2);
}
}
break;
}
default:
{
/* error occured */
errorHandler(__LINE__, __FILE__, "Default called");
break;
}
} /* end switch */
if (event == WAIT_OBJECT_0 + CLOSE_DOWN_EVENT)
{
break;
}
} /* end while */
CloseHandle(osWrote.hEvent);
SetEvent(txDownEvent);
ExitThread(0);
}
void rxThreadFunc(void)
{
OVERLAPPED osRead = {0};
DWORD event;
uint8_t *rxData;
DWORD bytesRead;
bool_t readSuccess;
bool_t startRead;
uint16_t theRxSize;
COMSTAT comStat;
DWORD errors;
DWORD numberToRead;
osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ( (osRead.hEvent == NULL) )
{
errorHandler(__LINE__, __FILE__, "Create event failed in rx thread");
exit(0);
}
rxEvents[CLOSE_DOWN_EVENT] = rxCloseDownEvent;
rxEvents[RX_DATA_EVENT] = osRead.hEvent;
rxEvents[DATA_READ_EVENT] = dataReadEvent;
rxData = rxBuf;
rxSize = 0;
while (TRUE)
{
EnterCriticalSection(&rxMutex);
theRxSize = rxSize;
LeaveCriticalSection(&rxMutex);
/* find next position for rx data in and if any space available in buffer */
if (theRxSize < RX_BUF_MAX_SIZE)
{
startRead = TRUE;
}
else
{
/* wait for available space in the buffer */
startRead = FALSE;
}
/* kick the read process if allowed (space left in rx buffer) */
if (startRead)
{
rxData = rxBuf + rxIn;
/* find out how many to read */
if (!ClearCommError(comHandle, &errors, &comStat))
{
/* serious error */
errorHandler(__LINE__, __FILE__, "Serious error in read file in rx thread");
}
numberToRead = comStat.cbInQue > 0 ? comStat.cbInQue : 1;
if (rxIn + numberToRead > RX_BUF_MAX_SIZE)
{
numberToRead = RX_BUF_MAX_SIZE - rxIn;
}
readSuccess = ReadFile(comHandle, rxData, numberToRead, &bytesRead, &osRead);
if (!readSuccess)
{
if (GetLastError() != ERROR_IO_PENDING)
{
/* serious error */
errorHandler(__LINE__, __FILE__, "Serious error in read file in rx thread");
}
}
else
{
if (bytesRead > 0)
{
handleRxData(bytesRead, rxData);
}
}
}
if (!readSuccess)
{
do
{
event = WaitForMultipleObjects(NO_OF_RX_EVENTS, rxEvents, FALSE, INFINITE);
switch (event)
{
case CLOSE_DOWN_EVENT:
{
/* to do */
ResetEvent(rxCloseDownEvent);
break;
}
case RX_DATA_EVENT:
{
bool_t success;
/* receive complete, store the data */
success = GetOverlappedResult(comHandle, &osRead, &bytesRead, FALSE);
if ((bytesRead > 0) && success)
{
handleRxData(bytesRead, rxData);
}
startRead = FALSE;
ResetEvent(osRead.hEvent);
break;
}
case DATA_READ_EVENT:
{
/* sufficient data has been read from the rx buffer to restart the reader thread */
ResetEvent(dataReadEvent);
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -