parsing complete messages from serial port

前端 未结 2 1353
有刺的猬
有刺的猬 2020-12-01 22:36

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

S

相关标签:
2条回答
  • 2020-12-01 23:28

    You can break the read into three parts. Find the start of a message. Then get the LENGTH. Then read the rest of the message.

    // Should probably clear these in case data left over from a previous read
    input_buffer[0] = input_buffer[1] = 0;
    
    // First make sure first char is 0xB5
    do {
        n = read(fd, input_buffer, 1); 
    } while (0xB5 != input_buffer[0]);
    
    // Check for 2nd sync char
    n = read(fd, &input_buffer[1], 1);
    
    if (input_buffer[1] != 0x62) {
         // Error
         return;
    }
    
    // Read up to LENGTH
    n = read(fd, &input_buffer[2], 4); 
    
    // Parse length
    //int length = *((int *)&input_buffer[4]);
    // Since I don't know what size an int is on your system, this way is better
    int length = input_buffer[4] | (input_buffer[5] << 8);
    
    // Read rest of message
    n = read(fd, &input_buffer[6], length);
    
    // input_buffer should now have a complete message
    

    You should add error checking...

    0 讨论(0)
  • 2020-12-01 23:33

    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) {
            ... 
    ...
    
    0 讨论(0)
提交回复
热议问题