偶写的串口通信类

适用于BCB6.0,  CB2006/TC2006

用法:

TMyComm<ThreadRd,ThreadWrt> Comm;  //异步模式Comm类, 含有读线程和写线程,有OnWritten,OnRead,OnSignal,OnError事件

TMyComm<BlockRd,BlockWrt> Comm;   //同步模式Comm类(阻塞),无读线程和写线程,使用Write和Read方法类似于文件读写的方式

TMyComm<ThreadRd,BlockWrt> Comm;   //有读线程无写线程, Write类似于普通文件写(写完才返回), 能过OnRead事件读到数据 

TMyComm<BlockRd,ThreadWrt> Comm;  //和上面相反, 有写线程无读线程, 不建议使用此模式, 除非只是用写功能或者你知道你在干什么.

另外使用BlockRd模式时建议使用SetTimeouts方法设置超时值,不然死在Read上可别怪我没说:)

//---------------------------------------------------------------------------

#ifndef TMyCommH
#define TMyCommH
#include <Classes.hpp>
#ifndef COMMREADBUFFERSIZE
#define COMMREADBUFFERSIZE 2048
#endif
#pragma option push -w-inl
enum TFlowControl {fcNull=0,fcHardware=1,fcXonXoff=2};
//---------------------------------------------------------------------------
struct TMyDCB :DCB{
        TMyDCB(){
         ZeroMemory(this,sizeof(DCB));
                DCBlength=sizeof(TMyDCB);
        }
        TMyDCB(const DCB &dcb){
         CopyMemory(this,&dcb,sizeof(DCB));
        }
        TMyDCB& operator=(const DCB &dcb){
         CopyMemory(this,&dcb,sizeof(DCB));
                return *this;
        }

 bool Build(const char *strDCB){        //eg."baud=1200 parity=N data=8 stop=1","9600,n,8,1"
         return BuildCommDCB(strDCB,this);
        }

        void SetFlowControl(TFlowControl FlowControl){
                fOutxCtsFlow=(FlowControl==fcHardware);
                fInX=fOutX=(FlowControl==fcXonXoff);
                fRtsControl=(FlowControl==fcHardware)?RTS_CONTROL_HANDSHAKE:RTS_CONTROL_ENABLE;
        }
       
};

