工控串口通讯设计的源码

来源:互联网 发布:武装突袭3画面优化 编辑:程序博客网 时间:2024/05/29 16:09

 

#ifndef _EASYCOMM_H
#define _EASYCOMM_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef enum{
NC_COMMBREAK = 110,
NC_COMMERROR = 111,
NC_COMMMONITOR = 112,
NC_COMMACK = 113,
NC_COMMRECIVE = 114,
NC_COMMSENT = 115
}NotifyCode;

typedef struct tagNMHDR_COMM{
HWND hwndFrom;
    UINT idFrom;
    UINT code;
LPARAM lParam;
WPARAM wParam;
}NMHDR_COMM;

#define WM_COMMMSG    WM_USER + 10

#define COMMCTRLCLASS   _T("CommCtrl")
ATOM RegisterCommCtrlClass(HINSTANCE hInstance);

#define COM_SETPORT    WM_COMMMSG + 150
#define COM_GETPORT    WM_COMMMSG + 151
#define COM_SETBAUDRATE   WM_COMMMSG + 152
#define COM_GETBAUDRATE   WM_COMMMSG + 153
#define COM_SETBYTESIZE   WM_COMMMSG + 154
#define COM_GETBYTESIZE   WM_COMMMSG + 155
#define COM_SETSTOPBITS   WM_COMMMSG + 156
#define COM_GETSTOPBITS   WM_COMMMSG + 157
#define COM_SETPARITY   WM_COMMMSG + 158
#define COM_GETPARITY   WM_COMMMSG + 159
#define COM_SETFCTRL   WM_COMMMSG + 160
#define COM_GETFCTRL   WM_COMMMSG + 161
#define COM_SETTIMEOUTS   WM_COMMMSG + 162
#define COM_GETTIMEOUTS   WM_COMMMSG + 163
#define COM_SETACKCHAR   WM_COMMMSG + 164
#define COM_GETACKCHAR   WM_COMMMSG + 165
#define COM_SETLISTIMER   WM_COMMMSG + 166
#define COM_GETLISTIMER   WM_COMMMSG + 167
#define COM_SETACTIVE   WM_COMMMSG + 168
#define COM_GETACTIVE   WM_COMMMSG + 169
#define COM_SETDATA    WM_COMMMSG + 170
#define COM_GETDATA    WM_COMMMSG + 171
#define COM_SETQUEUE   WM_COMMMSG + 172
#define COM_POSTERROR   WM_COMMMSG + 175
#define COM_POSTRECIVE   WM_COMMMSG + 176
#define COM_POSTSENT   WM_COMMMSG + 177
#define COM_POSTBREAK   WM_COMMMSG + 178
#define COM_POSTACK    WM_COMMMSG + 179
#define COM_POSTMONITOR   WM_COMMMSG + 180
#define COM_QUERYSEND   WM_COMMMSG + 181

#define PY_NONE     0 /*无奇偶校验*/
#define PY_EVEN     1 /*偶校验*/
#define PY_ODD     2 /*奇校验*/
#define PY_MARK     3
#define PY_SPACE    4

#define STOPBITS_ONE   1 /*1位停止位*/
#define STOPBITS_TWO   2 /*2位停止位*/
#define STOPBITS_ONEHALF 3 /*1.5停止位*/

#define FLOWCTRL_NONE   0 /*无流控制*/
#define FLOWCTRL_HARD   1 /*硬件控制*/
#define FLOWCTRL_SOFT   2 /*软件控制*/

#define CE_PARAM    -1

#define READ_SUCCESS   0
#define READ_TIMEOUTS   1
#define WRITE_SUCCESS   0
#define WRITE_TIMEOUTS   1

/*端口状态*/
typedef struct _CommMonitor{
BOOL bRLSDHold;
BOOL bCTSHold;
BOOL bDSRHold;
BOOL bXOFFHold;
BOOL bXOFFSent;
int nInQueue;
int nOutQueue;
}CommMonitor;

