| #!/usr/bin/env python | |
| from construct import * | |
| BLOCK_TYPE = Enum(Int8ul, | |
| RESERVED = 0x00, | |
| ARBITRARY_TIMESTAMP = 0x01, | |
| CONSTANT_FREQUENCY = 0x02, | |
| ) | |
| SAMPLE_TYPE = Enum(Int16ul, | |
| RESERVED = 0x0000, | |
| TEMPERATURE = 0x0001, | |
| ACCELERATION = 0x0002, | |
| ANGULAR_RATE = 0x0003, | |
| VOLTAGE = 0x0004, | |
| ECG = 0x0005, | |
| HUMIDITY = 0x0006, | |
| PRESSURE = 0x0007, | |
| MAGNETIC_FLUX_DENSITY = 0x0008, | |
| CUSTOM = 0xF000, | |
| ) | |
| resd_header = Struct( | |
| "magic" / Const(b"RESD"), | |
| "version" / Int8ul, | |
| "reserved" / Padding(3) | |
| ) | |
| blob = Struct( | |
| "size" / Rebuild(Int32ul, len_(this.data)), | |
| "data" / Int8ul[this.size], | |
| ) | |
| data_block_metadata_item = Struct( | |
| "key" / NullTerminated(GreedyRange(Int8ub)), | |
| "type" / Int8ul, | |
| "value" / Switch(this.type, | |
| { | |
| 0x00: Int8sl, | |
| 0x01: Int8ul, | |
| 0x02: Int16sl, | |
| 0x03: Int16ul, | |
| 0x04: Int32sl, | |
| 0x05: Int32ul, | |
| 0x06: Int64sl, | |
| 0x07: Int64ul, | |
| 0x08: Float32l, | |
| 0x09: Float64l, | |
| 0x0A: NullTerminated(GreedyRange(Int8ul)), | |
| 0x0B: blob, | |
| }), | |
| ) | |
| data_block_metadata = Struct( | |
| "size" / Int64ul, | |
| "items" / FixedSized(this.size, GreedyRange(data_block_metadata_item)), | |
| ) | |
| data_block_sample = lambda sample_type: Switch(sample_type, { | |
| "TEMPERATURE": Int32sl, | |
| "ACCELERATION": Struct( | |
| "x" / Int32sl, | |
| "y" / Int32sl, | |
| "z" / Int32sl, | |
| ), | |
| "ANGULAR_RATE": Struct( | |
| "x" / Int32sl, | |
| "y" / Int32sl, | |
| "z" / Int32sl, | |
| ), | |
| "VOLTAGE": Int32ul, | |
| "ECG": Int32sl, | |
| "HUMIDITY": Int32ul, | |
| "PRESSURE": Int64ul, | |
| "MAGNETIC_FLUX_DENSITY": Struct( | |
| "x" / Int32sl, | |
| "y" / Int32sl, | |
| "z" / Int32sl, | |
| ), | |
| }) | |
| data_block_sample_arbitrary = lambda sample_type: Struct( | |
| "timestamp" / Int64ul, | |
| "sample" / data_block_sample(sample_type) | |
| ) | |
| data_block_sample_arbitrary_subheader = Struct( | |
| "start_time" / Int64ul, | |
| ) | |
| data_block_sample_frequency = lambda sample_type: Struct( | |
| "sample" / data_block_sample(sample_type) | |
| ) | |
| data_block_sample_frequency_subheader = Struct( | |
| "start_time" / Int64ul, | |
| "period" / Int64ul, | |
| ) | |
| data_block_sample_single = lambda type_, sample_type: Switch(type_, { | |
| "ARBITRARY_TIMESTAMP": data_block_sample_arbitrary(sample_type), | |
| "CONSTANT_FREQUENCY": data_block_sample_frequency(sample_type), | |
| }) | |
| data_block_subheader = Switch(this.header.block_type, { | |
| "ARBITRARY_TIMESTAMP": data_block_sample_arbitrary_subheader, | |
| "CONSTANT_FREQUENCY": data_block_sample_frequency_subheader | |
| }) | |
| data_block_header = Struct( | |
| "block_type" / BLOCK_TYPE, | |
| "sample_type" / SAMPLE_TYPE, | |
| "channel_id" / Int16ul, | |
| "data_size" / Int64ul, | |
| ) | |
| data_block = Struct( | |
| "header" / data_block_header, | |
| "subheader" / data_block_subheader, | |
| "metadata" / data_block_metadata, | |
| "samples" / GreedyRange(data_block_sample_single(this.header.block_type, this._.header.sample_type)) | |
| ) | |
| resd = Struct( | |
| "header" / resd_header, | |
| "blocks" / GreedyRange(data_block) | |
| ) |