Raspberry Pi C ++从Adafruit的终极GPS模块中读取NMEA句子

时间:2013-08-11 18:39:41

标签: c++ c gps raspberry-pi nmea

我正在尝试阅读Adafruit的Ultimate GPS模块中的GPS NMEA句子。我在raspberry pi上使用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

为什么我会重复句子,我该如何解决?我试着刷新串口缓冲区,但事情变得非常丑陋!感谢。

2 个答案:

答案 0 :(得分:1)

我不确定我理解你的确切问题。该功能存在一些问题,但可以解释各种错误。

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

似乎错了。您将通过比较读取的字符数absoluteMax来决定何时增加缓冲区,因此需要匹配分配的缓冲区大小。在重新分配之前,您目前正在编写超出已分配内存的末尾。这导致未定义的行为。如果你很幸运,你的应用程序会崩溃,如果你运气不好,事情似乎会有效,但你会丢失你读过的数据的后半部分,因为只有写入你拥有的内存的数据才会被{ {1}}(如果它重新定位您的堆单元格)。

此外,您不应该从realloc(或malloc)转换回报,并且可以依赖realloc为1。

您丢失了第一个字符读取(在sizeof(char)循环之前读取的字符)。这是故意的吗?

重新分配while时,不应重置buffer。这会导致与上面相同的错误,在重新分配之前,您将在rcount的末尾之外写入。同样,这样做的效果是未定义的,但可能包括丢失部分输出。

与您目前关注的错误无关,但值得注意的是您泄漏bufferbuffer。在退出函数之前,您应该分别fdFfree

以下(未经测试的)版本应该解决这些问题

fclose

答案 1 :(得分:1)

也许您可以尝试刷新串口缓冲区,然后再显示它in this link

每次调用Linuxutils :: readFromSerialPort时,我也会考虑不重新打开串口 - 你可以保持文件描述符打开以便进一步阅读(无论如何调用都是阻塞的,所以从调用者的角度来看没有任何变化)。