_com.h
上传用户:fudaml
上传日期:2013-05-28
资源大小:211k
文件大小:15k
源码类别:

GPS编程

开发平台:

Visual C++

  1. /*
  2. 串口基础类库(WIN32) ver 0.1
  3. 编译器 : BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET;  GCC;
  4. class   _base_com : 虚基类 基本串口接口;
  5. class   _sync_com : 同步I/O 串口类;
  6. class   _asyn_com : 异步I/O 串口类;
  7. class _thread_com : 异步I/O 辅助读监视线程 可转发窗口消息 串口类(可继承虚函数on_receive用于读操作);
  8. class        _com : _thread_com 同名
  9. copyright(c) 2004.8 llbird wushaojian@21cn.com
  10. */
  11. /*
  12. Example :
  13. */
  14. #ifndef _COM_H_
  15. #define _COM_H_
  16. #pragma warning(disable: 4530)
  17. #pragma warning(disable: 4786)
  18. #pragma warning(disable: 4800)
  19. #include <cassert>
  20. #include <strstream>
  21. #include <algorithm>
  22. #include <exception>
  23. #include <iomanip>
  24. #include <fstream>
  25. using namespace std;
  26. #include "GPSParam.h"
  27. #include <windows.h>
  28. class _base_com   //虚基类 基本串口接口
  29. {
  30. protected:
  31.  volatile int _port;  //串口号
  32.  volatile HANDLE _com_handle;//串口句柄
  33.  char _com_str[20];
  34.  DCB _dcb;     //波特率,停止位,等
  35.  COMMTIMEOUTS _co;  // 超时时间
  36.  virtual bool open_port() = 0;
  37.  void init() //初始化
  38.  {
  39.   memset(_com_str, 0, 20);
  40.   memset(&_co, 0, sizeof(_co));
  41.   memset(&_dcb, 0, sizeof(_dcb));
  42.   _dcb.DCBlength = sizeof(_dcb);
  43.   _com_handle = INVALID_HANDLE_VALUE;
  44.  }                  
  45.  virtual bool setup_port()
  46.  {
  47.   if(!is_open())
  48.    return false;
  49.   if(!SetupComm(_com_handle, 8192, 8192))
  50.    return false; //设置推荐缓冲区
  51.   if(!GetCommTimeouts(_com_handle, &_co))
  52.    return false;
  53.   _co.ReadIntervalTimeout = 0xFFFFFFFF;
  54.   _co.ReadTotalTimeoutMultiplier = 0;
  55.   _co.ReadTotalTimeoutConstant = 0;
  56.   _co.WriteTotalTimeoutMultiplier = 0;
  57.   _co.WriteTotalTimeoutConstant = 2000;
  58.   if(!SetCommTimeouts(_com_handle, &_co))
  59.   return false; //设置超时时间
  60.   if(!PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ))
  61.   return false; //清空串口缓冲区
  62.   return true;
  63.  }       
  64.  inline void set_com_port(int port)
  65.  {
  66.   char p[12];
  67.   _port = port;
  68.   strcpy(_com_str, "\\.\COM"); 
  69.   ltoa(_port, p, 10);
  70.   strcat(_com_str, p);
  71.  }
  72. public:
  73.  _base_com()
  74.  {
  75.   init(); 
  76.  }
  77.  virtual ~_base_com()
  78.  {
  79.   close();      
  80.  }
  81.  //设置串口参数:波特率,停止位,等 支持设置字符串 "9600, 8, n, 1"
  82.  bool set_state(char *set_str) 
  83.  {
  84.   if(is_open())
  85.   {
  86.    if(!GetCommState(_com_handle, &_dcb))
  87.     return false;
  88.    if(!BuildCommDCB(set_str, &_dcb))
  89.     return false;
  90.    return SetCommState(_com_handle, &_dcb) == TRUE;
  91.   }
  92.   return false;
  93.  }
  94.  //设置内置结构串口参数:波特率,停止位
  95.  bool set_state(int BaudRate = 9600, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT, char EvtChar='n' )
  96.  {
  97.  if(is_open())
  98.  {
  99.  if(!GetCommState(_com_handle, &_dcb))
  100.  return false;
  101.  _dcb.BaudRate = BaudRate;
  102.  _dcb.ByteSize = ByteSize;
  103.  _dcb.Parity   = Parity;
  104.  _dcb.StopBits = StopBits;
  105.  _dcb.EvtChar  = EvtChar;
  106.  return SetCommState(_com_handle, &_dcb) == TRUE;
  107.  }
  108.  return false;
  109.  }
  110.  //打开串口 缺省 9600, 8, n, 1
  111.  inline bool open(int port)
  112.  {
  113.  return open(port, 9600);
  114.  }
  115.  //打开串口 缺省 baud_rate, 8, n, 1
  116.  inline bool open(int port, int baud_rate)
  117.  {
  118.   if(port < 1 || port > 1024)
  119.    return false;
  120.   set_com_port(port);
  121.   if(!open_port())
  122.    return false;
  123.   if(!setup_port())
  124.    return false;
  125.   return set_state(baud_rate);
  126.  }
  127.  //打开串口
  128.  inline bool open(int port, char *set_str)
  129.  {
  130.   if(port < 1 || port > 1024)
  131.    return false;
  132.   set_com_port(port);
  133.   if(!open_port())
  134.    return false;
  135.   if(!setup_port())
  136.    return false;
  137.   return set_state(set_str);
  138.   
  139.  }
  140.  inline bool set_buf(int in, int out)
  141.  {
  142.   return is_open() ? SetupComm(_com_handle, in, out) : false;
  143.  }
  144.  //关闭串口
  145.  inline virtual void close()
  146.  {
  147.   if(is_open())  
  148.   {
  149.    CloseHandle(_com_handle);
  150.    _com_handle = INVALID_HANDLE_VALUE;
  151.   }
  152.  }
  153.  //判断串口是或打开
  154.  inline bool is_open()
  155.  {
  156.   return _com_handle != INVALID_HANDLE_VALUE;
  157.  }
  158.  //获得串口句炳
  159.  HANDLE get_handle()
  160.  {
  161.   return _com_handle;
  162.  }
  163.  operator HANDLE()
  164.  {
  165.   return _com_handle;
  166.  }
  167. };
  168. class _sync_com : public _base_com
  169. {
  170. protected:
  171.  //打开串口
  172.  virtual bool open_port()
  173.  {
  174.   if(is_open())
  175.    close();
  176.   _com_handle = CreateFile(
  177.    _com_str,
  178.    GENERIC_READ | GENERIC_WRITE,
  179.    0,
  180.    NULL,
  181.    OPEN_EXISTING,
  182.    FILE_ATTRIBUTE_NORMAL , 
  183.    NULL
  184.    );
  185.   assert(is_open());
  186.   return is_open();//检测串口是否成功打开
  187.  }
  188. public:
  189.  _sync_com()
  190.  {
  191.  }
  192.  //同步读
  193.  int read(char *buf, int buf_len)
  194.  {
  195.   if(!is_open())
  196.    return 0;
  197.   buf[0] = '';
  198.   
  199.   COMSTAT  stat;
  200.   DWORD error;
  201.   if(ClearCommError(_com_handle, &error, &stat) && error > 0) //清除错误
  202.   {
  203.    PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
  204.    return 0;
  205.   }
  206.    
  207.   unsigned long r_len = 0;
  208.   buf_len = min(buf_len - 1, (int)stat.cbInQue);
  209.   if(!ReadFile(_com_handle, buf, buf_len, &r_len, NULL))
  210.     r_len = 0;
  211.   buf[r_len] = '';
  212.   return r_len;
  213.  }
  214.  //同步写
  215.  int write(char *buf, int buf_len)
  216.  {
  217.   if(!is_open() || !buf)
  218.    return 0;
  219.   
  220.   DWORD    error;
  221.   if(ClearCommError(_com_handle, &error, NULL) && error > 0) //清除错误
  222.    PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR);
  223.   unsigned long w_len = 0;
  224.   if(!WriteFile(_com_handle, buf, buf_len, &w_len, NULL))
  225.    w_len = 0;
  226.   return w_len;
  227.  }
  228.  //同步写
  229.  inline int write(char *buf)
  230.  {
  231.   assert(buf);
  232.   return write(buf, strlen(buf));
  233.  }
  234.  //同步写, 支持部分类型的流输出
  235.  template<typename T>
  236.  _sync_com& operator << (T x)
  237.  {
  238.   strstream s;
  239.   s << x;
  240.   write(s.str(), s.pcount());
  241.   return *this;
  242.  }
  243. };
  244. class _asyn_com : public _base_com
  245. {
  246. protected:
  247.  OVERLAPPED _ro, _wo; // 重叠I/O
  248.  virtual bool open_port()
  249.  {
  250.   if(is_open())
  251.    close();
  252.   _com_handle = CreateFile(
  253.    _com_str,
  254.    GENERIC_READ | GENERIC_WRITE,
  255.    0,
  256.    NULL,
  257.    OPEN_EXISTING,
  258.    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠I/O
  259.    NULL
  260.    );
  261.   //assert(is_open());
  262.   return is_open();//检测串口是否成功打开
  263.  }
  264. public:
  265.  _asyn_com()
  266.  {
  267.   memset(&_ro, 0, sizeof(_ro));
  268.   memset(&_wo, 0, sizeof(_wo));
  269.   _ro.hEvent = CreateEvent(NULL, true, false, NULL);
  270.   assert(_ro.hEvent != INVALID_HANDLE_VALUE); 
  271.   
  272.   _wo.hEvent = CreateEvent(NULL, true, false, NULL);
  273.   assert(_wo.hEvent != INVALID_HANDLE_VALUE); 
  274.  }
  275.  virtual ~_asyn_com()
  276.  {
  277.   close();
  278.   if(_ro.hEvent != INVALID_HANDLE_VALUE)
  279.    CloseHandle(_ro.hEvent);
  280.   if(_wo.hEvent != INVALID_HANDLE_VALUE)
  281.    CloseHandle(_wo.hEvent);
  282.  }
  283.  //异步读
  284.  int read(char *buf, int buf_len, int time_wait = 20)
  285.  {
  286.   if(!is_open())
  287.    return 0;
  288.   buf[0] = '';
  289.   COMSTAT  stat;
  290.   DWORD error;
  291.   if(ClearCommError(_com_handle, &error, &stat) && error > 0) //清除错误
  292.   {
  293.    PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
  294.    return 0;
  295.   }
  296.   if(!stat.cbInQue)// 缓冲区无数据
  297.    return 0;
  298.   unsigned long r_len = 0;
  299.   buf_len = min((int)(buf_len ), (int)stat.cbInQue);
  300.   if(!ReadFile(_com_handle, buf, buf_len, &r_len, &_ro)) //2000 下 ReadFile 始终返回 True
  301.   {
  302.    if(GetLastError() == ERROR_IO_PENDING) // 结束异步I/O
  303.    {
  304.     //WaitForSingleObject(_ro.hEvent, time_wait); //等待20ms
  305.     if(!GetOverlappedResult(_com_handle, &_ro, &r_len, false))
  306.     {
  307.      if(GetLastError() != ERROR_IO_INCOMPLETE)//其他错误
  308.        r_len = 0;
  309.     }
  310.    }
  311.    else
  312.     r_len = 0;
  313.   }
  314.    
  315.   buf[r_len] = '';
  316.   return r_len;
  317.  }
  318.  //异步写
  319.  int write(char *buf, int buf_len)
  320.  {
  321.   if(!is_open())
  322.    return 0;
  323.   
  324.   DWORD    error;
  325.   if(ClearCommError(_com_handle, &error, NULL) && error > 0) //清除错误
  326.    PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR); 
  327.   unsigned long w_len = 0, o_len = 0;
  328.   if(!WriteFile(_com_handle, buf, buf_len, &w_len, &_wo))
  329.    if(GetLastError() != ERROR_IO_PENDING)
  330.     w_len = 0;
  331.   return w_len;
  332.  }
  333.  //异步写
  334.  inline int write(char *buf)
  335.  {
  336.   assert(buf);
  337.   return write(buf, strlen(buf));
  338.  }
  339.  //异步写, 支持部分类型的流输出
  340.  template<typename T>
  341.  _asyn_com& operator << (T x)
  342.  {
  343.   strstream s;
  344.   s << x ;
  345.   write(s.str(), s.pcount());
  346.   return *this;
  347.  }
  348. };
  349. //当接受到数据送到窗口的消息
  350. #define ON_COM_RECEIVE WM_USER + 618  //  WPARAM 端口号
  351. class _thread_com : public _asyn_com
  352. {
  353. protected:
  354.  volatile HANDLE _thread_handle; //辅助线程
  355.  volatile HANDLE _file_thread_handle; //文件辅助线程
  356.  CString m_filename; //文件名
  357.  volatile HWND _notify_hwnd; // 通知窗口
  358.  volatile long _notify_num;//接受多少字节(>_notify_num)发送通知消息
  359.  volatile bool _run_flag; //线程运行循环标志
  360.  void (*_func)(WPARAM wp, LPARAM lp);
  361. // GPSParam gps; //存储临时gps返回参数
  362.  OVERLAPPED _wait_o; //WaitCommEvent use
  363.  //线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含窗口编号
  364.  virtual void on_receive()
  365.  {
  366.  char str[270];
  367.  memset(str,10,270);
  368.  this->read(str,270);
  369.  int j=0;
  370.  bool start=false;
  371.  char order[90];
  372.  for( int i=0; i<270; i++)
  373.  {
  374.  switch(str[i])
  375.  {
  376.  case '$':
  377.  start=true;
  378.  order[0]='$';
  379.  j=1;
  380.  break;
  381.  case 10:
  382.  if( start ) //得到一个完整指令
  383.  {
  384. ////////////////////////////////////
  385. ///如果,消息响应不及时,gps内存有可能泄露
  386.  GPSParam *gps=new GPSParam;
  387.  gps->SetParam(order,90);
  388.  if(gps->DataTransform())
  389.  {
  390.  if(_notify_hwnd)
  391.  {
  392.  PostMessage( _notify_hwnd, ON_COM_RECEIVE, WPARAM(gps), 0 );
  393.  }
  394.  else
  395.  ; ///////////////////
  396.  }
  397. //////////////////////////////////////////////////////
  398. /*
  399.  //GPSParam gps(order,90);
  400.  gps.SetParam(order,j);
  401.  if(gps.DataTransform())
  402.  {
  403.  if(_notify_hwnd)
  404.  PostMessage( _notify_hwnd, ON_COM_RECEIVE, WPARAM(gps.X), LPARAM(gps.Y) );
  405.  else
  406.  ; ///////////////////
  407.  }
  408. */
  409.  }
  410.  start=false;
  411.  j=0;
  412.  memset(order,0,90);
  413.  break;
  414.  default:
  415.  {
  416.  if( start )
  417.  {
  418.  order[j]=str[i];
  419.  j++;
  420.  }
  421.  }
  422.  }
  423.  
  424.  }
  425. /*
  426.   if(_notify_hwnd)
  427.    PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0));
  428.   else
  429.   {
  430.    if(_func)
  431.     _func(_port);
  432.   }
  433. */
  434.  }
  435.  //打开串口,同时打开监视线程
  436.  virtual bool open_port()
  437.  {
  438.   if(_asyn_com::open_port())
  439.   {
  440.    _run_flag = true; 
  441.    DWORD id;
  442.    _thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id); //辅助线程
  443.    assert(_thread_handle);
  444.    if(!_thread_handle)
  445.    {
  446.     CloseHandle(_com_handle);
  447.     _com_handle = INVALID_HANDLE_VALUE;
  448.    }
  449.    else
  450.     return true;
  451.   }
  452.   return false;
  453.  }
  454. public:
  455.  _thread_com()
  456.  {
  457.   _notify_num = 250;
  458.   _notify_hwnd = NULL;
  459.   _thread_handle = NULL;
  460.   _file_thread_handle = NULL;
  461.   _func = NULL;
  462.   memset(&_wait_o, 0, sizeof(_wait_o));
  463.   _wait_o.hEvent = CreateEvent(NULL, true, false, NULL);
  464.   assert(_wait_o.hEvent != INVALID_HANDLE_VALUE); 
  465.  }
  466.  ~_thread_com()
  467.  {
  468.   close();
  469.   if(_wait_o.hEvent != INVALID_HANDLE_VALUE)
  470.    CloseHandle(_wait_o.hEvent);
  471.  }
  472.  //设定发送通知, 接受字符最小值
  473.  void set_notify_num(int num)
  474.  {
  475.   _notify_num = num;
  476.  }
  477.  int get_notify_num()
  478.  {
  479.   return _notify_num;
  480.  }
  481.  //送消息的窗口句柄
  482.  inline void set_hwnd(HWND hWnd)
  483.  {
  484.   _notify_hwnd = hWnd;
  485.  }
  486.  inline HWND get_hwnd()
  487.  {
  488.   return _notify_hwnd;
  489.  }
  490.  inline void set_func(void (*f)(WPARAM wp, LPARAM lp))
  491.  {
  492.   _func = f;
  493.  }
  494.  //关闭线程及串口
  495.  virtual void close()
  496.  {
  497.   if(is_open())  
  498.   {
  499.    _run_flag = false;
  500.    SetCommMask(_com_handle, 0);
  501.    SetEvent(_wait_o.hEvent);
  502.    if(WaitForSingleObject(_thread_handle, 100) != WAIT_OBJECT_0)
  503.     TerminateThread(_thread_handle, 0);
  504.    CloseHandle(_com_handle);
  505.    CloseHandle(_thread_handle);
  506.    _thread_handle = NULL;
  507.    _com_handle = INVALID_HANDLE_VALUE;
  508.    ResetEvent(_wait_o.hEvent);
  509.   }
  510.  }
  511.  /*辅助线程控制*/
  512.  //获得线程句柄
  513.  HANDLE get_thread()
  514.  {
  515.   return _thread_handle;
  516.  }
  517.  //暂停监视线程
  518.  bool suspend()
  519.  {
  520.   return _thread_handle != NULL ? SuspendThread(_thread_handle) != 0xFFFFFFFF : false;
  521.  }
  522.  //恢复监视线程
  523.  bool resume()
  524.  {
  525.   return _thread_handle != NULL ? ResumeThread(_thread_handle) != 0xFFFFFFFF : false;
  526.  }
  527.  //重建监视线程
  528.  bool restart() 
  529.  {
  530.   if(_thread_handle) /*只有已有存在线程时*/
  531.   {
  532.    _run_flag = false;
  533.    SetCommMask(_com_handle, 0);
  534.    SetEvent(_wait_o.hEvent);
  535.    if(WaitForSingleObject(_thread_handle, 100) != WAIT_OBJECT_0)
  536.     TerminateThread(_thread_handle, 0);
  537.    CloseHandle(_thread_handle);
  538.    _run_flag = true;
  539.    _thread_handle = NULL;
  540.    DWORD id;
  541.    _thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id);
  542.    return (_thread_handle != NULL); //辅助线程
  543.   }
  544.   return false;
  545.  }
  546. bool Open_file(CString str)
  547. {
  548. if (_file_thread_handle ==NULL) 
  549. {
  550. m_filename=str;
  551. DWORD id;
  552. _file_thread_handle=CreateThread(NULL,0,file_thread,this,0,&id);
  553. return (_file_thread_handle != NULL);
  554. }
  555. return false;
  556. }
  557. private:
  558.  //监视线程
  559.  static DWORD WINAPI com_thread(LPVOID para)
  560.  {
  561.  _thread_com *pcom = (_thread_com *)para; 
  562.  
  563.  //制定串口的监视事件 接收到一个字符 或者出现错误
  564.  if(!SetCommMask(pcom->_com_handle, EV_RXCHAR | EV_ERR | EV_RXFLAG ) )
  565.  return 0;
  566.  
  567.  COMSTAT  stat;
  568.  DWORD error;
  569.  
  570.  for(DWORD length, mask = 0; pcom->_run_flag && pcom->is_open(); mask = 0)
  571.  {
  572.  if(!WaitCommEvent(pcom->_com_handle, &mask, &pcom->_wait_o))
  573.  {
  574.  if(GetLastError() == ERROR_IO_PENDING)
  575.  {
  576.  GetOverlappedResult(pcom->_com_handle, &pcom->_wait_o, &length, true);
  577.  }
  578.  }
  579.  //错误处理
  580.  if ( mask & EV_ERR ) //线上错误
  581.  ClearCommError(pcom->_com_handle, &error, &stat);
  582.  
  583.  //接收到事件字符
  584.  if( mask & EV_RXFLAG ) //  EV_RXFLAG事件产生
  585.  {
  586.  ClearCommError(pcom->_com_handle, &error, &stat);
  587.  pcom->on_receive();
  588.  }
  589.  //接收到一个字符处理
  590.  if(mask & EV_RXCHAR) // == EV_RXCHAR
  591.  {
  592.  ClearCommError(pcom->_com_handle, &error, &stat);
  593.  if(stat.cbInQue > pcom->_notify_num)
  594.  pcom->on_receive();
  595.  }
  596.  }
  597.  return 0;
  598.  }
  599.  static DWORD WINAPI file_thread(LPVOID para)
  600.  {  
  601.  _thread_com *pcom = (_thread_com *)para; 
  602.  
  603.  ifstream in;
  604.  in.open(pcom->m_filename);
  605.  while (true)
  606.  {
  607. // Sleep(5);
  608.  char str[270];
  609.  memset(str,10,270);
  610.  if( !in.getline(str,270)  )
  611.  break;
  612.  
  613.  int j=0;
  614.  bool start=false;
  615.  char order[90]; //存储一条指令
  616.  for( int i=0; i<270; i++)
  617.  {
  618.  switch(str[i])
  619.  {
  620.  case '$':
  621.  start=true;
  622.  order[0]='$';
  623.  j=1;
  624.  break;
  625.  case 10:
  626.  if( start ) //得到一个完整指令
  627.  {
  628.  GPSParam *gps=new GPSParam;
  629.  gps->SetParam(order,90);
  630.  if(gps->DataTransform())
  631.  {
  632.  if(pcom->_notify_hwnd)
  633.  {
  634.  PostMessage( pcom->_notify_hwnd, ON_COM_RECEIVE, WPARAM(gps), 0 );
  635.  }
  636.  else
  637.  delete gps; ///////////////////
  638.  /*
  639.  if( pcom->_func )
  640.  {
  641. //  pcom->_func( (WPARAM)gps,(LPARAM)pcom->_notify_hwnd );
  642.  }
  643.  else
  644.  delete gps;
  645.  */
  646.  }
  647.  else
  648.  delete gps;
  649. // delete gps;
  650.  }
  651.  start=false;
  652.  j=0;
  653.  memset(order,0,90);
  654.  break;
  655.  default:
  656.  {
  657.  if( start )
  658.  {
  659.  order[j]=str[i];
  660.  j++;
  661.  }
  662.  }
  663.  }
  664.  
  665.  }
  666.  
  667.  }
  668.  return 0;
  669.  }
  670. };
  671. typedef _thread_com _com; //名称简化
  672. #endif //_COM_H_