#ifdef _CHS
#define ERROR_PARAM    _T("参数错误")
#define ERROR_BREAK    _T("硬件中断")
#define ERROR_FRAME    _T("硬件幀错误")
#define ERROR_IOE    _T("通讯I/O错误")
#define ERROR_OVERRUM   _T("数据丢失")
#define ERROR_RXOVER   _T("输入缓冲区溢出")
#define ERROR_RXPARITY   _T("硬件校验错误")
#define ERROR_TXFULL   _T("输出缓冲区溢出")
#define ERROR_UNKNOWN   _T("其他错误")
#else
#define ERROR_PARAM    _T("The parameter setup error")
#define ERROR_BREAK    _T("The hardware detected a break condition.")
#define ERROR_FRAME    _T("The hardware detected a framing error.")
#define ERROR_IOE    _T("An I/O error occurred during communications with the device.")
#define ERROR_OVERRUN   _T("A character-buffer overrun has occurred. The next character is lost.")
#define ERROR_RXOVER   _T("An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character.")
#define ERROR_RXPARITY   _T("The hardware detected a parity error.")
#define ERROR_TXFULL   _T("The application tried to transmit a character, but the output buffer was full.")
#define ERROR_UNKNOWN   _T("Other error occurred")
#endif

extern void InitCommControl(HINSTANCE hInstance);
extern void UnInitCommControl(HINSTANCE hInstance);

#ifdef __cplusplus
}
#endif

#endif

/*************************************************************
EasySoft easycomm v2.0

(c) 2001-2004 EasySoft Corporation. All Rights Reserved.

@doc easycomm.rtf

@module easycomm.c | easycomm impliment file

@devnote jdzwq 2003.01 - 2004.10
*************************************************************/

#include "easycomm.h"

typedef struct tagCommDelta{
HWND hWnd;
BOOL bActive;   /*侦听标志*/
BOOL bReady;   /*串口可写标志*/
HANDLE hListen;   /*侦听线程句柄*/
DWORD dwListen;   /*侦听线程ID*/
OVERLAPPED ovListen; /*用于侦听的重叠操作结构*/
HANDLE hCom;   /*端口句柄*/
CRITICAL_SECTION cs; /* 同步临界区*/
short nFlowCtrl; /*流控制模式*/
short nAckChar;   /*回应字符*/
short nParity;   /*校验方式*/
short nStopBits; /*停止位*/
short nByteSize; /*位长*/
short nReadTimeoutPerByte; /*读每字节超时参数*/
short nWriteTimeoutPerByte; /*写每字节超时参数*/
long nListenTimeout;   /*侦听超时*/
long nBaudRate;   /*波特率*/
long nInQueue;   /*输入缓冲区大小*/
long nOutQueue;   /*输出缓冲区大小*/
TCHAR szPort[10]; /*端口*/
}CommDelta;

/*定义线程操作结构*/
typedef struct _OperaParam
{
HANDLE hCom;   /*串口句柄*/
LPCRITICAL_SECTION pcs; /*临界区引用*/
DWORD dwDataBytes; /*请求操作字节数*/
DWORD dwOperaBytes; /*实际操作字节数*/
BYTE* data;    /*读写数据指针*/
short nRetCode;
}OperaParam;

#define GETCOMMDELTA(hWnd) ((CommDelta*)GetWindowLong(hWnd,GWL_USERDATA))
#define SETCOMMDELTA(hWnd,ptd) SetWindowLong(hWnd,GWL_USERDATA,(LONG)ptd)

LRESULT CALLBACK CommCtrlProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


void COM_Paint(HWND hWnd,HDC hDC);
int COM_SendSign(HWND hWnd,UINT sign, WPARAM wParam,LPARAM lParam);

BOOL COM_Active(HWND hWnd,BOOL bActive);
long COM_SendData(HWND hWnd,long size,BYTE* data);
long COM_ReciveData(HWND hWnd,long size,BYTE* data);

DWORD WINAPI ListenProc(LPVOID lpParam);
DWORD WINAPI WriteProc(LPVOID lpParam);

void* _CommAlloc(long size);
void _CommFree(void* data);

