1

Adafruit の Ultimate GPS モジュールから GPS NMEA センテンスを読み取ろうとしています。モジュールへのシリアルポート接続を読み取るために、ラズベリーパイでC++を使用しています

ここに私の読み取り機能があります:

int Linuxutils::readFromSerialPort(int fd, int bufferSize) {

    /*
    Reading data from a port is a little trickier. When you operate the port in raw data mode,
    each read(2) system call will return however many characters are actually available in the
    serial input buffers. If no characters are available, the call will block (wait) until
    characters come in, an interval timer expires, or an error occurs. The read function can be
    made to return immediately by doing the following:
    fcntl(fd, F_SETFL, FNDELAY);
    The NDELAY option causes the read function to return 0 if no characters are available on the port.
    */

    // Check the file descriptor
    if ( !checkFileDecriptorIsValid(fd) ) {
        fprintf(stderr, "Could not read from serial port - it is not a valid file descriptor!\n");
        return -1;
    }

    // Now, let's wait for an input from the serial port.
    fcntl(fd, F_SETFL, 0); // block until data comes in

    // Now read the data
    int absoluteMax = bufferSize*2;
    char *buffer = (char*) malloc(sizeof(char) * bufferSize); // allocate buffer.
    int rcount = 0;
    int length = 0;

    // Read in each newline
    FILE* fdF = fdopen(fd, "r");
    int ch = getc(fdF);
    while ( (ch != '\n') ) { // Check for end of file or newline

        // Reached end of file
        if ( ch == EOF ) {
            printf("ERROR: EOF!");
            continue;
        }

        // Expand by reallocating if necessary
        if( rcount == absoluteMax ) { // time to expand ?
          absoluteMax *= 2; // expand to double the current size of anything similar.
          rcount = 0; // Re-init count
          buffer = (char*)realloc(buffer, absoluteMax); // Re-allocate memory.
        }

        // Read from stream
        ch = getc(fdF);

        // Stuff in buffer
        buffer[length] = ch;

        // Increment counters
        length++;
        rcount++;

    }

    // Don't care if we return 0 chars read
    if ( rcount == 0 ) {
        return 0;
    }

    // Stick
    buffer[rcount] = '\0';

    // Print results
    printf("Received ( %d bytes ): %s\n", rcount,buffer);

    // Return bytes read
    return rcount;

}

したがって、以下に示すような文を取得します。問題は、次のような完全な文のこれらの「繰り返される」部分を取得することです。

Received ( 15 bytes ): M,-31.4,M,,*61

完全なものは次のとおりです。

Received ( 72 bytes ): GPGGA,182452.000,4456.2019,N,09337.0243,W,1,8,1.19,292.6,M,-31.4,M,,*61

Received ( 56 bytes ): GPGSA,A,3,17,07,28,26,08,11,01,09,,,,,1.49,1.19,0.91*00

Received ( 15 bytes ): M,-31.4,M,,*61

Received ( 72 bytes ): GPGGA,182453.000,4456.2019,N,09337.0242,W,1,8,1.19,292.6,M,-31.4,M,,*61

Received ( 56 bytes ): GPGSA,A,3,17,07,28,26,08,11,01,09,,,,,1.49,1.19,0.91*00

Received ( 15 bytes ): M,-31.4,M,,*61

Received ( 72 bytes ): GPGGA,182456.000,4456.2022,N,09337.0241,W,1,8,1.21,292.6,M,-31.4,M,,*64

Received ( 56 bytes ): GPGSA,A,3,17,07,28,26,08,11,01,09,,,,,2.45,1.21,2.13*0C

Received ( 70 bytes ): GPRMC,182456.000,A,4456.2022,N,09337.0241,W,0.40,183.74,110813,,,A*7F

Received ( 37 bytes ): GPVTG,183.74,T,,M,0.40,N,0.73,K,A*34

Received ( 70 bytes ): GPRMC,182453.000,A,4456.2019,N,09337.0242,W,0.29,183.74,110813,,,A*7E

