c++ - serial - puerto serie arduino mega
analizar mensajes completos desde el puerto serie (2)
Intento leer mensajes completos de mi GPS a través del puerto serie.
El mensaje que estoy buscando comienza con:
0xB5 0x62 0x02 0x13
Así que leo desde el puerto serie como si
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.
}
}
El problema que estoy teniendo es que necesito obtener un mensaje completo. La mitad de un mensaje podría estar en el buffer una iteración. Y la otra mitad podría entrar en el mensaje la próxima iteración.
Alguien sugirió que libere el búfer del mensaje completo. Y luego muevo el resto de los datos en el búfer al comienzo del búfer.
¿Cómo hago eso o de otra forma para asegurarme de recibir todos los mensajes seleccionados que entran?
Quiero una clase y una identificación en particular. Pero también puedo leer en la longitud
Para minimizar la sobrecarga de hacer muchos syscalls de lectura () de pequeños bytes, use un buffer intermedio en su código.
El read () s debe estar en modo de bloqueo para evitar un código de retorno de cero 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++;
}
Para obtener el código de inicialización de termios adecuado para el terminal en serie, consulte esta respuesta . Debe aumentar el parámetro VMIN a algo más cercano al valor BLEN.
Ahora puede acceder cómodamente a los datos recibidos un byte a la vez con un mínimo de penalización de rendimiento.
#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) {
...
...
Puedes dividir la lectura en tres partes. Encuentra el comienzo de un mensaje. Luego obtén LONGITUD. Luego lee el resto del mensaje.
// 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
Debe agregar la comprobación de errores ...