2017-04-07 51 views
1

我想通過串行端口從我的GPS讀取完整消息。解析來自串行端口的完整消息

我與尋找啓動的消息:

0xB5 0x62 0x02 0x13 

所以我從串口讀取,像這樣

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

} 

我遇到的問題是,我需要得到一個完整的消息。一半的消息可能在緩衝區中一次迭代。另一半可能在下一次迭代中進入消息。

有人建議將緩衝區從完整的消息中釋放出來。然後我將緩衝區中的其餘數據移動到緩衝區的開始位置。

我該怎麼做,或者其他方式,以確保我得到每一個完整的選定信息?

編輯// enter image description here

我想一個特定的類和ID。但我也可以讀長度爲

+0

您可以在一個循環中一次讀取1個字節,直到您有完整的消息。 –

+0

文件是否在信息結尾處關閉?什麼終止消息?一般的信息格式是什麼? – Galik

+0

@Galik我添加了消息結構 – rielt12

回答

0

您可以將讀取分爲三部分。找到消息的開始。然後獲得LENGTH。然後閱讀其餘的消息。

// 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 

您應該添加錯誤檢查...

+0

消息圖清楚地顯示了兩個字節進行同步,但您的代碼只是檢查第一個字節。 'length'被表示爲little-endian,並且您的代碼將其視爲big-endian。 – sawdust

+0

@sawdust好的。我已經添加了一個檢查。 –

+0

你的代碼仍然有錯誤。嘗試獲取長度爲'n = read(fd,&input_buffer [2],4)'的字節可以獲取小於所請求的4個字節。請參閱https:// stackoverflow。com/questions/43871939/serial-port-read-is-not-complete因此接下來的** read()**對於其餘的消息使用一個僞長度值'length'。爲了解決這個錯誤,不檢查返回代碼。 – sawdust

1

爲了減少使得許多閱讀()的小字節計數系統調用的開銷,在代碼中使用的中間緩衝器。
read()應該處於阻塞模式以避免零字節的返回碼。

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

爲了正確termios的串行終端初始化代碼,見this answer。您應該將VMIN參數增加到更接近BLEN值的值。

現在您可以方便地一次訪問一個字節的接收數據,並且性能損失最小。

#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) { 
     ... 
...