Received ( 37 bytes ): GPVTG,183.74,T,,M,0.29,N,0.55,K,A*3F

Received ( 32 bytes ): 242,W,0.29,183.74,110813,,,A*7E

Received ( 70 bytes ): GPRMC,182452.000,A,4456.2019,N,09337.0243,W,0.33,183.74,110813,,,A*75

文が繰り返されるのはなぜですか?どうすれば修正できますか? シリアル ポート バッファをフラッシュしようとしましたが、状況が非常に悪くなりました。ありがとう。

4

2 に答える 2

1

あなたの正確な問題を理解しているかどうかわかりません。関数にはいくつかの問題がありますが、さまざまなエラーを説明する可能性があります。

台詞

int absoluteMax = bufferSize*2;
char *buffer = (char*) malloc(sizeof(char) * bufferSize); // allocate buffer.

間違っているようです。読み取った文字数を比較してバッファを拡張するタイミングを決定するabsoluteMaxため、これは割り当てられたバッファのサイズと一致する必要があります。現在、再割り当てする前に、割り当てられたメモリの終わりを超えて書き込みを行っています。これにより、未定義の動作が発生します。運が良ければアプリがクラッシュします。運が悪ければ、動作しているように見えますが、所有しているメモリに書き込まれたデータのみが移動されるため、読み取ったデータの後半が失われますrealloc(ヒープセルを再配置する場合)。

mallocまた、 (または)からのリターンをキャストするべきではなく、 1reallocであることを信頼できsizeof(char)ます。

while読み取られた最初の文字 (ループの直前に読み取られた文字) が失われます。これは意図的なものですか?

を再割り当てするときbufferは、リセットしないでくださいrcount。これにより、上記と同じバグが発生し、buffer再度再割り当てする前に の末尾を超えて書き込みます。繰り返しますが、これを行った場合の影響は未定義ですが、出力の一部が失われる可能性があります。

現在懸念しているバグとは関係ありませんが、注目に値するのは、リークbufferfdF. 関数を終了する前に、それぞれを実行する必要がfreeありfcloseます。

次の(テストされていない)バージョンは、これらの問題を修正する必要があります

int Linuxutils::readFromSerialPort(int fd, int bufferSize)
{
    if ( !checkFileDecriptorIsValid(fd) ) {
        fprintf(stderr, "Could not read from serial port - it is not a valid file descriptor!\n");
        return -1;
    }

    fcntl(fd, F_SETFL, 0); // block until data comes in
    int absoluteMax = bufferSize;
    char *buffer = malloc(bufferSize);
    int rcount = 0;
    int length = 0;

    // Read in each newline
    FILE* fdF = fdopen(fd, "r");
    int ch = getc(fdF);
    for (;;) {
        int ch = getc(fdF);
        if (ch == '\n') {
            break;
        }
        if (ch == EOF) { // Reached end of file
            printf("ERROR: EOF!\n");
            break;
        }
        if (length+1 >= absoluteMax) {
            absoluteMax *= 2;
            char* tmp = realloc(buffer, absoluteMax);
            if (tmp == NULL) {
                printf("ERROR: OOM\n");
                goto cleanup;
            }
            buffer = tmp;
        }
        buffer[length++] = ch;
    }

    if (length == 0) {
        return 0;
    }
    buffer[length] = '\0';

    // Print results
    printf("Received ( %d bytes ): %s\n", rcount,buffer);

cleanup:
    free(buffer);
    fclose(fdH);
    return length;
}
于 2013-08-11T18:54:29.170 に答える
1

このリンクに示されているように、シリアルポートバッファから読み取る前に、シリアルポートバッファをフラッシュすることを試みることができますか?

また、Linuxutils::readFromSerialPort を呼び出すたびにシリアル ポートを再度開かないようにすることも検討します。さらに読み取るためにファイル記述子を開いたままにしておくこともできます (とにかく呼び出しがブロックされているため、呼び出し元の観点からは何も変わりません)。

于 2013-08-11T19:27:08.993 に答える