2013-08-11 5 views
0

Я пытаюсь прочитать предложения GPS NMEA от Ultimate GPS-модуля Adafruit. Я использую C++ на малиновом пи читать соединение через последовательный порт к модулюRaspberry Pi C++ Чтение предложений NMEA от Ultimate GPS-модуля Adafruit

Вот моя функция чтения:

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 

Почему я получаю повторяющиеся предложения и как я могу это исправить? Я попытался промыть буферы последовательного порта, но потом все стало действительно уродливо! Благодарю.

ответ

1

Я не уверен, что понимаю вашу точную проблему. Есть несколько проблем с функцией, которые могут объяснить множество ошибок.

Линии

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

кажется неправильным. Вы решите, когда выращивать буфер, сравнивая количество символов, считанных с absoluteMax, поэтому это должно соответствовать размеру выделенного буфера. В настоящее время вы пишете за пределами выделенной памяти до перераспределения. Это приводит к неопределенному поведению. Если вам повезет, ваше приложение потерпит крах, если вам повезет, все будет работать, но вы потеряете вторую половину данных, которые вы читали, поскольку только данные, записанные в вашу память, будут перемещены на realloc (если он перемещает вашу кучную ячейку).

Кроме того, вы не должны отбрасывать возвращение из malloc (или realloc) и может полагаться на sizeof(char) быть 1.

Вы теряете первый прочитанный символ (тот, который читается как раз перед циклом while). Это преднамеренно?

При перераспределении buffer, вы не должны сбросить rcount. Это вызывает ту же ошибку, что и выше, где вы напишете до конца buffer перед повторным перераспределением. Опять же, последствия этого не определены, но могут включать потерю части вывода.

Не связано с ошибкой, с которой вы в настоящее время обеспокоены, но также стоит отметить, что вы протекаете buffer и fdF. Вы должны 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; 
} 
1

Может быть, вы могли бы попытаться потопить последовательные буфера порта, прежде чем читать из него, как показано in this link?

Я бы также подумал о том, чтобы не возобновлять последовательный порт каждый раз, когда вы вызываете Linuxutils :: readFromSerialPort - вы можете оставить дескриптор файла открытым для дальнейшего чтения (в любом случае вызов блокируется, поэтому с точки зрения вызывающего абонента ничего не меняется).

 Смежные вопросы

  • Нет связанных вопросов^_^