开发者

Parse and read data frame in C?

开发者 https://www.devze.com 2022-12-23 17:02 出处:网络
I am writing a program that reads the data from the serial port on Linux. The data are sent by another device with the following frame format:

I am writing a program that reads the data from the serial port on Linux. The data are sent by another device with the following frame format:

|start | Command | Data               | CRC  | End |
|0x02  | 0x41    | (0-127 octets)     |      | 0x03|
----------------------------------------------------

The Data field contains 127 octets as shown and octet 1,2 contains one type of data; octet 3,4 contains another data. I need to get these data

I know how to write and read data to and from a serial port in Linux, but it is just to write and read a simple string (like "ABD")

My issue is that I do not know how to parse the data frame formatted as above so that I can:

  • get the data in octet 1,2 in the Data field
  • get the data in octet 3,4 in the Data field
  • get the value in CRC field to check the consistency of the data

Here the sample snip code that read and write a simple string from and to a serial port in Linux:

int writeport(int fd, char *chars) {
    int len = strlen(chars);
    chars[len] = 0x0d; // stick a <CR> after the command
    chars[len+1] = 0x00; // terminate the string properly
    int n = write(fd, chars, strlen(chars));
    if (n < 0) {
        fputs("write failed!\n", stderr);
        return 0;
    }
    return 1;                                                                                                           
}

int readport(int fd, char *result) {
    int iIn = read(fd, result, 254);
    result[iIn-1] = 0x00;
    if (iIn < 0) {
        if (errno == EAGAIN) {
            printf("SERIAL EAGAIN ERROR\n");
            return 0;
        } else {
            printf("SERIAL read error %d %s\n", errn开发者_C百科o, strerror(errno));
            return 0;
        }
    }                    
    return 1;
}

Does anyone please have some ideas?


result is an array of chars, which are 1 octet wide.

to read octet n use:

char octet_n = result[n];

So to do what you want you need:

// skip the start and command fields
char *data_field = result + 2; 

int octet_1_2 = data_field[1] | (data_field[2] << 8);
int octet_3_4 = data_field[3] | (data_field[4] << 8);

// crc is at byte 128 + 2 = 130
int crc = result[130];

Edit: An explanation for this line:

int octet_1_2 = data_field[1] | (data_field[2] << 8);

You want to read two consecutive octets into one 16-bit word:

            1
       bits 5        8 7       0
            --------------------
octet_1_2 = | octet 2 | octet 1|
            --------------------

So you want to take bits 7:0 of octet 1 and put them in bits 7:0 of octet_1_2:

octet_1_2 = data_field[1];

Then you want to take bits 7:0 of octet 2 and put them in bits 15:8 of octet_1_2. You do this by shifting octet 2 8 bits to the left, and OR'ing the result into octet_1_2:

octet_1_2 |= data_field[2] << 8;

These two lines can be merged into one as I did above.


The best thing to read formatted data in C is to read a structure. Given the frame format you have I would do the following.


typedef struct special_data
{
    char first_data[2];
    char second data[2];
} special_data_t;

union data_u
{
    special_data_t my_special_data;
    char           whole_data[128];
};

typedef struct data_frame
{
    unsigned char start;
    unsigned char cmd;
    union data_u  data;
    unsigned char crc;
    unsigned char end;
} data_frame_t;

void func_read(int fd)
{
    data_frame_t my_data;

    if (read(fd, &my_data, sizeof(my_data)) != -1)
    {
        // Do something
    }
    return;
}

This way you may access the data you need through the structure fields. The first structure and the union are just helpers to access the bytes you need in the data field of the frame.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号