⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _com.h

📁 一个较全de串口类
💻 H
字号:
/*
串口基础类库(WIN32) ver 0.1

编译器 : BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET;  GCC;

class   _base_com : 虚基类 基本串口接口;
class   _sync_com : 同步I/O 串口类;
class   _asyn_com : 异步I/O 串口类;
class _thread_com : 异步I/O 辅助读监视线程 可转发窗口消息 串口类(可继承虚函数on_receive用于读操作);
class        _com : _thread_com 同名

copyright(c) 2004.8 llbird wushaojian@21cn.com
*/
/*
Example :
*/
#ifndef _COM_H_
#define _COM_H_

#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#pragma warning(disable: 4800)

#include <cassert>
#include <strstream>
#include <algorithm>
#include <exception>
#include <iomanip>
using namespace std;

#include "GPSParam.h"
#include <windows.h>

class _base_com   //虚基类 基本串口接口
{
protected:

	 volatile int _port;  //串口号
	 volatile HANDLE _com_handle;//串口句柄
	 char _com_str[20];
	 DCB _dcb;     //波特率,停止位,等
	 COMMTIMEOUTS _co;  // 超时时间

	 virtual bool open_port() = 0;
	 void init() //初始化
	 {
		  memset(_com_str, 0, 20);
		  memset(&_co, 0, sizeof(_co));
		  memset(&_dcb, 0, sizeof(_dcb));
		  _dcb.DCBlength = sizeof(_dcb);
		  _com_handle = INVALID_HANDLE_VALUE;
	 }                  
	 virtual bool setup_port()
	 {
		  if(!is_open())
		   return false;

		  if(!SetupComm(_com_handle, 8192, 8192))
		   return false; //设置推荐缓冲区

		  if(!GetCommTimeouts(_com_handle, &_co))
		   return false;
		  _co.ReadIntervalTimeout = 0xFFFFFFFF;
		  _co.ReadTotalTimeoutMultiplier = 0;
		  _co.ReadTotalTimeoutConstant = 0;
		  _co.WriteTotalTimeoutMultiplier = 0;
		  _co.WriteTotalTimeoutConstant = 2000;
		  if(!SetCommTimeouts(_com_handle, &_co))
			  return false; //设置超时时间

		  if(!PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ))
			  return false; //清空串口缓冲区

		  return true;
	 }       
	 inline void set_com_port(int port)
	 {
	  char p[12];
	  _port = port;
	  strcpy(_com_str, "\\\\.\\COM"); 
	  ltoa(_port, p, 10);
	  strcat(_com_str, p);
	 }
public:
 _base_com()
 {
  init(); 
 }
 virtual ~_base_com()
 {
  close();      
 }
 //设置串口参数:波特率,停止位,等 支持设置字符串 "9600, 8, n, 1"
 bool set_state(char *set_str) 
 {
  if(is_open())
  {
   if(!GetCommState(_com_handle, &_dcb))
    return false;
   if(!BuildCommDCB(set_str, &_dcb))
    return false;
   return SetCommState(_com_handle, &_dcb) == TRUE;
  }
  return false;
 }
 //设置内置结构串口参数:波特率,停止位
 bool set_state(int BaudRate = 9600, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT, char EvtChar='\n' )
 {
	 if(is_open())
	 {
		 if(!GetCommState(_com_handle, &_dcb))
			 return false;
		 _dcb.BaudRate = BaudRate;
		 _dcb.ByteSize = ByteSize;
		 _dcb.Parity   = Parity;
		 _dcb.StopBits = StopBits;
		 _dcb.EvtChar  = EvtChar;
		 return SetCommState(_com_handle, &_dcb) == TRUE;
	 }
	 return false;
 }
 //打开串口 缺省 9600, 8, n, 1
 inline bool open(int port)
 {
	 return open(port, 9600);
 }
 //打开串口 缺省 baud_rate, 8, n, 1
 inline bool open(int port, int baud_rate)
 {
  if(port < 1 || port > 1024)
   return false;

  set_com_port(port);

  if(!open_port())
   return false;

  if(!setup_port())
   return false;

  return set_state(baud_rate);
 }
 //打开串口
 inline bool open(int port, char *set_str)
 {
  if(port < 1 || port > 1024)
   return false;

  set_com_port(port);

  if(!open_port())
   return false;

  if(!setup_port())
   return false;

  return set_state(set_str);
  
 }
 inline bool set_buf(int in, int out)
 {
  return is_open() ? SetupComm(_com_handle, in, out) : false;
 }
 //关闭串口
 inline virtual void close()
 {
  if(is_open())  
  {
   CloseHandle(_com_handle);
   _com_handle = INVALID_HANDLE_VALUE;
  }
 }
 //判断串口是或打开
 inline bool is_open()
 {
  return _com_handle != INVALID_HANDLE_VALUE;
 }
 //获得串口句炳
 HANDLE get_handle()
 {
  return _com_handle;
 }
 operator HANDLE()
 {
  return _com_handle;
 }
};