ATOM RegisterCommCtrlClass(HINSTANCE hInstance)
{
WNDCLASS wcex;
#ifdef _WINDOWS
wcex.style    = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
#else
wcex.style    = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
#endif
wcex.lpfnWndProc = (WNDPROC)CommCtrlProc;
wcex.cbClsExtra   = 0;
wcex.cbWndExtra   = 0;
wcex.hInstance   = hInstance;
wcex.hIcon    = NULL;
wcex.hCursor   = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = COMMCTRLCLASS;

return RegisterClass(&wcex);
}

LRESULT CALLBACK CommCtrlProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
PAINTSTRUCT ps;
int n;

switch(message)
{
case WM_CREATE:
   ptd = (CommDelta*)calloc(1,sizeof(CommDelta));
   ptd->hWnd = hWnd;
   /*默认参数配置*/
   lstrcpy(ptd->szPort,_T("COM1"));
   ptd->nReadTimeoutPerByte = ptd->nWriteTimeoutPerByte = 10;
   ptd->nListenTimeout = 5000;
   ptd->nFlowCtrl = 0;
   ptd->nAckChar = 0;
   ptd->nParity = 0;
   ptd->nStopBits = 1;
   ptd->nByteSize = 8;
   ptd->nBaudRate = 1200;
   ptd->bReady = FALSE;

   ptd->bActive = FALSE;
   ptd->hCom = INVALID_HANDLE_VALUE;
   ptd->hListen = NULL;
   InitializeCriticalSection(&ptd->cs);

   SETCOMMDELTA(hWnd,ptd);
   break;
case WM_DESTROY:
   if(ptd->bActive)
    SendMessage(hWnd,COM_SETACTIVE,(WPARAM)FALSE,0);
   DeleteCriticalSection(&ptd->cs);
   free(ptd);
   break;
case WM_PAINT:
   if(GetUpdateRect(hWnd,NULL,TRUE))
   {
    BeginPaint(hWnd,&ps);
    COM_Paint(hWnd,ps.hdc);
    EndPaint(hWnd,&ps);
   }
case COM_SETPORT:
   if(lParam)
   {
    n = _tcslen((TCHAR*)lParam);
    n = (n < 9)? n : 9;
    _tcsncpy(ptd->szPort,(TCHAR*)lParam,n);
    (ptd->szPort)[n] = _T('/0');
   }
   return 0;
case COM_GETPORT:
   if(lParam)
   {
    n = _tcslen(ptd->szPort);
    n = (n < (int)wParam)? n : (int)wParam;
    _tcsncpy((TCHAR*)lParam,ptd->szPort,n);
    ((TCHAR*)lParam)[n] = _T('/0');
   }
   return 0;
case COM_GETBAUDRATE:
   return (LRESULT)ptd->nBaudRate;
case COM_SETBAUDRATE:
   ptd->nBaudRate = (long)wParam;
   return 0;
case COM_GETBYTESIZE:
   return (LRESULT)ptd->nByteSize;
case COM_SETBYTESIZE:
   ptd->nByteSize = (short)wParam;
   return 0;
case COM_GETSTOPBITS:
   return (LRESULT)ptd->nStopBits;
case COM_SETSTOPBITS:
   ptd->nStopBits = (short)wParam;
   return 0;
case COM_GETPARITY:
   return (LRESULT)ptd->nParity;
case COM_SETPARITY:
   ptd->nParity = (short)wParam;
   return 0;
case COM_GETFCTRL:
   return ptd->nFlowCtrl;
case COM_SETFCTRL:
   ptd->nFlowCtrl = (short)wParam;
   return 0;
case COM_GETTIMEOUTS:
   return (LRESULT)MAKEWPARAM((WORD)ptd->nReadTimeoutPerByte,(WORD)ptd->nWriteTimeoutPerByte);
case COM_SETTIMEOUTS:
   ptd->nReadTimeoutPerByte = (short)LOWORD(wParam);
   ptd->nWriteTimeoutPerByte = (short)HIWORD(wParam);
   return 0;
case COM_GETACKCHAR:
   return (LRESULT)ptd->nAckChar;
case COM_SETACKCHAR:
   ptd->nAckChar = (short)wParam;
   return 0;
case COM_GETLISTIMER:
   return (LRESULT)ptd->nListenTimeout;
case COM_SETLISTIMER:
   ptd->nListenTimeout = (long)wParam;
   return 0;
case COM_SETQUEUE:
   ptd->nInQueue = (long)wParam;
   ptd->nOutQueue = (long)lParam;
   return 0;
case COM_GETACTIVE:
   return (LRESULT)ptd->bActive;
case COM_SETACTIVE:
   return (LRESULT)COM_Active(hWnd,(BOOL)wParam);
case COM_SETDATA:
   return (LRESULT)COM_SendData(hWnd,(long)wParam,(BYTE*)lParam);
case COM_GETDATA:
   return (LRESULT)COM_ReciveData(hWnd,(long)wParam,(BYTE*)lParam);
case COM_POSTBREAK:
   COM_SendSign(hWnd,NC_COMMBREAK,0,0);
   return 0;
case COM_POSTERROR:
   COM_SendSign(hWnd,NC_COMMERROR,wParam,lParam);
   if(lParam)
    _CommFree((void*)lParam);
   return 0;
case COM_POSTMONITOR:
   COM_SendSign(hWnd,NC_COMMMONITOR,wParam,lParam);
   if(lParam)
    _CommFree((void*)lParam);
   return 0;
case COM_POSTACK:
   COM_SendSign(hWnd,NC_COMMACK,(long)wParam,0);
   return 0;
case COM_POSTRECIVE:
   COM_SendSign(hWnd,NC_COMMRECIVE,(long)wParam,0);
   return 0;
case COM_POSTSENT:
   COM_SendSign(hWnd,NC_COMMSENT,(long)wParam,0);
   return 0;
case COM_QUERYSEND:
   return (LRESULT)ptd->bReady;
}

