?? com_class.h
字號:
/*
串口基礎(chǔ)類庫(WIN32) ver 0.1
編譯器 : BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET; GCC;
class _base_com : 虛基類 基本串口接口;
class _aync_com : 同步I/O 串口類;
class _sync_com : 異步I/O 串口類;
class _thread_com : 異步I/O 輔助讀監(jiān)視線程 可轉(zhuǎn)發(fā)窗口消息 串口類(可繼承虛函數(shù)on_receive用于讀操作);
copyright(c) 2004.8 llbird wushaojian@21cn.com
*/
#ifndef _COM_CLASS_H_
#define _COM_CLASS_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 <windows.h>
class _base_com //虛基類 基本串口接口
{
protected:
volatile int _port; //串口號
volatile HANDLE _com_handle;//串口句柄
DCB _dcb; //波特率,停止位,等
int _in_buf, _out_buf; // 緩沖區(qū)
COMMTIMEOUTS _co; // 超時時間
//虛函數(shù),用于不同方式的串口打開
virtual bool open_port() = 0;
void init() //初始化
{
memset(&_dcb, 0, sizeof(_dcb));
_dcb.DCBlength = sizeof(_dcb);
_com_handle = INVALID_HANDLE_VALUE;
_in_buf = _out_buf = 8192;
memset(&_co, 0, sizeof(_co));
_co.ReadIntervalTimeout = 0xFFFFFFFF;
_co.ReadTotalTimeoutMultiplier = 0;
_co.ReadTotalTimeoutConstant = 0;
_co.WriteTotalTimeoutMultiplier = 0;
_co.WriteTotalTimeoutConstant = 5000;
}
public:
_base_com()
{
init();
}
virtual ~_base_com()
{
close();
}
/*基本參數(shù)設(shè)置*/
//設(shè)置串口參數(shù):波特率,停止位,等
inline bool set_para()
{
return is_open() ? SetCommState(_com_handle, &_dcb) : false;
}
//打開設(shè)置對話框
bool config_dialog()
{
if(is_open())
{
COMMCONFIG cf;
memset(&cf, 0, sizeof(cf));
cf.dwSize = sizeof(cf);
cf.wVersion = 1;
char com_str[10];
strcpy(com_str, "COM");
ltoa(_port, com_str + 3, 10);
if(CommConfigDialog(com_str, NULL, &cf))
{
memcpy(&_dcb, &cf.dcb, sizeof(DCB));
return SetCommState(_com_handle, &_dcb);
}
}
return false;
}
//支持設(shè)置字符串 "9600, 8, n, 1"
bool set_dcb(char *set_str)
{
return bool(BuildCommDCB(set_str, &_dcb));
}
//設(shè)置內(nèi)置結(jié)構(gòu)串口參數(shù):波特率,停止位
bool set_dcb(int BaudRate, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT)
{
_dcb.BaudRate = BaudRate;
_dcb.ByteSize = ByteSize;
_dcb.Parity = Parity;
_dcb.StopBits = StopBits;
return true;
}
//設(shè)置緩沖區(qū)大小
inline bool set_buf(int in_buf, int out_buf)
{
return is_open() ? SetupComm(_com_handle, in_buf, out_buf) : false;
}
//打開串口 缺省 9600, 8, n, 1
inline bool open(int port)
{
if(port < 1 || port > 1024)
return false;
set_dcb(9600);
_port = port;
return open_port();
}
//打開串口 缺省 baud_rate, 8, n, 1
inline bool open(int port, int baud_rate)
{
if(port < 1 || port > 1024)
return false;
set_dcb(baud_rate);
_port = port;
return open_port();
}
//打開串口
inline bool open(int port, char *set_str)
{
if(port < 1 || port > 1024)
return false;
if(!BuildCommDCB(set_str, &_dcb))
return false;
_port = port;
return open_port();
}
//關(guān)閉串口
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;
}
};
class _sync_com : public _base_com
{
protected:
//打開串口
virtual bool open_port()
{
if(is_open())
close();
char com_str[10];
strcpy(com_str, "COM");
ltoa(_port, com_str + 3, 10);
_com_handle = CreateFile(
com_str,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL ,
NULL
);
assert(is_open());
if(!is_open())//檢測串口是否成功打開
return false;
BOOL ret;
ret = SetupComm(_com_handle, _in_buf, _out_buf); //設(shè)置推薦緩沖區(qū)
assert(ret);
ret &= SetCommState(_com_handle, &_dcb); //設(shè)置串口參數(shù):波特率,停止位,等
assert(ret);
ret &= SetCommTimeouts(_com_handle, &_co); //設(shè)置超時時間
assert(ret);
ret &= PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); //清空串口緩沖區(qū)
assert(ret);
if(!ret)
{
close();
return false;
}
return true;
}
public:
_sync_com()
{
_co.ReadTotalTimeoutConstant = 5000;
}
//同步讀
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); /*清除輸入緩沖區(qū)*/
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();
char com_str[10];
strcpy(com_str, "COM");
ltoa(_port, com_str + 3, 10);
_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());
if(!is_open())//檢測串口是否成功打開
return false;
BOOL ret;
ret = SetupComm(_com_handle, _in_buf, _out_buf); //設(shè)置推薦緩沖區(qū)
assert(ret);
ret = SetCommState(_com_handle, &_dcb); //設(shè)置串口參數(shù):波特率,停止位,等
assert(ret);
ret = SetCommTimeouts(_com_handle, &_co); //設(shè)置超時時間
assert(ret);
ret = PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); //清空串口緩沖區(qū)
assert(ret);
return true;
}
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)
{
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); /*清除輸入緩沖區(qū)*/
return 0;
}
if(!stat.cbInQue)// 緩沖區(qū)無數(shù)據(jù)
return 0;
unsigned long r_len = 0;
buf_len = min((int)(buf_len - 1), (int)stat.cbInQue);
if(!ReadFile(_com_handle, buf, buf_len, &r_len, &_ro)) //2000 下 ReadFile 始終返回 True
{
if(GetLastError() == ERROR_IO_PENDING) // 結(jié)束異步I/O
{
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;
assert(buf);
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;
}
};
//當(dāng)接受到數(shù)據(jù)送到窗口的消息
#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;//接受多少字節(jié)(>_notify_num)發(fā)送通知消息
volatile bool _run_flag; //線程運行循環(huán)標志
OVERLAPPED _wait_o; //WaitCommEvent use
//線程收到消息自動調(diào)用, 如窗口句柄有效, 送出消息, 包含窗口編號
virtual void on_receive()
{
if(_notify_hwnd)
PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0));
}
//打開串口,同時打開監(jiān)視線程
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 = 0;
_notify_hwnd = NULL;
_thread_handle = 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);
}
//設(shè)定發(fā)送通知, 接受字符最小值 默認 0
void set_notify_num(int num)
{
_notify_num = num;
}
//送消息的窗口句柄
inline void set_hwnd(HWND hWnd)
{
_notify_hwnd = hWnd;
}
//關(guān)閉線程及串口
virtual void close()
{
if(is_open())
{
_run_flag = false;
SetCommMask(_com_handle, 0);
ResetEvent(_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;
}
}
/*輔助線程控制*/
//獲得線程句柄
HANDLE get_thread()
{
return _thread_handle;
}
//暫停監(jiān)視線程
bool suspend()
{
return _thread_handle != NULL ? SuspendThread(_thread_handle) != 0xFFFFFFFF : false;
}
//恢復(fù)監(jiān)視線程
bool resume()
{
return _thread_handle != NULL ? ResumeThread(_thread_handle) != 0xFFFFFFFF : false;
}
private:
//監(jiān)視線程
static DWORD WINAPI com_thread(LPVOID para)
{
_thread_com *pcom = (_thread_com *)para;
if(!SetCommMask(pcom->_com_handle, EV_RXCHAR | EV_ERR))
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) // == EV_ERR
ClearCommError(pcom->_com_handle, &error, &stat);
if(mask & EV_RXCHAR) // == EV_RXCHAR
{
ClearCommError(pcom->_com_handle, &error, &stat);
if(stat.cbInQue > pcom->_notify_num)
pcom->on_receive();
}
}
return 0;
}
};
#endif _COM_CLASS_H_
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -