Raspberry Pi C ++ Считайте предложения NMEA от окончательного модуля GPS Adafruit

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

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

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

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

0

Решение

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

Линии

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

Другие решения

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

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

1

По вопросам рекламы [email protected]