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

时间:2013-09-11 09:28:50

标签: python c struct nested unpack

这是my previous question, "Unpacking nested C structs in Python"的后续问题。我正在使用的结构变得更加复杂,我再次不确定如何解压缩并完全处理它们。

在C方面,标题的相关部分如下所示:

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 - 告诉他们不同的唯一方法是阅读type中的mps_packet_header字段两种数据包类型都有。这意味着我需要在知道其全部内容之前解压缩数据包,我不知道如何干净利落(因为我没有记错)两种数据包类型有不同的calcsize(54和分别为56)。第二个挑战是解包mps_dms_packet_t;正如你从struct的定义中看到的那样,这个数据包有一个由8个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:]

这很好用。现在,我需要以某种方式能够读取标头(我需要解压缩结构),然后根据其类型正确解压缩结构。

我将如何做到这一点?

1 个答案:

答案 0 :(得分:2)

为什么不试试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)
    ]