template<class p_rd,class p_wt> class TMyComm:
 public p_rd,public p_wt
{
 TMyComm(const TMyComm&);
        TMyComm & operator=(const TMyComm&);
protected:
 HANDLE hComm;
        AnsiString FPort;
        TMyDCB dcb;
        void CheckOpened(){if(!Opened()) throw(Exception("Port do not opened!"));}
public:
 TMyComm():hComm(INVALID_HANDLE_VALUE),p_rd(hComm),p_wt(hComm){;}
        ~TMyComm(){Close();}

        // Open & Close
        void Open(const AnsiString &Port);
        void Close();
        bool Opened(){return hComm!=INVALID_HANDLE_VALUE;}
        AnsiString GetPort(){return FPort;}

        // Read & Write
        bool TransmitCommChar(char c){
         CheckOpened();
                return ::TransmitCommChar(hComm,c);
        }
        //dwFunc: CLRDTR,CLRRTS,SETDTR,SETRTS,SETXOFF,SETXON,SETBREAK,CLRBREAK,RESETDEV
        bool EscapeCommFunction(DWORD dwFunc){
         CheckOpened();
                return ::EscapeCommFunction(hComm,dwFunc);
        }

        void Flush(){CheckOpened();FlushFileBuffers(hComm);}
        void ClearRdBuf(){CheckOpened();PurgeComm(hComm,PURGE_RXABORT|PURGE_RXCLEAR);}
        void ClearWrtBuf(){CheckOpened();PurgeComm(hComm,PURGE_TXABORT|PURGE_TXCLEAR);}

        // Info
        HANDLE GetHandle(){return hComm;}
        DWORD GetCommModemStatus(){         //MS_CTS_ON,MS_DSR_ON,MS_RING_ON,MS_RLSD_ON
         CheckOpened();
                DWORD Result=0;
                Win32Check(::GetCommModemStatus(hComm,&Result));
                return Result;
        }

        // Setting DCB,Must be Opened;
        void SetDCB(const DCB&);
        TMyDCB GetDCB(){CheckOpened();return dcb;}

        void SetBaudRate(DWORD);
        void SetParity(BYTE);
        void SetByteSize(BYTE);
        void SetStopBits(BYTE);
 DWORD GetBaudRate(){return GetDCB().BaudRate;}                 /* Baudrate at which running       */
        BYTE GetParity(){return GetDCB().Parity;}                      /* 0-4=None,Odd,Even,Mark,Space    */
        BYTE GetByteSize(){return GetDCB().ByteSize;}                  /* Number of bits/byte, 4-8        */
        BYTE GetStopBits(){return GetDCB().StopBits;}                  /* 0,1,2 = 1, 1.5, 2               */
        /*//winbase.h defined/
        #define NOPARITY            0
        #define ODDPARITY           1
        #define EVENPARITY          2
        #define MARKPARITY          3
        #define SPACEPARITY         4

        #define ONESTOPBIT          0
        #define ONE5STOPBITS        1
        #define TWOSTOPBITS         2
        /*///
 // Setting TimeOut
        void SetTimeouts(const COMMTIMEOUTS&);
        void SetTimeouts(DWORD RdItv,DWORD RdMult=0,DWORD RdConst=0,
         DWORD WrtMult=0,DWORD WrtConst=0);
        COMMTIMEOUTS GetTimeouts();

        // Setting Buffer
        void SetBuffers(DWORD In,DWORD Out)
        {
         CheckOpened();
                Win32Check(SetupComm(hComm,In,Out));
        }
};
// BlockWrt-------------------------------------------
struct BlockWrt{
 BlockWrt(HANDLE &_hComm):hComm(_hComm),Opened(false){;}
        DWORD Write(void *Buf,DWORD Len)
        {
         if(!Opened)return 0;
                DWORD Result=Len;
                if(Result && !WriteFile(hComm, Buf, Result,&Result,&osWrite))
                {
                        Result=0;
                        if (GetLastError() == ERROR_IO_PENDING)
                                GetOverlappedResult(hComm,&osWrite,&Result,true);
                }
                return Result;
        }
 void Open()
        {
         if(Opened)return;
         ZeroMemory(&osWrite,sizeof(osWrite));
         osWrite.hEvent=CreateEvent(NULL, true, false, NULL);
         Opened=true;
        }
        void Close()
        {
         if(!Opened)return;
                PurgeComm(hComm,PURGE_TXABORT|PURGE_TXCLEAR);
         CloseHandle(osWrite.hEvent);
         Opened=false;
        }
private:
 HANDLE &hComm;
        bool Opened;
        OVERLAPPED osWrite;
};
// BlockRd-------------------------------------------
struct BlockRd{
 BlockRd(HANDLE &_hComm):hComm(_hComm),Opened(false){;}
        DWORD Read(void *Buf,DWORD Len)
        {
                if(!Opened)return 0;
                DWORD Result=Len;
                if (Result && !ReadFile(hComm, Buf, Result, &Result, &osRead))
                {
                        Result=0;
                        if (GetLastError() == ERROR_IO_PENDING)
                                GetOverlappedResult(hComm,&osRead,&Result,true);
                }
                return Result;
        }
 void Open()
        {
         if(Opened)return;
         ZeroMemory(&osRead,sizeof(osRead));
         osRead.hEvent=CreateEvent(NULL, true, false, NULL);
         Opened=true;
        }
        void Close()
        {
         if(!Opened)return;
                PurgeComm(hComm,PURGE_RXABORT|PURGE_RXCLEAR);
         CloseHandle(osRead.hEvent);
         Opened=false;
        }
private:
 HANDLE &hComm;
        bool Opened;
        OVERLAPPED osRead;
};
// ThreadWrt-------------------------------------------
typedef void (__closure *TWrtEvent)(HANDLE,void*,DWORD);
class TCommWriter : public TThread
{
private:
 struct TWrtItem{
         DWORD Len;
                char Buf[0];
        };
 HANDLE &hComm;
        OVERLAPPED osWrite;
 TThreadList *_WriteQueue;
        HANDLE evWrite;
        TWrtEvent OnWritten;
protected:
 void __fastcall Execute()
        {
                while(!Terminated)
                {
                        WaitForSingleObject(evWrite,INFINITE);
                        TWrtItem *Item=NULL;
                        TList *pList = _WriteQueue->LockList();
                        try
                        {
                                if(pList->Count>0)
                                {
                                        Item=(TWrtItem*)pList->First();
                                        pList->Delete(0);
                                }
                                else
                                {
                                        ResetEvent(evWrite);
                                }
                        }
                        __finally
                        {
                                _WriteQueue->UnlockList();
                        }
                        if(Item)
                        {
                                DWORD Result=0;
                                try{
                                        if(Item->Len&&!WriteFile(hComm, Item->Buf ,Item->Len,&Result,&osWrite))
                                        {
                                                if (GetLastError() == ERROR_IO_PENDING)
                                                        GetOverlappedResult(hComm,&osWrite,&Result,true);
                                        }
                                        if(Result&&OnWritten) OnWritten(hComm,Item->Buf,Item->Len);
                                }
                                __finally
                                {
                                 free(Item);
                                }
                        }
                }
        }
public:
 __fastcall TCommWriter(HANDLE &handle,TWrtEvent WrtEvent)
         :TThread(true),hComm(handle),OnWritten(WrtEvent)
        {
  _WriteQueue=new TThreadList;
         evWrite=CreateEvent(NULL,true,false,NULL);
                ZeroMemory(&osWrite,sizeof(osWrite));
                osWrite.hEvent=CreateEvent(NULL,true,false,NULL);
        }
 __fastcall ~TCommWriter()
        {
  Clear();
         CloseHandle(evWrite);
                CloseHandle(osWrite.hEvent);
  delete _WriteQueue;
        }
        void __fastcall Terminate(void)
        {
  TThread::Terminate();
                SetEvent(osWrite.hEvent);
  SetEvent(evWrite);
                PurgeComm(hComm,PURGE_TXABORT|PURGE_TXCLEAR);
        }
 void Write(void *Buf,DWORD Len)
        {
                TWrtItem *Data=(TWrtItem *)malloc(sizeof(TWrtItem)+Len);
                Data->Len=Len;
                CopyMemory(Data->Buf,Buf,Len);
                _WriteQueue->LockList();
                _WriteQueue->Add(Data);
                SetEvent(evWrite);
                _WriteQueue->UnlockList();
        }
 void Clear()
        {
                TList *pList = _WriteQueue->LockList();
                try
                {
                        for (int i = 0; i < pList->Count; i++)
                        {
                                free(pList->Items[i]);
                        }
                        pList->Clear();
                }
                __finally
                {
                        _WriteQueue->UnlockList();
                }
        }
};