return DefWindowProc(hWnd,message,wParam,lParam);
}


void* _CommAlloc(long size)
{
return (TCHAR*)GlobalLock(GlobalAlloc(GHND,size));
}

void _CommFree(void* data)
{
GlobalUnlock((HGLOBAL)data);
GlobalFree((HGLOBAL)data);
}

void _FormatCommError(DWORD errcode,TCHAR* buf)
{
switch(errcode)
{
case CE_PARAM:
   _tcscpy(buf,ERROR_PARAM);
   break;
case CE_BREAK:
   _tcscpy(buf,ERROR_BREAK);
   break;
case CE_FRAME:
   _tcscpy(buf,ERROR_FRAME);
   break;
case CE_IOE:
   _tcscpy(buf,ERROR_IOE);
   break;
case CE_OVERRUN:
   _tcscpy(buf,ERROR_OVERRUN);
   break;
case CE_RXOVER:
   _tcscpy(buf,ERROR_RXOVER);
   break;
case CE_RXPARITY:
   _tcscpy(buf,ERROR_RXPARITY);
   break;
case CE_TXFULL:
   _tcscpy(buf,ERROR_TXFULL);
   break;
default:
   _tcscpy(buf,ERROR_UNKNOWN);
   break;
}
}

DWORD _InternalRead(HWND hWnd,DWORD size, void *buf)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
DWORD dwOperaBytes = 0;

if(ptd->hCom == INVALID_HANDLE_VALUE)
   return 0;

ReadFile(ptd->hCom,buf,size,&dwOperaBytes,NULL);
return dwOperaBytes;
}

BOOL _InternalOpen(HWND hWnd)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
TCHAR szFile[20];
DCB dcb;
COMMTIMEOUTS to;
TCHAR* mem;

_stprintf(szFile,_T("////.//%s"),ptd->szPort);
/*打开端口文件*/
ptd->hCom = CreateFile(szFile,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);
if(ptd->hCom == INVALID_HANDLE_VALUE)
   return FALSE;