class _sync_com : public _base_com
{
protected:
 //打开串口
 virtual bool open_port()
 {
  if(is_open())
   close();

  _com_handle = CreateFile(
   _com_str,
   GENERIC_READ | GENERIC_WRITE,
   0,
   NULL,
   OPEN_EXISTING,
   FILE_ATTRIBUTE_NORMAL , 
   NULL
   );
  assert(is_open());
  return is_open();//检测串口是否成功打开
 }

public:

 _sync_com()
 {
 }
 //同步读
 int read(char *buf, int buf_len)
 {
  if(!is_open())
   return 0;

  buf[0] = '\0';
  
  COMSTAT  stat;
  DWORD error;

  if(ClearCommError(_com_handle, &error, &stat) && error > 0) //清除错误
  {
   PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
   return 0;
  }
   
  unsigned long r_len = 0;

  buf_len = min(buf_len - 1, (int)stat.cbInQue);
  if(!ReadFile(_com_handle, buf, buf_len, &r_len, NULL))
    r_len = 0;
  buf[r_len] = '\0';

  return r_len;
 }
 //同步写
 int write(char *buf, int buf_len)
 {
  if(!is_open() || !buf)
   return 0;
  
  DWORD    error;
  if(ClearCommError(_com_handle, &error, NULL) && error > 0) //清除错误
   PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR);

  unsigned long w_len = 0;
  if(!WriteFile(_com_handle, buf, buf_len, &w_len, NULL))
   w_len = 0;

  return w_len;
 }
 //同步写
 inline int write(char *buf)
 {
  assert(buf);
  return write(buf, strlen(buf));
 }
 //同步写, 支持部分类型的流输出
 template<typename T>
 _sync_com& operator << (T x)
 {
  strstream s;

  s << x;
  write(s.str(), s.pcount());

  return *this;
 }
};

class _asyn_com : public _base_com
{
protected:

 OVERLAPPED _ro, _wo; // 重叠I/O

 virtual bool open_port()
 {
  if(is_open())
   close();

  _com_handle = CreateFile(
   _com_str,
   GENERIC_READ | GENERIC_WRITE,
   0,
   NULL,
   OPEN_EXISTING,
   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠I/O
   NULL
   );
  assert(is_open());
  return is_open();//检测串口是否成功打开
 }

public:

 _asyn_com()
 {
  memset(&_ro, 0, sizeof(_ro));
  memset(&_wo, 0, sizeof(_wo));

  _ro.hEvent = CreateEvent(NULL, true, false, NULL);
  assert(_ro.hEvent != INVALID_HANDLE_VALUE); 
  
  _wo.hEvent = CreateEvent(NULL, true, false, NULL);
  assert(_wo.hEvent != INVALID_HANDLE_VALUE); 
 }
 virtual ~_asyn_com()
 {
  close();

  if(_ro.hEvent != INVALID_HANDLE_VALUE)
   CloseHandle(_ro.hEvent);

  if(_wo.hEvent != INVALID_HANDLE_VALUE)
   CloseHandle(_wo.hEvent);
 }
 //异步读
 int read(char *buf, int buf_len, int time_wait = 20)
 {
  if(!is_open())
   return 0;

  buf[0] = '\0';

  COMSTAT  stat;
  DWORD error;

  if(ClearCommError(_com_handle, &error, &stat) && error > 0) //清除错误
  {
   PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
   return 0;
  }

  if(!stat.cbInQue)// 缓冲区无数据
   return 0;

  unsigned long r_len = 0;

  buf_len = min((int)(buf_len ), (int)stat.cbInQue);

  if(!ReadFile(_com_handle, buf, buf_len, &r_len, &_ro)) //2000 下 ReadFile 始终返回 True
  {
   if(GetLastError() == ERROR_IO_PENDING) // 结束异步I/O
   {
    //WaitForSingleObject(_ro.hEvent, time_wait); //等待20ms
    if(!GetOverlappedResult(_com_handle, &_ro, &r_len, false))
    {
     if(GetLastError() != ERROR_IO_INCOMPLETE)//其他错误
       r_len = 0;
    }
   }
   else
    r_len = 0;
  }
   
  buf[r_len] = '\0';
  return r_len;
 }
 //异步写
 int write(char *buf, int buf_len)
 {
  if(!is_open())
   return 0;
  
  DWORD    error;
  if(ClearCommError(_com_handle, &error, NULL) && error > 0) //清除错误
   PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR); 

  unsigned long w_len = 0, o_len = 0;
  if(!WriteFile(_com_handle, buf, buf_len, &w_len, &_wo))
   if(GetLastError() != ERROR_IO_PENDING)
    w_len = 0;

  return w_len;
 }
 //异步写
 inline int write(char *buf)
 {
  assert(buf);
  return write(buf, strlen(buf));
 }
 //异步写, 支持部分类型的流输出
 template<typename T>
 _asyn_com& operator << (T x)
 {
  strstream s;

  s << x ;
  write(s.str(), s.pcount());

  return *this;
 }
};

//当接受到数据送到窗口的消息
#define ON_COM_RECEIVE WM_USER + 618  //  WPARAM 端口号

class _thread_com : public _asyn_com
{
protected:
 volatile HANDLE _thread_handle; //辅助线程
 volatile HWND _notify_hwnd; // 通知窗口
 volatile long _notify_num;//接受多少字节(>_notify_num)发送通知消息
 volatile bool _run_flag; //线程运行循环标志
 void (*_func)(int port);

 OVERLAPPED _wait_o; //WaitCommEvent use

 //线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含窗口编号
 virtual void on_receive()
 {
	 char str[270];
	 memset(str,10,270);
	 this->read(str,270);

	 int j=0;
	 bool start=false;
	 char order[90];
	 for( int i=0; i<270; i++)
	 {
		 switch(str[i])
		 {
		 case '$':
			 start=true;
			 order[0]='$';
			 j=1;
			 break;
		 case 10:
			 if( start )		//得到一个完整指令
			 {
				 GPSParam gps(order,90);
				 if(gps.DataTransform())
				 {
					 if(_notify_hwnd)
						 PostMessage( _notify_hwnd, ON_COM_RECEIVE, WPARAM(gps.X), LPARAM(gps.Y) );
					 else
						 ;	///////////////////
				 }
			 }
			 start=false;
			 j=0;
			 memset(order,0,90);
			 break;
		 default:
			 {
				 if( start )
				 {
					 order[j]=str[i];
					 j++;
				 }
			 }
		 }
		 
	 }

  if(_notify_hwnd)
   PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0));
  else
  {
   if(_func)
    _func(_port);
  }
 }
 //打开串口,同时打开监视线程
 virtual bool open_port()
 {
  if(_asyn_com::open_port())
  {
   _run_flag = true; 
   DWORD id;
   _thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id); //辅助线程
   assert(_thread_handle);
   if(!_thread_handle)
   {
    CloseHandle(_com_handle);
    _com_handle = INVALID_HANDLE_VALUE;
   }
   else
    return true;
  }
  return false;
 }

