シリアルポート(COMポート)の操作方法
  その4 タイムアウトの巻




ようやく試験も完了しましたので、シリアルポートをWin9x系のOSから操作する方法を 紹介できます。
ちょっと、怪しいコーディングなので正常な動作をする保証はありませんが現在のところは 異常な動きは見せていません。
NT版ソースとのおおきな違いは、通信ポートに対してタイムアウトの設定を行っていること です。この処理により、ライト完了待ちになって処理を全く受け付けなくなるのを防止できる のです。まさに、タイムアウト万歳です。
それと、読み込み処理と書き込み処理の非同期処理がなくなるので処理が簡単になります。
こっちの方がいいじゃんと思ってNTで動かしたらんNTでは動作しなくて困ってしまいました。
なにせ、今回のプロジェクトのターゲットマシンはNTだが、実際は9x系を使う方が多いはず なので。
では処理の方を見ていきます。

1.タイムアウトを設定する (サンプル)
    //-----------------------------------------------------------------------------
    /// READ・WRITE復帰タイムアウト設定処理
    //-----------------------------------------------------------------------------
    COMMTIMEOUTS    TimeOuts;    // 通信タイムアウト構造体
    // OSがWin9x系の時だけ設定します
    if( E_OSVersion == D_OS_WIN9X )
    {
//      TimeOuts.ReadIntervalTimeout = MAXWORD;         // ReadTotalTimeoutMultiplierとReadTotalTimeoutConstantが0でMAXWARDならreadfileが即時リターンする
        TimeOuts.ReadTotalTimeoutMultiplier = 10000;    // 1Byte毎のタイマ
        TimeOuts.ReadTotalTimeoutConstant = 1000;       // 1関数コール毎のタイマ
        TimeOuts.WriteTotalTimeoutMultiplier = 1;       // 1Byte毎のタイマ
        TimeOuts.WriteTotalTimeoutConstant = 1;         // 1関数コール毎のタイマ

        // タイムアウト設定
        SetCommTimeouts( E_ComPort, &TimeOuts );
    }
ポートのオープン処理は「その5」で紹介した通りなので、そちらを参考にして下さい。
サンプルはオープンが完了した後の処理です。
タイムアウト構造体の各項目をセットします。
ReadIntervalTimeoutはReadTotalTimeoutMultiplierとReadTotalTimeoutMultiplierが0の時にMAXWORDを 設定すると、ReadFile()関数が即時にリターンされます。まあ、使うことは無いと思います。
ReadTotalTimeoutMultiplierは1バイトあたり読み込むのに何ミリ秒待つかを指定します。
ReadTotalTimeoutConstantはReadFile()関数がコールされた時に何ミリ秒待つかを指定します。
読み込みタイムアウト秒数=(ReadTotalTimeoutMultiplier*読み込みバイト数)+ReadTotalTimeoutConstantと なります。
WriteTotalTimeoutMultiplierは1バイトあたり書き込むのに何ミリ秒待つかを指定します。
WriteTotalTimeoutConstantはWriteFIle()関数がコールされた時に何ミリ秒待つかを指定します。
書き込みタイムアウト秒数=(WriteTotalTimeoutMultiplier*書き込みバイト数)+WriteTotalTimeoutConstantと なります。
SetCommTimeouts()関数でポートにタイムアウト秒数を設定します。第一引数はポートを指定して下さい。


2.読み込み処理
(サンプル)
UINT SimReadThread_9x( 
        LPVOID pParam                       // [IN]  未使用
        )
{
    BOOL        Bool_Ret;                   // 関数戻り値
    static char	ReadBuff[10];               // 読み込みバッファ
    unsigned long    ReadSize;              // 読み込み完了サイズ
    BOOL        Loop_End = FALSE;           // 処理終了状態


    //-----------------------------------------------------------------------------
    /// 端末からの電文受信処理
    //-----------------------------------------------------------------------------

    // 電文受信待ちループ
    while( !Loop_End )
    {
        // 読み込みバッファ初期化
        memset( ReadBuff,NULL,sizeof(ReadBuff) );
        // 1バイトずつ読み込み
        Bool_Ret = ReadFile( E_ComPort, ReadBuff, 1, &ReadSize, NULL );
        // 読み込み結果チェック
        if( Bool_Ret == FALSE || ReadSize == 0 )
        {
            // エラーメッセージ表示
            SimErrMsg( "%s[%d] 受信失敗(%d)",
                       0, __file__, __line__, GetLastError() );

            // ループ終了フラグON
            Loop_End = TRUE;
            break;
        }
        else
        {
            // 読み込みOK
            // バッファリング処理
            Bool_Ret = SimReadSuccess( (char)ReadBuff[0] );

            // バッファリング処理失敗
            if( Bool_Ret != TRUE )
            {
                // エラーメッセージ表示
                SimErrMsg( "%s[%d] バッファリング処理失敗(%d)",
                0, __file__, __line__, GetLastError() );
            }
        }
    }

    // スレッド終了
    return(0);
}
読み込み処理そのものは普通の処理です。ただし、オープンするときに非同期モードで オープンしており、非同期でオープンした場合はReadFile()関数の最後に非同期用の 構造体を指定しないと、動作が保証できないといった警告がマニュアルには記述されて います。
まあ、マニュアル通りではないが、これで動きます。で、読み込みタイムアウトが発生 すると、関数は正常でリターンします。エラーにはならないので注意して下さい。
読み込みが完了したのかタイムアウトかの判断は読み込み完了バイト数で行っています。


3.書き込み処理
読み込み処理と同じなので省略。
WriteFile()関数を使用して下さい。




N総研ソフトウェア開発部のTOPに戻る。

このページに関するご意見・質問は
ドンタコスN村 E-mail:wnaka@coco.ned.co.jp
まで送信してください。