简体   繁体   中英

C++ Eclipse console encoding plain text as other characters

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;
}

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.

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 :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM