I tried to write a parser to a simple binary protocol
- 0 or more out of frame bytes
- Start of frame with STX (0x02)
- Two messaje length bytes for messaje length.
- One command byte .
- 0 or more data bytes.
- One checksun byte.
The ragel script
static int len;
static unsigned char command;
static int indexx;
static unsigned char data[0x10000];
static unsigned char checksum;
%%{
machine themachine;
action out_of_frame_action { }
action start_of_frame_action {}
action first_byte_len_action { len = fc *256; }
action second_byte_len_action { len += fc; }
action command_action { command = fc; indexx=0; len--;}
action data_action {
if(!len)
fgoto check;
else
{
data[indexx++];
len --;
}
}
action checksum_action { checksum = fc; }
stx = 0x02;
first_byte_len = any;
second_byte_len = any;
command = any;
data = any*;
checksum = any;
main := (^stx* $ out_of_frame_action)
(stx > start_of_frame_action)
(first_byte_len > first_byte_len_action)
(second_byte_len > second_byte_len_action)
(command > command_action)
(data $ data_action) ;
check := (checksum % checksum_action) ;
}%%
But the result machine don't jump to check (5) status so doesn't execute checksum_action and don't return to the first state to continue parsing.
What is wrong?
Follow @Roman recomendations I post a full example. This example doesn't work either because get a wrong checksum.
#include <stdint.h>
#include <stdio.h>
static int len;
static unsigned char command;
static int indexx;
static unsigned char data[0x10000];
static unsigned char checksum;
%%{
machine themachine;
stx = 0x02;
action out_of_frame_action
{
printf("OOF %02X\n",fc);
}
action start_of_frame_action
{
printf("STX ");
}
action first_byte_len_action
{
printf("fbl[%d] ",(int)(fc));
len = 256*((unsigned char)fc);
}
action second_byte_len_action
{
len += (unsigned char )fc ;
printf("sbl[%d] Len=%d ",(int)(fc),len);
indexx=0;
len-=2; // Checksum and command are included on message len
}
action command_action
{
command = fc;
printf("CMM=%02X ", command);
}
action check_len
{
len > 0
}
action data_action
{
data[indexx++]=fc;
printf("[%02X]",(unsigned char) fc);
len--;
}
action checksum_action
{
checksum = fc;
printf(" Chk=%02X \n",checksum);
}
first_byte_len = any ;
second_byte_len = any;
command = any;
data = any*;
checksum = any;
check = (checksum % checksum_action);
main := ((^stx* $ out_of_frame_action)
(stx > start_of_frame_action)
(first_byte_len > first_byte_len_action)
(second_byte_len > second_byte_len_action)
(command > command_action)
(data when check_len $ data_action)
check
)**;
}%%
%% write data;
int main(void)
{
uint8_t buf[] = {
0x00, // OOF 00
0x00, // OOF 00
0x02,0x00,0x03,0x20,0x01,0x21, // STX fbl[0] sbl[3] Len = 3 CMM=20 [01] Chk=21
0x00, // OOF 00
0x00, // OOF 00
0x02,0x00,0x05,0x81,0x01,0x02,0x03,0x87, // STX fbl[0] sbl[5] Len = 5 CMM=81 [01][02][03] Chk=87
0x02,0x00,0x03,0x03,0x01,0x04, // STX fbl[0] sbl[3] Len = 3 CMM=03 [01] Chk=04
0x02,0x00,0x05,0x07,0x01,0x02,0x03,0x0D // STX fbl[0] sbl[5] Len = 5 CMM=07 [01][02][03] Chk=0D
};
int cs;
uint8_t *p, *pe, *eof;
p = buf;
eof = pe = buf + sizeof(buf)/sizeof(uint8_t);
%% write init;
%% write exec;
}
I change
check = (checksum % checksum_action);
by
check = (checksum > checksum_action);
but is not a solution.