screwyscrew
@screwyscrew

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Win32API の ReadFile でゼロが読めない

解決したいこと

Win32API でシリアル通信を実装してます。
でもなぜかゼロだけ読めない。なぜだろう困った。原因の特定をしたいです。

ゼロが読めないというのは、実装しているプログラム側をとりあえず受信側と呼ぶことにして、送信側で 0x01 を送るとちゃんと 0x01 が読めるのに対し、0x00 は反応がない or バッファに溜まらないという具合です。

発生している問題・エラー

例)

送信データ
33 00 10 20 44 55 00 66

受信データ
33 10 20 44 55 66

ゼロだけ送ってももちろんダメですし、間に挟んでも抜け落ちます。

該当するソースコード

int main()
{
    HANDLE comPort = CreateFile( L"\\\\.\\COM14",
                        GENERIC_READ | GENERIC_WRITE,
                        0, nullptr, OPEN_EXISTING, 0, nullptr );

    DCB dcb;
    GetCommState( comPort, &dcb );
    dcb.BaudRate    = 115200;
    dcb.ByteSize    = 8;
    dcb.Parity      = NOPARITY;
    dcb.StopBits    = ONESTOPBIT;
    dcb.fOutxCtsFlow= FALSE;
    SetCommState( comPort, &dcb );

    COMMTIMEOUTS to = { MAXDWORD, 0, 0, 0, 0, };
    SetCommTimeouts( comPort, &to );
    uint8_t buf[100];
    uint32_t count;

    while( 1 )
    {
        ReadFile( comPort, buf, 100, (LPDWORD)&count, nullptr );
        if( count )
        {
            int i = 0;
            while( count-- )
            {
                printf( "%02X ", buf[i++] );
            }
            printf( "\r\n" );
            const uint8_t sl[] = { 0x00,0x00,0x00 };
            WriteFile( comPort, sl, 3, nullptr, nullptr );
        }
        Sleep( 100 );
    }
}

自分で試したこと

WaitCommEvent などオーバーラップ動作が目的ではあるのですが、なぜゼロだけ読めないのかを調査する過程で上記のような最小限のコードでもダメということが判明しました。
そのくせ WriteFile はちゃんとゼロを送信できております。

シリアル通信は2個の USBシリアル機器を直結してます。
通信波形をオシロスコープで観察していますので 0x00 の波形も出ていることを確認しています。
送信側のソフトウェアは SerialDebugTool を使わせてもらってます。

0

2Answer

SerialDebugToolやオシロでの観察を疑うわけではありませんが、このコードから相手にWriteFileでゼロを送信できているのなら、まずは送信側からもご自身のコードでWriteFileしてみてはどうでしょうか?

1Like

Comments

  1. @screwyscrew

    Questioner

    回答ありがとうございます。

    そんなのやる意味ないだろーとか思いつつやってみたら、受信できました!
    どういうことだろうと考えて波形を比較してみたところ1バイトの長さが違う。
    設定を見返すと SerialDebugTool とはパリティの設定が異なっていました。
    合わせたはずなのになぜだろう...自分のミス以外無いですね。
    設定を直したら SerialDebugTool でもゼロ受信できました。

    これでクローズしても良いかもしれない、と思いつつも、最終目的となる外部デバイスの設定には問題が見つかっておらず、もう少し探して見つかったらクローズにしようと思います。

解決しました。
@itagagaki さんのご指摘でとにかく設定を疑って調べたところ、全然違う結論にたどり着きました。

DCB::fNullというフラグが true になっていた、というのが結論です。
このフラグの存在に気づかないままあれこれ調べていましたが参りました、何の役に立つのだろうこのフラグというか機能。
dcb.fNull = false という一行を加えるだけでサクッと解決です。

fNull
このメンバーが TRUE の場合、null バイトは受信時に破棄されます。

また問題をややこしくしていたのがGetCommStateですね。
たぶん取得できる初期値がいつも同じというわけではないのでしょう。同じなら↑のコードを対向させてもゼロ受信出来るはずもないので。
パリティの違いも原因の一つだったんでしょうが、これが結論ということでクローズします。

「説明書ちゃんと読め」ってやつですね:sob:

0Like

Your answer might help someone💌