/*配置端口参数*/
memset((void*)&dcb,0,sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
GetCommState(ptd->hCom,&dcb);

switch(ptd->nBaudRate)
{
case 110:
   dcb.BaudRate = CBR_110;
   break;
case 300:
   dcb.BaudRate = CBR_300;
   break;
case 600:
   dcb.BaudRate = CBR_600;
   break;
case 1200:
   dcb.BaudRate = CBR_1200;
   break;
case 2400:
   dcb.BaudRate = CBR_2400;
   break;
case 4800:
   dcb.BaudRate = CBR_4800;
   break;
case 9600:
   dcb.BaudRate = CBR_9600;
   break;
case 14400:
   dcb.BaudRate = CBR_14400;
   break;
case 19200:
   dcb.BaudRate = CBR_19200;
   break;
case 38400:
   dcb.BaudRate = CBR_38400;
   break;
case 56000:
   dcb.BaudRate = CBR_56000;
   break;
case 57600 :
   dcb.BaudRate = CBR_57600;
   break;
case 115200 :
   dcb.BaudRate = CBR_115200;
   break;
case 128000 :
   dcb.BaudRate = CBR_128000;
   break;
case 256000 :
   dcb.BaudRate = CBR_256000;
   break;
default:
   ptd->nBaudRate = 1200;
   dcb.BaudRate = CBR_1200;
}

switch(ptd->nByteSize)
{
case 5:
case 6:
case 7:
case 8:
   dcb.ByteSize = (BYTE)ptd->nByteSize;
   break;
default:
   ptd->nByteSize = 8;
   dcb.ByteSize = 8;
}

switch(ptd->nStopBits)
{
case STOPBITS_ONE:
   dcb.StopBits = ONESTOPBIT;
   break;
case STOPBITS_TWO:
   dcb.StopBits = TWOSTOPBITS;
   break;
case STOPBITS_ONEHALF:
   dcb.StopBits = ONE5STOPBITS;
   break;
default:
   ptd->nStopBits = STOPBITS_ONE;
   dcb.StopBits = ONESTOPBIT;
   break;
}

switch(ptd->nParity)
{
case PY_NONE:
   dcb.Parity = NOPARITY;
   break;
case PY_EVEN:
   dcb.Parity = EVENPARITY;
   break;
case PY_ODD:
   dcb.Parity = ODDPARITY;
   break;
case PY_MARK:
   dcb.Parity = MARKPARITY;
   break;
case PY_SPACE:
   dcb.Parity = SPACEPARITY;
   break;
default:
   ptd->nParity = PY_NONE;
   dcb.Parity = NOPARITY;
   break;
}

switch(ptd->nFlowCtrl)
{
case FLOWCTRL_NONE:
   dcb.fInX = FALSE;
   dcb.fOutX = FALSE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fOutxCtsFlow = FALSE;
   dcb.fDtrControl = DTR_CONTROL_ENABLE;
   dcb.fRtsControl = RTS_CONTROL_ENABLE;
   break;
case FLOWCTRL_HARD:
   dcb.fInX = FALSE;
   dcb.fOutX = FALSE;
   dcb.fOutxDsrFlow = TRUE;
   dcb.fOutxCtsFlow = TRUE;
   dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
   dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
   break;
case FLOWCTRL_SOFT:
   dcb.fInX = TRUE;
   dcb.fOutX = TRUE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fOutxCtsFlow = FALSE;
   dcb.fDtrControl = DTR_CONTROL_ENABLE;
   dcb.fRtsControl = RTS_CONTROL_ENABLE;
   break;
default:
   ptd->nFlowCtrl = FLOWCTRL_NONE;
   dcb.fInX = FALSE;
   dcb.fOutX = FALSE;
   dcb.fOutxDsrFlow = FALSE;
   dcb.fOutxCtsFlow = FALSE;
   dcb.fDtrControl = DTR_CONTROL_ENABLE;
   dcb.fRtsControl = RTS_CONTROL_ENABLE;
   break;
}

if(ptd->nAckChar)
   dcb.EvtChar = (char)ptd->nAckChar;

if(!SetCommState(ptd->hCom,&dcb))
{
   mem = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
   _FormatCommError(CE_PARAM,mem);
   PostMessage(hWnd,COM_POSTERROR,(WPARAM)_tcslen(mem),(LPARAM)mem);
}

GetCommTimeouts(ptd->hCom,&to);
to.ReadTotalTimeoutConstant = 500;
to.WriteTotalTimeoutConstant = 500;
to.ReadTotalTimeoutMultiplier = ptd->nReadTimeoutPerByte;
to.WriteTotalTimeoutMultiplier = ptd->nWriteTimeoutPerByte;
if(!SetCommTimeouts(ptd->hCom,&to))
{
   mem = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
   _FormatCommError(CE_PARAM,mem);
   PostMessage(hWnd,COM_POSTERROR,(WPARAM)_tcslen(mem),(LPARAM)mem);
}

return TRUE;
}

