web-dev-qa-db-ja.com

C ++でシリアルデバイスから読み取る方法

Linux C++でシリアル通信を使用してArduinoに対してどのように読み取り/書き込みを行うべきかを理解しようとしています。現在、「トリガー」するArudinoからの応答を読み取ろうとしています。

echo "g" > /dev/ttyACM0"

次のコマンドを使用して、ターミナルでArduinoからの応答を確認してみました。

tail -f /dev/ttyACM0

これは正常に機能しています。今、私はC++アプリケーションで同じことをしたいと思います。だから私はこのテストをしました

void testSerialComm()
{

    std::string port = "/dev/ttyACM0";
    int device = open(port.c_str(), O_RDWR | O_NOCTTY | O_SYNC);

    std::string response;
    char buffer[64];

    do
    {
        int n = read(device, buffer, sizeof buffer);

        if (n > 0) {
            response += std::string(buffer);
            std::cout << buffer;
        }

    } while (buffer[0] != 'X'); // 'X' means end of transmission

    std::cout << "Response is: " << std::endl;
    std::cout << response << std::endl;

    close(device);

}

いくつかの「メッセージ」の後、送信は少し混乱します。私のテストアプリケーションはランダムな順序で応答文字を書き込みますが、何かが正しくありません。次のコマンドで/ dev/ttyACM0デバイスを構成してみました。

stty -F /dev/ttyUSB0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

サイコロはありません。誰かがC++でArduinoと通信する方法を理解するのを手伝ってもらえますか?

6
gromit190

示されているコードは_/dev/ttyACM0_を開き、この「ファイル」の最後までシークしようとし、結果のファイル位置に基づいて、昔ながらのCスタイルのメモリバッファーを割り当てます。

このアプローチの問題は、通常のプレーンな園芸品種のファイルしか検索できないことです。 _/dev/ttyACM0_は通常のファイルではありません。それはデバイスです。一部のデバイスはシーク可能ですが、これはシークできません。コメントによると、これはあなたが独自に発見したものです。

シリアルポートデバイスは読み取りと書き込みが可能です。それらは求めることができません。シリアルポートを「探す」ようなことはありません。それは意味がありません。

シリアルポートから読み取るには、それを読み取るだけです。それだけです。オペレーティングシステムはある程度のサイズの内部バッファを維持しているため、シリアルポートですでに一部の文字を受信して​​いる場合、最初の読み取りでそれらすべてが返されます(read()バッファサイズが十分に大きい場合)。たとえば、1024文字のバッファを渡し、シリアルポートからすでに5文字が読み取られている場合、read()は5を返し、それに応じてそれを示します。

文字が読み取られておらず、ブロックデバイスとしてシリアルポートを開いた場合、read()は、シリアルポートから1文字が読み取られるまで少なくともブロックし、その後戻ります。

したがって、シリアルポートから読み取るために必要なのは、シリアルポートから読み取ることだけです。これは、シリアルポートから読み取る必要があるすべてを読み取ったと判断するまで続きます。どうやってそれを決めるのですか?それはあなた次第です。改行文字を読むまでだけ読みたいと思うかもしれません。または、固定の_#n_文字数が読み取られるまで読み取りのみを行うこともできます。それは完全にあなた次第です。

そしてもちろん、ハードウェアが適切に配置されていて、シリアルポート制御ピンを尊重するようにシリアルポートデバイスと必要な調整を行った場合、構成に応じて、DCDおよび/またはDSRピンに信号が送信されて次のことが示されます。シリアルポートデバイスが使用できなくなった場合、read()はすぐに0を返し、シリアルポートデバイスのファイル状態の疑似終了を示します。これは、処理に必要なロジックを実装するために必要なものでもあります。

P.S. CスタイルのstdioもC++スタイルのiostreamsも、独自の内部バッファリングアルゴリズムがあるため、文字デバイスではうまく機能しません。シリアルポートを使用する場合は、open(2)read(2)write(2)、およびclose(2)を使用することをお勧めします。ただし、上記のすべてが引き続き適用されます。

11
Sam Varshavchik