public:
 _thread_com()
 {
  _notify_num = 250;
  _notify_hwnd = NULL;
  _thread_handle = NULL;
  _func = NULL;

  memset(&_wait_o, 0, sizeof(_wait_o));
  _wait_o.hEvent = CreateEvent(NULL, true, false, NULL);
  assert(_wait_o.hEvent != INVALID_HANDLE_VALUE); 
 }
 ~_thread_com()
 {
  close();

  if(_wait_o.hEvent != INVALID_HANDLE_VALUE)
   CloseHandle(_wait_o.hEvent);
 }
 //设定发送通知, 接受字符最小值
 void set_notify_num(int num)
 {
  _notify_num = num;
 }
 int get_notify_num()
 {
  return _notify_num;
 }
 //送消息的窗口句柄
 inline void set_hwnd(HWND hWnd)
 {
  _notify_hwnd = hWnd;
 }
 inline HWND get_hwnd()
 {
  return _notify_hwnd;
 }
 inline void set_func(void (*f)(int))
 {
  _func = f;
 }
 //关闭线程及串口
 virtual void close()
 {
  if(is_open())  
  {
   _run_flag = false;
   SetCommMask(_com_handle, 0);
   SetEvent(_wait_o.hEvent);

   if(WaitForSingleObject(_thread_handle, 100) != WAIT_OBJECT_0)
    TerminateThread(_thread_handle, 0);

   CloseHandle(_com_handle);
   CloseHandle(_thread_handle);

   _thread_handle = NULL;
   _com_handle = INVALID_HANDLE_VALUE;
   ResetEvent(_wait_o.hEvent);
  }
 }
 /*辅助线程控制*/
 //获得线程句柄
 HANDLE get_thread()
 {
  return _thread_handle;
 }
 //暂停监视线程
 bool suspend()
 {
  return _thread_handle != NULL ? SuspendThread(_thread_handle) != 0xFFFFFFFF : false;
 }
 //恢复监视线程
 bool resume()
 {
  return _thread_handle != NULL ? ResumeThread(_thread_handle) != 0xFFFFFFFF : false;
 }
 //重建监视线程
 bool restart() 
 {
  if(_thread_handle) /*只有已有存在线程时*/
  {
   _run_flag = false;
   SetCommMask(_com_handle, 0);
   SetEvent(_wait_o.hEvent);

   if(WaitForSingleObject(_thread_handle, 100) != WAIT_OBJECT_0)
    TerminateThread(_thread_handle, 0);

   CloseHandle(_thread_handle);

   _run_flag = true;
   _thread_handle = NULL;

   DWORD id;
   _thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id);
   return (_thread_handle != NULL); //辅助线程
  }
  return false;
 }

private:
 //监视线程
 static DWORD WINAPI com_thread(LPVOID para)
 {
	 _thread_com *pcom = (_thread_com *)para; 
	 
	 //制定串口的监视事件 接收到一个字符 或者出现错误
	 if(!SetCommMask(pcom->_com_handle, EV_RXCHAR | EV_ERR | EV_RXFLAG ) )
		 return 0;
	 
	 COMSTAT  stat;
	 DWORD error;
	 
	 for(DWORD length, mask = 0; pcom->_run_flag && pcom->is_open(); mask = 0)
	 {
		 if(!WaitCommEvent(pcom->_com_handle, &mask, &pcom->_wait_o))
		 {
			 if(GetLastError() == ERROR_IO_PENDING)
			 {
				 GetOverlappedResult(pcom->_com_handle, &pcom->_wait_o, &length, true);
			 }
		 }

		 //错误处理
		 if ( mask & EV_ERR )		//线上错误
			 ClearCommError(pcom->_com_handle, &error, &stat);
		 
		 //接收到事件字符
		 if( mask & EV_RXFLAG ) //  EV_RXFLAG事件产生
		 {
			 ClearCommError(pcom->_com_handle, &error, &stat);
			 pcom->on_receive();
		 }

		 //接收到一个字符处理
		 if(mask & EV_RXCHAR) // == EV_RXCHAR
		 {
			 ClearCommError(pcom->_com_handle, &error, &stat);
			 if(stat.cbInQue > pcom->_notify_num)
				 pcom->on_receive();
		 }
	 }

	 return 0;
 }
 
};

typedef _thread_com _com; //名称简化

#endif //_COM_H_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -