2017-01-25 14 views
0

私はビーグルボーンブラックのシリアルポート(/dev/ttyS4)から読み取ろうとしていますが、これは一般的にすべてのLinuxデバイスに当てはまると思います(?)。Linuxシリアル読み取りブロックminicom

現在、私はminicomをボーレート9600と8N1データに設定して、シリアルポートから正しく読み取ることができます。しかし、私が直接cat /dev/ttyS4を試みると、何も私の端末に表示されません。私のコードでもこれを行い、Resource temporarily unavailableエラーを返します。これはcatコマンドで起こっていると思われます。

私はstty -F /dev/ttyS4を実行した場合、私は(私の知る限り、私のminicomの設定と一致している、)次のような出力が得られます。

speed 9600 baud; line = 0; 
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>; werase = <undef>; lnext = <undef>; flush = <undef>; 
-brkint -imaxbel 
-opost -onclr 
-isig -iexten -echo -echoe -echok -echoctl -echoke 

興味深いノートでは、私はminicomオープンを持っている場合ということです私がプログラムを始めると、ミニコムは何も印刷をやめ、プログラムを止めてもそのままにしておきます。シリアル設定を再度開いて(Ctrl-AP)、それを閉じてminicomを再開して作業を再開する必要があります(変更されていないようです)。次のように

私のコードは次のとおりです。

int main() { 
    std::cout << "Starting..." << std::endl; 

    std::cout << "Connecting..." << std::endl; 
    int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY); 
    if (tty4 < 0) { 
     std::cout << "Error opening serial terminal." << std::endl; 
    } 

    std::cout << "Configuring..." << std::endl; 
    struct termios oldtio, newtio; 
    tcgetattr(tty4, &oldtio); // save current serial port settings 
    bzero(&newtio, sizeof(newtio)); // clear struct for new settings 

    newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL; 
    newtio.c_iflag = IGNPAR | ICRNL; 
    newtio.c_oflag = 0; 
    newtio.c_lflag = ICANON; 

    tcflush(tty4, TCIFLUSH); 
    tcsetattr(tty4, TCSANOW, &newtio); 

    std::cout << "Reading..." << std::endl; 
    while (true) { 
     uint8_t byte; 
     int status = read(tty4, &byte, 1); 
     if (status > 0) { 
      std::cout << (char)byte; 
     } else if (status == -1) { 
      std::cout << "\tERROR: " << strerror(errno) << std::endl; 
     } 
    } 

    tcsetattr(tty4, TCSANOW, &oldtio); 
    close(tty4); 
} 

編集:私はBeagleBoneでのpythonを使用するためのAdafruitのチュートリアルに従うことによって(Pythonで)正しく動作するシリアルポートを得ています。この時点で私は確信しています私は何か間違っています。問題は何ですか?私はPythonよりもC++を使う方が好きなので、それを働かすことは素晴らしいことです。

+0

いくつかの問題が考えられますが、何が問題なのですか? – sawdust

+0

シリアルポートから正常に読み込むためにC++プログラムをどのように変更すればよいですか? –

答えて

1

プログラムは、非ブロックモードでシリアル端末を開きます。

int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY); 

ノンブロッキングI/O、特に操作を読んで、プログラム内の追加、特殊な処理が必要となります。 このモードについて言及しておらず、あなたのプログラムはこのモードを正しく処理する能力がないので、これはバグとみなされる可能性があります。

どちらかオープン()呼び出しからO_NDELAYオプションを削除、またはブロックモードに戻すfcntl(tty4, F_SETFL, 0)文を挿入します。


マイコードもこれを行い、そしてノンブロッキングリード()と一致するEAGAIN誤差だResource temporarily unavailable誤差、

を返します。
このエラーについてのマニュアルページは、「ファイル記述子...が非ブロック(O_NONBLOCK)とマークされており、読み込みがブロックされた」ときに発生します。
read()読み取り要求を満たすデータがないため、syscallが「ブロックする」と表示されます。

ノンブロッキングモードを使用することを強くお勧めする場合、プログラムはこの状態に対処できなければなりません。これはエラーではなく一時的/一時的な状態です。
しかし、ブロッキングモードは、マルチタスキングシステムの一般的なプログラムでは、より簡単で好ましい動作モードです。
プログラムは前述のように変更する必要があります。


シリアル端末の初期化には多くの問題があります。


tcgetattr(tty4, &oldtio); // save current serial port settings 

のtcgetattr()のtcsetattrからの戻り値()システムコールはエラーがチェックされることはありません。


bzero(&newtio, sizeof(newtio)); // clear struct for new settings 

空のtermios構造体を皮切りほとんど常に悪い考えです。いくつかのシステムでは動作するように見えるかもしれませんが、移植可能なコードではありません。
termios構造体を初期化する適切な方法は、tcgetattr()の値を使用することです。
Setting Terminal Modes Properlyを参照してください。
既に呼び出されているので、構造をコピーするにはnewtio = oldtioが必要です。むしろ定数の割り当てより


newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL; 
    newtio.c_iflag = IGNPAR | ICRNL; 
    newtio.c_oflag = 0; 
    newtio.c_lflag = ICANON; 

、これらのフラグを変更する適切な方法は、個々の属性を有効または無効にすることです。
次は、標準的なモードで十分です:

newtio.c_cflag |= CLOCAL | CREAD; 
    newtio.c_cflag &= ~CSIZE; 
    newtio.c_cflag |= CS8;   /* 8-bit characters */ 
    newtio.c_cflag &= ~PARENB;  /* no parity bit */ 
    newtio.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
    newtio.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 

    newtio.c_lflag |= ICANON | ISIG; /* canonical input */ 
    newtio.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

    newtio.c_iflag &= ~INPCK; 
    newtio.c_iflag |= ICRNL; 
    newtio.c_iflag &= ~(INLCR | IGNCR | IUCLC | IMAXBEL); 
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */ 

    newtio.c_oflag &= ~OPOST; 

次のボーレートを設定するための好ましい方法である:任意の顕著な属性が指定されていない残っている場合は、既存の設定は、

cfsetospeed(&newtio, B9600); 
    cfsetispeed(&newtio, B9600); 

中古。
これは、プログラムの動作が異常になる可能性があります。時にはうまくいく、時にはうまくいかない。


興味深いメモがあること、私はオープンminicomのを持っているとき、私は私のプログラムを起動する場合は、minicomの何も印刷を停止し、私は私のプログラムを停止しても、そのように滞在します。シリアル設定をもう一度開いて(Ctrl-A、P)、minicomを閉じて作業を再開する必要があります(何も変更されていないようです)。

シリアル端末は、複数のプロセス間で共有することを目的としていません。
いくつかのtermios属性はシリアルデバイスドライバに実装する必要がありますが、これにはポートを共有するという概念はありません。最新のtermios属性は、デバイスに有効です。
ミニコムが起動した後にプログラムを実行すると、ミニコムが実行されると予想されるtermios属性が壊れてしまいます。
メニューを使用して、termios属性をminicomの要件に戻しています。

+0

ありがとう!これは私の最初の試みであり、私はちょっと頭がおかしくなってしまったと思います。あなたの答えは本当に役に立ちます:) –

関連する問題