在Python中解包复杂的嵌套C结构

r55awzrz  于 2023-08-03  发布在  Python
关注(0)|答案(2)|浏览(108)

这是my previous question, "Unpacking nested C structs in Python"的后续问题。我正在使用的结构体已经变得更加复杂,我再一次不确定如何完全解包和处理它们。
在C端,header的相关部分看起来像这样:

typedef struct {
    uint8_t seq;
    uint8_t type;
    uint16_t flags;
    uint16_t upTimestamp;
}__attribute__ ((packed)) mps_packet_header;

typedef struct {
    mps_packet_header header;
    int16_t x[6];
    int16_t y[6];
    int16_t z[6];
    uint16_t lowTimestmp[6];
}__attribute__ ((packed)) mps_acc_packet_t;
typedef mps_acc_packet_t accpacket_t;

typedef struct {
    int16_t hb1;
    int16_t hb2;
} acam_hb_data_set;

typedef struct __attribute__ ((packed)) {
    mps_packet_header header;
    uint16_t temp;
    uint16_t lowTimestmp[8];
    acam_hb_data_set dms_data[8];
} mps_dms_packet_t;

字符串
由此产生了两个挑战。首先,我收到的数据包(以二进制形式)可以是mps_acc_packet_tmps_dms_packet_t-区分它们的唯一方法是读取两种数据包类型都具有的mps_packet_header中的type字段。这意味着我需要在知道它的完整内容之前解包,我不知道如何干净地做(如果我没有弄错的话)这两种包类型有不同的calcsize(分别为54和56)。第二个挑战是解包mps_dms_packet_t;从结构体的定义中可以看出,这个包有一个由8个acam_hb_data_set示例组成的数组,而acam_hb_data_set又是一个由两个int16值组成的结构体。我不知道如何为它制定一个正确的格式字符串。
我之前的代码(在引入mps_dms_packet_t之前)看起来像这样,正如falsetru in his answer to my previous question所建议的那样:

s = struct.Struct('= B B H H 6h 6h 6h 6H')
fields = s.unpack(packet_data)
seq, _type, flags, upTimestamp = fields[:4]
x = fields[4:10]
y = fields[10:16]
z = fields[16:22]
lowTimestamp = fields[22:]


这很有效。现在,我需要以某种方式能够读取头(为此我需要解包结构),然后根据其类型正确地解包结构。
我该怎么做呢?

wz8daaqr

wz8daaqr1#

试试ctypes。它的可读性更强,更容易打包/解包数据。

import ctypes

class mps_packet_header(ctypes.Structure):
    _fields_ = [
        ("seq", ctypes.c_uint8),
        ("type", ctypes.c_uint8),
        ("flags", ctypes.c_uint16),
        ("upTimestamp", ctypes.c_uint16)
    ]

class mps_acc_packet_t(ctypes.Structure):
    _fields_ = [
        ("header", mps_packet_header),
        ("x", ctypes.c_int16 * 6),
        ("y", ctypes.c_int16 * 6),
        ("z", ctypes.c_int16 * 6),
        ("lowTimestmp", ctypes.c_uint16 * 6)
    ]

class acam_hb_data_set(ctypes.Structure):
    _fields_ = [
        ("hb1", ctypes.c_int16),
        ("hb2", ctypes.c_int16),
    ]

class mps_dms_packet_t(ctypes.Structure):
    _fields_ = [
        ("header", mps_packet_header),
        ("temp", ctypes.c_uint16),
        ("lowTimestmp", ctypes.c_uint16 * 8),
        ("dms_data", acam_hb_data_set * 8)
    ]

字符串

fykwrbwg

fykwrbwg2#

我写了一个基于bitstruct包的this小包。基本上,它允许你做你已经可以按照前面的答案实现的事情,但包括在Python端添加位字段的可能性。
比如说

typedef struct __attribute__((packed)) {
    uint8_t number;
    char brand[10];
} shoes_t;

typedef struct __attribute__((packed)) {
    char tshirt[10];
    char shorts[10];
    shoes_t shoes;
} clothes_t;

typedef struct __attribute__((packed)) {
    char name[10];
    uint8_t age;
    float weight;
    clothes_t clothes;
} person_t;

字符串
表示为:

shoes_t =  Struct(
    {
        "number": c_unsigned_int(8),
        "brand": c_char(10*8)
    }
)

dresses_t =  Struct(
    {
        "tshirt": c_char(10*8),
        "shorts": c_char(10*8),
        "shoes": shoes_t
    }
)

person_t = Struct(
    {
        "name": c_char(10*8),
        "age": c_unsigned_int(8),
        "weight": c_float(32),
        "dresses": dresses_t
    }
)


Struct类公开了packunpack方法。
你可以在这里找到一个用法的例子

相关问题