科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件工控串口通讯实现

工控串口通讯实现

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

工控串口通讯设计的源码。

作者:酷吏巡城 来源:CSDN 2008年3月20日

关键字: 串口通讯 工控 C++ C Linux

  • 评论
  • 分享微博
  • 分享邮件

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

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

 @doc easycomm.rtf

 @module easycomm.h | easycomm interface file

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

#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);
}

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章