BOOL _InternalClose(HWND hWnd)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);

if(ptd->hCom != INVALID_HANDLE_VALUE)
{
   CloseHandle(ptd->hCom);
}
ptd->hCom = INVALID_HANDLE_VALUE;
return TRUE;
}

BOOL COM_Active(HWND hWnd,BOOL newVal)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);

if(newVal)
{
   if(ptd->bActive)
    return TRUE;

   /*打开端口*/
   if(!_InternalOpen(hWnd))
    return FALSE;

   ptd->ovListen.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
   ptd->bActive = TRUE;
   /*创建侦听线程*/
   ptd->hListen = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ListenProc,(LPVOID)ptd,0,&ptd->dwListen);
   if(ptd->hListen == NULL)
   {
    _InternalClose(hWnd);
    CloseHandle(ptd->ovListen.hEvent);
    memset((void*)&ptd->ovListen,0,sizeof(OVERLAPPED));
    ptd->bActive = FALSE;
    return FALSE;
   }
   ptd->bReady = TRUE;
   Sleep(100); /*让线程运行*/
   return TRUE;
}else
{
   if(!ptd->bActive)
    return TRUE;

   EnterCriticalSection(&ptd->cs);
   ptd->bActive = FALSE;
   ptd->bReady = FALSE;
   LeaveCriticalSection(&ptd->cs);
   Sleep(100); /*让线程终止*/
   /*等待侦听线程中止*/
   WaitForSingleObject(ptd->ovListen.hEvent,ptd->nListenTimeout);
   /*关闭线程句柄*/  
   TerminateThread(ptd->hListen,0);
   CloseHandle(ptd->hListen);
   CloseHandle(ptd->ovListen.hEvent);
   memset((void*)&ptd->ovListen,0,sizeof(OVERLAPPED));
   /*关闭端口*/
   _InternalClose(hWnd);
   return TRUE;
}
}

DWORD WINAPI ListenProc(LPVOID lpParam)
{
CommDelta* pCom = (CommDelta*)lpParam;
DWORD dwMask,dwError;
COMSTAT cst;
TCHAR* err;
CommMonitor* pm;
BOOL bActive;

EnterCriticalSection(&pCom->cs);
/*清空输入流和输出流*/
PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);

switch(pCom->nFlowCtrl)
{
case FLOWCTRL_NONE: /*无流控制*/
   dwMask = EV_BREAK | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
   SetCommMask(pCom->hCom,dwMask);
   break;
case FLOWCTRL_HARD: /*硬件控制*/
   dwMask = EV_BREAK | EV_CTS | EV_DSR | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
   SetCommMask(pCom->hCom,dwMask);
   /*通知DCE可以输出数据*/
   EscapeCommFunction(pCom->hCom,SETRTS);
   EscapeCommFunction(pCom->hCom,SETDTR);
   break;
case FLOWCTRL_SOFT: /*Xon/Xoff控制*/
   dwMask = EV_BREAK | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
   SetCommMask(pCom->hCom,dwMask);
   break;
default:
   dwMask = EV_BREAK | EV_RXCHAR |EV_RXFLAG | EV_ERR | EV_TXEMPTY;
   SetCommMask(pCom->hCom,dwMask);
   break;
}
LeaveCriticalSection(&pCom->cs);

