用C解析和读取数据帧?

发布于 2024-08-26 05:36:19 字数 1429 浏览 5 评论 0原文

我正在编写一个从Linux上的串口读取数据的程序。 数据由另一台设备发送,帧格式如下:

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

数据字段包含 127 个八位位组,如图所示,八位位组 1,2 包含一种类型的数据;八位位组 3,4 包含另一个数据。我需要获取这些数据

我知道如何在 Linux 中的串行端口写入和读取数据,但这只是写入和读取一个简单的字符串(如“ABD”)

我的问题是我不知道如何解析如上所述格式化的数据帧,以便我可以:

  • 获取数据字段中八位字节 1,2 中的数据
  • 获取数据字段中八位字节 3,4 中的数据
  • 获取 CRC 字段中的值以检查数据的一致性

这里在 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", errno, strerror(errno));
            return 0;
        }
    }                    
    return 1;
}

有人有一些想法吗?

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", errno, strerror(errno));
            return 0;
        }
    }                    
    return 1;
}

Does anyone please have some ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

街角迷惘 2024-09-02 05:36:19

result 是一个 char 数组,宽度为 1 个八位字节。

读取八位位组n使用:

char octet_n = result[n];

所以要做你想做的事情你需要:

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

编辑:这一行的解释:

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

你想将两个连续的八位位组读入一个16位字:

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

因此您想要获取八位字节 1 的位 7:0 并将它们放入 octet_1_2 的位 7:0:

octet_1_2 = data_field[1];

然后您想要获取八位字节 2 的位 7:0 并将它们放入位 15: 8 个 octet_1_2。您可以通过将八位字节 2 的 8 位向左移动,然后将结果“或”运算到 octet_1_2 中来完成此操作:

octet_1_2 |= data_field[2] << 8;

这两行可以合并为一行,就像我上面所做的那样。

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.

尘曦 2024-09-02 05:36:19

在 C 中读取格式化数据的最好方法是读取结构。
鉴于您拥有的帧格式,我将执行以下操作。


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

这样您就可以通过结构字段访问所需的数据。第一个结构和联合只是访问帧数据字段中所需字节的帮助器。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文