0

I have a C++ program running on an Intel Edison reading some GPS data from a serial port and echoing it back to the console.

That part is working fine, but when the strings are read in the console they have characters that shouldn't be there, like "¬é­". I'm guessing that something is messed up with encoding in the Eclipse console/G++, and it thinks some of the readings are character codes.

Here is some output from the Eclipse Console:

$GPVTG,,T,,M,0.041,N,0.075,K,A*24
$GPGGA,225153.00,5206.75433,N,12206.88881,W,1,10,1.03,582.1,M,-15.6,M,,*6F
$GPGSA,A,3,32,02,12,14,24,06,03,19,17,25,,,1.84,1.03,1.53*05
$GPGSV,3,1,11,¬é­N
-> 02,51,176,30,03,10,027,17,06,60,088,33,12,68,295,36*79
$GPGSV,3,2,11,14,10,316,30,17,20,072,27,19,45,069,40,24,36,215,35*7E
$GPGSV,3,3,11,25,29,301,28,29,05,254,,32,07,305,33*40
$GPGLL,5206.75433,N,12206.88881,W,225153.00,A,A*78
.53*05
$GPGSV,3,1,11,¬é­N

And here is some of the output as read directly from the serial port on the Edison (cat /dev/ttyMFD1):

$GPVTG,,T,,M,0.048,N,0.090,K,A*26
$GPGGA,225407.00,5206.75339,N,12206.88816,W,1,10,1.02,584.2,M,-15.6,M,,*6C
$GPGSA,A,3,32,02,12,14,24,06,03,19,17,25,,,1.80,1.02,1.49*0B
$GPGSV,3,1,11,02,52,176,15,03,10,026,20,06,59,086,29,12,69,295,41*76
$GPGSV,3,2,11,14,09,316,29,17,19,072,29,19,44,070,34,24,35,215,32*74
$GPGSV,3,3,11,25,30,301,29,29,06,254,,32,06,304,17*4C
$GPGLL,5206.75339,N,12206.88816,W,225407.00,A,A*7F
$GPRMC,225408.00,A,5206.75337,N,12206.88814,W,0.058,,170616,,,A*6F

I tried all the encoding options available in the run configurations common tab, but they all produced stranger results, even Chinese characters!

The relevant code is char array[255]; to initialize the buffer, and then this to read the serial data into the buffer and output it into the console:

while(true){
    dev->read(array,255);
    std::cout<<"-> "<<array<<std::endl;
}
0andriy
  • 4,183
  • 1
  • 24
  • 37
Keith M
  • 1,199
  • 2
  • 18
  • 38
  • I don't think this is eclipse. Looks like you're reading or printing some crap after an unterminated string. The tokens all line up. `$GPGSV,3,1,11,¬é­N02,51,176,30,03,10,027,17,06,60,088,33,12,68,295,36*79` looks like it should be `$GPGSV,3,1,11,02,51,176,30,03,10,027,17,06,60,088,33,12,68,295,36*79` and the checksum matches. – user4581301 Jun 17 '16 at 23:35
  • @user4581301 I think your right, it looks like I may have found the issue now, just doing some more testing to be sure – Keith M Jun 17 '16 at 23:46

2 Answers2

1

Given this block:

-> 02,51,176,30,03,10,027,17,06,60,088,33,12,68,295,36*79
$GPGSV,3,2,11,14,10,316,30,17,20,072,27,19,45,069,40,24,36,215,35*7E
$GPGSV,3,3,11,25,29,301,28,29,05,254,,32,07,305,33*40
$GPGLL,5206.75433,N,12206.88881,W,225153.00,A,A*78
.53*05
$GPGSV,3,1,11,¬é­N

adding rn to represent the two characters of the CRLF that terminates a line of NMEA data that, and then just counting the number of characters between the garbage I get

  0123456789ABCDEF
0 02,51,176,30,03,
1 10,027,17,06,60,
2 088,33,12,68,295
3 ,36*79rn$GPGSV,3
4 ,2,11,14,10,316,
5 30,17,20,072,27,
6 19,45,069,40,24,
7 36,215,35*7Ern$G
8 PGSV,3,3,11,25,2
9 9,301,28,29,05,2
A 54,,32,07,305,33
B *40rn$GPGLL,5206
C .75433,N,12206.8
D 8881,W,225153.00
E ,A,A*78rn.53*05r
F n$GPGSV,3,1,11,

255 characters

Exactly one of these:

dev->read(array,255);

Cheap hack is to

char array[256];

and then

dev->read(array,sizeof(array)-1);
array[sizeof(array)-1] = '\0';

But I think you are better off with something like this:

int len = receiveUntil(array,sizeof(array), "\r\n")
if (len >= 0)
{
    // checksum and parse
}
discardUntil ("$");

where

receiveUntil reads the incoming stream into array until it finds the end of the NMEA sentence then null terminates array and returns the number of bytes read or array is about to overflow, in which case it returns -1.

discardUntil throws away everything until it finds the NMEA start character '$'

Bonus points for replacing receiveUntil with a function that resets array when it finds a $ so you don't miss any messages that weren't already corrupt.

user4581301
  • 33,082
  • 7
  • 33
  • 54
0

Turns out it wasn't an issue with encoding. I started to realize it was something else when I tried to do the same thing with NodeJS, and got the same output back.

I forgot that the correct way to read the output from this GPS module is to read the characters one at a time until you hit the newline terminator at the end of the line, and then work with it/log it to console.

So my code then became:

char array[255];
char c[1];
int i = 0;

while(true){
     dev->read(c,1);

     if(c[0] == '\n'){
         i = 0;

         std::cout<<"-> "<<array<<std::endl;

         char *begin = array;
         char *end = begin + sizeof(array);
         std::fill(begin, end, 0);
     }else{
         array[i] = c[0];
         ++i;
     }
}

Which now works perfectly :)

Keith M
  • 1,199
  • 2
  • 18
  • 38
  • 1
    Recommendation: `char c;` rather than an array of 1, and then `dev->read(&c,sizeof(c));` `sizeof(c)` is me being a bit pedantic, but allows extending to wide characters. Not an issue with any NMEA format I'm familiar with. – user4581301 Jun 18 '16 at 00:12