bActive = pCom->bActive;
while(bActive)
{
   /*异步等待端口事件*/
   dwMask = 0;
   /*重制信号*/
   ResetEvent(pCom->ovListen.hEvent);

   EnterCriticalSection(&pCom->cs);
   WaitCommEvent(pCom->hCom,&dwMask,&pCom->ovListen);
   LeaveCriticalSection(&pCom->cs);

   WaitForSingleObject(pCom->ovListen.hEvent,INFINITE);
   
   switch(dwMask)
   {
   case EV_BREAK:
    PostMessage(pCom->hWnd,COM_POSTBREAK,0,0);
    break;
   case EV_CTS:
   case EV_DSR:
    ClearCommError(pCom->hCom,&dwError,&cst);
    pm = (CommMonitor*)_CommAlloc(sizeof(CommMonitor));
    pm->bCTSHold = cst.fCtsHold;
    pm->bDSRHold = cst.fDsrHold;
    pm->bRLSDHold = cst.fRlsdHold;
    pm->bXOFFHold = cst.fXoffHold;
    pm->bXOFFSent = cst.fXoffSent;
    pm->nInQueue = cst.cbInQue;
    pm->nOutQueue = cst.cbOutQue;
    PostMessage(pCom->hCom,COM_POSTMONITOR,(WPARAM)sizeof(CommMonitor),(LPARAM)pm);
    break;
   case EV_ERR:
    ClearCommError(pCom->hCom,&dwError,&cst);
    if(dwError == CE_RXOVER)
    {
     PurgeComm(pCom->hCom,PURGE_RXCLEAR);
    }else if(dwError == CE_TXFULL)
    {
     PurgeComm(pCom->hCom,PURGE_TXCLEAR);
    }else
    {
     PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
     PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
    }
    err = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
    _FormatCommError(dwError,err);
    PostMessage(pCom->hWnd,COM_POSTERROR,(WPARAM)dwError,(LPARAM)err);
    break;
   case EV_RXFLAG:
   case EV_RXCHAR:
    ClearCommError(pCom->hCom,&dwError,&cst);
    if(dwMask == EV_RXCHAR)
     PostMessage(pCom->hWnd,COM_POSTRECIVE,(WPARAM)cst.cbInQue,0);
    else
     PostMessage(pCom->hWnd,COM_POSTACK,(WPARAM)cst.cbInQue,0);  
    break;
   case EV_TXEMPTY:
    EnterCriticalSection(&pCom->cs);
    /*允许后继写入*/
    pCom->bReady = TRUE;
    LeaveCriticalSection(&pCom->cs);
    PostMessage(pCom->hWnd,COM_POSTSENT,0,0); /*通知端口可写*/
    break;   
   }

   /*查询主线程终止信号*/
   EnterCriticalSection(&pCom->cs);
   bActive = pCom->bActive;
   LeaveCriticalSection(&pCom->cs);
}

EnterCriticalSection(&pCom->cs);
/*通知DCE停止数据传输*/
if(pCom->nFlowCtrl == FLOWCTRL_HARD)
{
   EscapeCommFunction(pCom->hCom,CLRRTS);
   EscapeCommFunction(pCom->hCom,CLRDTR);
}
/*撤销输入流和输出流*/
PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);

LeaveCriticalSection(&pCom->cs);
/*通知主线程,本线程结束*/
SetEvent(pCom->ovListen.hEvent);

return 0;
}

