Top > WINDOWS >非同期シリアル通信クラス

非同期シリアル通信クラス

 マイコンで比較的簡単にパソコンと通信する方法として、 シリアル通信があります。TeraTermとかハイパーターミナルを使えば、 簡単にデバッグすることができます。 とはいえ、バイナリデータをやりとりしたり、 本格的に通信を利用するアプリケーションを作るとなると、 プログラムを自作する必要があります。

TurboC++には、スレッドを簡単に扱うためのTThreadというコンポーネントが用意されています。 今回は、TThreadを継承して非同期のシリアル通信クラスを作成します。 けっこう適当にできているのでバグがあるかもしれないです。 以下にソースを置いておきます。

クラス定義

まずは、シリアル通信クラスの構造を示します。 バッファにはSTLのvectorを使いました。非同期書き込み中のバッファを操作するのは、 非常にアレなのでダブルバッファにしました。また、今回はRTSやDTSといった信号の制御や、 CTS変化などのイベントも受信できるようにしています。

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

#ifndef CommPortH
#define CommPortH
//---------------------------------------------------------------------------

#include <Classes.hpp>
#include <vector.h>
//---------------------------------------------------------------------------
//
//  シリアルポート非同期通信クラス
//
//---------------------------------------------------------------------------
#define WAIT_COMM		WAIT_OBJECT_0
#define WAIT_ESC		(WAIT_OBJECT_0+1)

const int COMM_EVENT = 0;
const int ESC_FUNC = 1;

typedef void __fastcall (__closure *TRecvEvent)(char *RxData, int size);
typedef void __fastcall (__closure *TErrorEvent)(DWORD fEvent);

class TCommPort : public TThread
{
private:

    //イベントオブジェクト
    HANDLE      hEventObjects[2];
    OVERLAPPED  fOverLapped;
    OVERLAPPED  fReadDummy;
    OVERLAPPED  fWriteDummy;
    DWORD       fEventMask;
    DWORD       fEvent;

    //通信ポート
    HANDLE      hCom;
    DCB         comDcb;
    COMSTAT     comStat;
    DWORD       comError;

    //通信バッファ
    vector<char>    RxBuff;
    vector<char>    TxBuff;
    vector<char>    TxData;


    //プロパティ
    int             FEnabled;
    int             FChPort;
    DWORD           FEscFunc;
    DWORD           FBaudRate;
    TRecvEvent      FOnRecvEvent;
    TErrorEvent     FOnErrorEvent;


    //内部メソッド
    void __fastcall comm_event();
    void __fastcall esc_func();

    void create_dcb();

protected:

    void __fastcall Execute();

public:

    //コンストラクタとデストラクタ
    __fastcall TCommPort(bool CreateSuspended=false);
    virtual __fastcall ~TCommPort();


    //オープンクローズ
    bool Open();
    void Close();
    void EscapeFunction(DWORD dwFunc);
    void SetEventMask(DWORD mask);
    void ResetEventMask(DWORD mask);


    //送信メソッド
    void write(const char* data, int size);
    void write(const char* buff);


    //プロパティ
    __property int Enabled
        = { read=FEnabled };
    __property int ChPort
        = { read=FChPort, write=writeChPort };
    __property DWORD BaudRate
        = { read=FBaudRate, write=writeBaudRate };
    __property TRecvEvent OnRecvEvent
        = { read=FOnRecvEvent, write=FOnRecvEvent };
    __property TErrorEvent OnErrorEvent
        = { read=FOnErrorEvent, write=FOnErrorEvent };

private:

    //プロパティ用アクセスメソッド
    void writeChPort(int port);
    void writeBaudRate(DWORD baud);

};
//---------------------------------------------------------------------------
#endif

各種制御メソッド

各種プロパティ

プロパティというのはBorland固有の言語拡張です。 通常C++であればメンバ変数に対するアクセスを制御する場合、 アクセスメソッドなどを用意して、その関数を介して変数にアクセスしますが、 プロパティを使えば、変数のように振舞いながらアクセスメソッドを介することができます。 たとえば、
    __property int ChPort
        = { read=FChPort, write=writeChPort };
のように宣言すれば、以下のようにChPortに代入したときに、 writeChPort(1)が呼び出されるというものです。
	TCommPort comm;
	comm.ChPort = 1;	//ここでwriteChPort(1);が呼び出される。