2017-04-07 5 views
1

Ich versuche, vollständige Nachrichten von meinem GPS über die serielle Schnittstelle zu lesen.Vollständige Nachrichten von der seriellen Schnittstelle analysieren

Die Botschaft, die ich für startet Suche mit:

0xB5 0x62 0x02 0x13 

So von der seriellen Schnittstelle ich wie 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. 
    } 

} 

Das Problem, das ich gelesen habe ist, dass ich eine komplette Nachricht erhalten müssen . Die Hälfte einer Nachricht könnte eine Iteration im Puffer enthalten sein. Und die andere Hälfte könnte in der nächsten Iteration in die Nachricht kommen.

Jemand schlug vor, den Puffer von der vollständigen Nachricht freizugeben. Und dann verschiebe ich den Rest der Daten im Puffer an den Anfang des Puffers.

Wie kann ich dies oder irgendeinen anderen Weg machen, der sicherstellt, dass ich jede vollständig ausgewählte Nachricht bekomme, die reinkommt?

bearbeiten // enter image description here

ich eine bestimmte Klasse und ID möchten. Aber ich kann auch in der Länge lesen

+0

Sie könnten 1 Byte zu einer Zeit in einer Schleife lesen, bis Sie eine vollständige Nachricht haben. –

+0

Schließt die Datei am Ende der Nachricht? Was beendet eine Nachricht? Was ist das allgemeine Nachrichtenformat? – Galik

+0

@Galik Ich habe die Nachrichtenstruktur hinzugefügt – rielt12

Antwort

0

Sie können das Lesen in drei Teile brechen. Finden Sie den Anfang einer Nachricht. Dann hol die LÄNGE. Dann lies den Rest der Nachricht.

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

Sie sollten überprüft Fehler hinzufügen ...

+0

Das Nachrichtendiagramm zeigt deutlich zwei Bytes für die Synchronisierung, aber Ihr Code nur zu prüfen, ob der erste. Die 'Länge' wird als Little-Endian angegeben und Ihr Code behandelt sie als Big-Endian. – sawdust

+0

@sawdust Ok. Ich habe einen Check dafür hinzugefügt. –

+0

Ihr Code enthält immer noch Fehler. Der Versuch, die Bytes für die Länge "n = read (fd, & input_buffer [2], 4)" zu erhalten, könnte weniger als die 4 angeforderten Bytes abrufen. Siehe https: // stackoverflow.com/questions/43871939/serial-port-read-is-not-complete Also verwendet der nachfolgende ** read() ** für den Rest der Nachricht einen gefälschten Wert von 'length'. Um diesen Fehler zu vermeiden, werden die Rückgabecodes nicht überprüft. – sawdust

1

Um den Aufwand für die Herstellung vieler read() syscalls von kleinen Bytezählwerte zu minimieren, einen Zwischenpuffer in Ihrem Code verwenden.
Die read() s sollte sich im blockierenden Modus befinden, um einen Rückkehrcode von Null Bytes zu vermeiden.

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

Für eine korrekte termios Initialisierungscode für die serielle Terminal, this answer sehen. Sie sollten den Parameter VMIN auf einen Wert erhöhen, der näher am BLEN-Wert liegt.

Jetzt können Sie bequem auf die empfangenen Daten ein Byte zu einem Zeitpunkt mit minimaler Leistungseinbuße zugreifen.

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