DWORD WINAPI ReadProc(LPVOID lpParam)
{
OperaParam* pop = (OperaParam*)lpParam;
OVERLAPPED ov;
COMMTIMEOUTS to;

/*取读超时参数*/
GetCommTimeouts(pop->hCom,&to);
/*创建异步写事件*/
memset((void*)&ov,0,sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
/*端口异步读*/
EnterCriticalSection(pop->pcs);
ReadFile(pop->hCom,(void*)pop->data,pop->dwDataBytes,&(pop->dwOperaBytes),&ov);
LeaveCriticalSection(pop->pcs);

/*等待异步读结果*/
if(WAIT_OBJECT_0 != WaitForSingleObject(ov.hEvent,to.ReadTotalTimeoutConstant + to.ReadTotalTimeoutMultiplier * pop->dwDataBytes))
{
   /*中止未完成的异步读*/
   PurgeComm(pop->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
   pop->nRetCode = READ_TIMEOUTS;
}else
{
   pop->nRetCode = READ_SUCCESS;
}
/*取读结果*/
GetOverlappedResult(pop->hCom,&ov,&(pop->dwOperaBytes),FALSE);

CloseHandle(ov.hEvent);
return 0;
}

DWORD WINAPI WriteProc(LPVOID lpParam)
{
OperaParam* pop = (OperaParam*)lpParam;
OVERLAPPED ov;
COMMTIMEOUTS to;

/*取写超时参数*/
GetCommTimeouts(pop->hCom,&to);
/*创建异步写事件*/
memset((void*)&ov,0,sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
/*端口异步写*/
EnterCriticalSection(pop->pcs);
WriteFile(pop->hCom,(void*)pop->data,pop->dwDataBytes,&(pop->dwOperaBytes),&ov);
LeaveCriticalSection(pop->pcs);

/*等待异步写结果*/
if(WAIT_OBJECT_0 != WaitForSingleObject(ov.hEvent,to.WriteTotalTimeoutConstant + to.WriteTotalTimeoutMultiplier * pop->dwDataBytes))
{
   /*中止未完成的异步写*/
   PurgeComm(pop->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
   pop->nRetCode = WRITE_TIMEOUTS;
}else
{
   pop->nRetCode = WRITE_SUCCESS;
}

/*取写结果*/
GetOverlappedResult(pop->hCom,&ov,&(pop->dwOperaBytes),FALSE);

CloseHandle(ov.hEvent);
return 0;
}

long COM_SendData(HWND hWnd,long size, BYTE* data)
{
CommDelta* pCom = GETCOMMDELTA(hWnd);
HANDLE hWrite;
DWORD dw;
OperaParam op;

if(!pCom->bActive)
   return -1;

if(!pCom->bReady)
   return -1;

//禁止后继写入
pCom->bReady = FALSE;
memset((void*)&op,0,sizeof(OperaParam));
op.hCom = pCom->hCom;
op.pcs = &pCom->cs;
op.data = data;
op.dwDataBytes = size;

/*异步写线程*/
hWrite = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteProc,(void*)&op,0,&dw);
if(hWrite)
{
   /*等待线程结束*/
   WaitForSingleObject(hWrite,INFINITE);
   CloseHandle(hWrite);
}else
   op.dwOperaBytes = -1;

return op.dwOperaBytes;
}

long COM_ReciveData(HWND hWnd,long size, BYTE* data)
{
CommDelta* pCom = GETCOMMDELTA(hWnd);
HANDLE hRead;
DWORD dw;
OperaParam op;

if(!pCom->bActive)
   return -1;

memset((void*)&op,0,sizeof(OperaParam));
op.hCom = pCom->hCom;
op.pcs = &pCom->cs;
op.data = data;
op.dwDataBytes = size;

/*异步读线程*/
hRead = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadProc,(void*)&op,0,&dw);
if(hRead)
{
   /*等待线程结束*/
   WaitForSingleObject(hRead,INFINITE);
   CloseHandle(hRead);
}else
   op.dwOperaBytes = -1;

return op.dwOperaBytes;
}

int COM_SendSign(HWND hWnd,UINT sign, WPARAM wParam,LPARAM lParam)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
NMHDR_COMM hdr;

hdr.hwndFrom = hWnd;
hdr.idFrom = GetWindowLong(hWnd,GWL_ID);
hdr.code = sign;
hdr.wParam = wParam;
hdr.lParam = lParam;

return (int)SendMessage(GetParent(hWnd),WM_NOTIFY,hdr.idFrom,(LPARAM)&hdr);
}

void COM_Paint(HWND hWnd,HDC hDC)
{
RECT rt;
GetClientRect(hWnd,&rt);
DrawText(hDC,_T("EasyComm"),-1,&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER);
}

void InitCommControl(HINSTANCE hInstance)
{
HINSTANCE hInst = (hInstance)? hInstance : GetModuleHandle(NULL);

RegisterCommCtrlClass(hInst);
}

void UnInitCommControl(HINSTANCE hInstance)
{
HINSTANCE hInst = (hInstance)? hInstance : GetModuleHandle(NULL);

UnregisterClass(COMMCTRLCLASS,hInst);
}

原创粉丝点击