Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
510 views
in Technique[技术] by (71.8m points)

c++ - parsing complete messages from serial port

I am trying to read complete messages from my GPS via serial port.

The message I am looking for starts with:

0xB5 0x62 0x02 0x13

So I read from the serial port like so

while (running !=0)
{

int n = read (fd, input_buffer, sizeof input_buffer); 


for (int i=0; i<BUFFER_SIZE; i++)
{   



if (input_buffer[i]==0xB5  && input_buffer[i+1]== 0x62 && input_buffer[i+2]== 0x02 && input_buffer[i+3]== 0x13    && i<(BUFFER_SIZE-1) )
     { 

            // process the message.
     }

}

The problem I am having is that I need to get a complete message. Half of a message could be in the buffer one iteration. And the other half could come into the message the next iteration.

Somebody suggested that free the buffer up from the complete message. And then I move the rest of data in the buffer to the beginning of the buffer.

How do I do that or any other way that make sure I get every complete selected message that comes in?

edit// enter image description here

I want a particular class and ID. But I can also read in the length

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To minimize the overhead of making many read() syscalls of small byte counts, use an intermediate buffer in your code.
The read()s should be in blocking mode to avoid a return code of zero bytes.

#define BLEN    1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;

static unsigned char getbyte(void)
{
    if ((rp - rbuf) >= bufcnt) {
        /* buffer needs refill */
        bufcnt = read(fd, rbuf, BLEN);
        if (bufcnt <= 0) {
            /* report error, then abort */
        }
        rp = rbuf;
    }
    return *rp++;
}

For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value.

Now you can conveniently access the received data a byte at a time with minimal performance penalty.

#define MLEN    1024  /* choose appropriate value for message protocol */
unsigned char mesg[MLEN];

while (1) {
    while (getbyte() != 0xB5)
        /* hunt for 1st sync */ ;
retry_sync:
    if ((sync = getbyte()) != 0x62) {
        if (sync == 0xB5)
            goto retry_sync;
        else    
            continue;    /* restart sync hunt */
    }

    class = getbyte();
    id = getbyte();

    length = getbyte();
    length += getbyte() << 8;

    if (length > MLEN) {
        /* report error, then restart sync hunt */
        continue;
    }
    for (i = 0; i < length; i++) {
        mesg[i] = getbyte();
        /* accumulate checksum */
    }

    chka = getbyte();
    chkb = getbyte();
    if ( /* valid checksum */ ) 
        break;    /* verified message */

    /* report error, and restart sync hunt */
}

/* process the message */
switch (class) {
case 0x02:
    if (id == 0x13) {
        ... 
...

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...