struct ThreadWrt{

 ThreadWrt(HANDLE &_hComm):hComm(_hComm),Wrt(NULL),OnWritten(NULL){;}
        ~ThreadWrt(){Close();}
        TWrtEvent OnWritten;

        DWORD Write(void *Buf,DWORD Len)
        {
         if(Wrt==NULL||Len==0)return 0;
                Wrt->Write(Buf,Len);
                return Len;
        }
 void Open()
        {
         if(Wrt)return;
                Wrt=new TCommWriter(hComm,OnWritten);
                Wrt->Resume();
        }
        void Close()
        {
         if(Wrt==NULL)return;
                Wrt->Terminate();
                Wrt->WaitFor();
                delete Wrt;
                Wrt=NULL;
        }
private:
 TCommWriter *Wrt;
        HANDLE &hComm;
};

// ThreadRd-------------------------------------------
typedef void (__closure *TRdEvent)(HANDLE,void*,DWORD);
typedef void (__closure *TRdError)(HANDLE,DWORD ErrorCode);
typedef void (__closure *TRdSignal)(HANDLE,DWORD EvtMask);

class TCommReader : public TThread
{
private:
 HANDLE &hComm;
        TRdEvent OnRead;
        OVERLAPPED osRead;
        OVERLAPPED osStatus;
        HANDLE hExit;
protected:
 void __fastcall Execute()
        {
            char Buffer[COMMREADBUFFERSIZE];
            bool WaitingRead=false;
            bool WaitingStat=false;
            DWORD Len=0;
            DWORD Evt;
            HANDLE hArray[3]={osRead.hEvent,osStatus.hEvent,hExit};
            SetCommMask(hComm,EV_CTS|EV_DSR|EV_ERR|EV_RING|EV_RLSD);

            while(!Terminated)
            {
                if (!WaitingRead)
                {
                    if (!ReadFile(hComm, Buffer, COMMREADBUFFERSIZE, &Len, &osRead))
                    {
                        if (GetLastError() == ERROR_IO_PENDING)  WaitingRead = true;
                    }
                    else
                    {    // read completed immediately
                        if (Len>0)
                        {
                            if(OnRead) OnRead(hComm,Buffer,Len);
                        }
                        else
                            Sleep(1);
                    }
                }
                if (!WaitingStat)
                {
                    if(!WaitCommEvent(hComm, &Evt, &osStatus))
                    {
                        if (GetLastError() == ERROR_IO_PENDING) WaitingStat = true;
                    }
                    else
                    {
                        if(OnSignal) OnSignal(hComm,Evt);
                    }
                }
                if(WaitingRead&&WaitingStat)
                {
                    DWORD dwRes = WaitForMultipleObjects(3,hArray,false,INFINITE);
                    switch(dwRes)
                    {
                        case WAIT_OBJECT_0: //Read
                            if(GetOverlappedResult(hComm, &osRead, &Len, false))
                            {
                             if(Len&&OnRead) OnRead(hComm,Buffer,Len);
                            }
                            WaitingRead = false;
                            break;
                        case WAIT_OBJECT_0+1: //State
                            if(GetOverlappedResult(hComm, &osStatus, &Len, false))
                            {
                                if(Evt&EV_ERR)
                                {
                                    DWORD ErrorCode=0;
                                    if(ClearCommError(hComm, &ErrorCode,NULL)&&OnError)
                                     OnError(hComm,ErrorCode);
                                }
                                else
                                    if(OnSignal) OnSignal(hComm,Evt);
                            }
                            WaitingStat=false;
                            break;
                        case WAIT_OBJECT_0+2: //Exit
                            goto end;
                    }
                }
            }
end:
        }
public:
        TRdError OnError;
        TRdSignal OnSignal;
 __fastcall TCommReader(HANDLE &handle,TRdEvent RdEvent)
         :TThread(true),hComm(handle),OnRead(RdEvent),OnSignal(NULL),OnError(NULL)
        {
         ZeroMemory(&osRead,sizeof(osRead));
                osRead.hEvent=CreateEvent(NULL,true,false,NULL);
                osStatus.hEvent=CreateEvent(NULL,true,false,NULL);
                hExit=CreateEvent(NULL,false,false,NULL);
        }
        __fastcall ~TCommReader()
        {
         CloseHandle(osRead.hEvent);
                CloseHandle(osStatus.hEvent);
                CloseHandle(hExit);
        }
        void __fastcall Terminate(void)
        {
  TThread::Terminate();
                PurgeComm(hComm,PURGE_RXABORT|PURGE_RXCLEAR);
                SetEvent(hExit);
        }
};
struct ThreadRd{
 ThreadRd(HANDLE &_hComm)
         :hComm(_hComm),Rd(NULL),OnRead(NULL),OnSignal(NULL),OnError(NULL)
                {;}
        ~ThreadRd(){Close();}
        TRdEvent OnRead;
        TRdError OnError;
        TRdSignal OnSignal;

        DWORD Read(void *Buf,DWORD Len)
        {
         return 0;
        }
 void Open()
        {
         if(Rd)return;
                Rd=new TCommReader(hComm,OnRead);
                Rd->OnSignal=OnSignal;
                Rd->OnError=OnError;
                Rd->Resume();
        }
        void Close()
        {
         if(Rd==NULL)return;
                Rd->Terminate();
                Rd->WaitFor();
                delete Rd;
                Rd=NULL;
        }
private:
 TCommReader *Rd;
        HANDLE &hComm;
};

#define Micro_DefDCB(v) /
        if(dcb.##v##==##v##)return; /
        TMyDCB tmpDcb=dcb;  /
        tmpDcb.##v##=##v##;   /
        SetDCB(tmpDcb);

//---------------------------------------------------------------------------
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::Open(const AnsiString &Port)
{
 if(Opened())
        {
         if(SameText(Port,FPort))
                {
                 return;
                }
                else
                {
                 Close();
                }
        }
        FPort=Port;
        hComm = CreateFile( FPort.c_str(),GENERIC_READ | GENERIC_WRITE,
                0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
        if (!Opened()) RaiseLastOSError();

        PurgeComm(hComm,PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR);

        ZeroMemory(&dcb,sizeof(dcb));
        if (!GetCommState(hComm, &dcb))
        {
         Close();
                RaiseLastOSError();
        }
        p_rd::Open();
        p_wt::Open();
}

template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::Close()
{
 if(Opened())
        {
         p_rd::Close();
                p_wt::Close();
         CloseHandle(hComm);
                hComm=INVALID_HANDLE_VALUE;
        }
}

template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetDCB(const DCB &_dcb)
{
 CheckOpened();
        DCB tmpDcb=_dcb;
        Win32Check(SetCommState(hComm, &tmpDcb));
        dcb=tmpDcb;
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetBaudRate(DWORD BaudRate)
{
 Micro_DefDCB(BaudRate)
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetParity(BYTE Parity)
{
        if(dcb.Parity==Parity)return;
        TMyDCB tmpDcb=dcb;
        tmpDcb.Parity=Parity;
        tmpDcb.fParity=Parity?1:0;
        SetDCB(tmpDcb);
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetByteSize(BYTE ByteSize)
{
 Micro_DefDCB(ByteSize)
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetStopBits(BYTE StopBits)
{
 Micro_DefDCB(StopBits)
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetTimeouts(const COMMTIMEOUTS& TimeOuts)
{
 CheckOpened();
        COMMTIMEOUTS _TimeOuts=TimeOuts;
        Win32Check(SetCommTimeouts(hComm,&_TimeOuts));
}
template<class p_rd,class p_wt>
void TMyComm<p_rd,p_wt>::SetTimeouts(
 DWORD RdItv,DWORD RdMult,DWORD RdConst,DWORD WrtMult,DWORD WrtConst)
{
        COMMTIMEOUTS _TimeOuts={RdItv,RdMult,RdConst,WrtMult,WrtConst};
        SetTimeouts(_TimeOuts);
}
template<class p_rd,class p_wt>
COMMTIMEOUTS TMyComm<p_rd,p_wt>::GetTimeouts()
{
 CheckOpened();
        COMMTIMEOUTS _TimeOuts={0,0,0,0,0};
        Win32Check(GetCommTimeouts(hComm,&_TimeOuts));
        return _TimeOuts;
}
#pragma option pop
#endif

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值