1#!/usr/bin/env python 2 3from construct import * 4 5BLOCK_TYPE = Enum(Int8ul, 6 RESERVED = 0x00, 7 ARBITRARY_TIMESTAMP = 0x01, 8 CONSTANT_FREQUENCY = 0x02, 9) 10 11SAMPLE_TYPE = Enum(Int16ul, 12 RESERVED = 0x0000, 13 TEMPERATURE = 0x0001, 14 ACCELERATION = 0x0002, 15 ANGULAR_RATE = 0x0003, 16 VOLTAGE = 0x0004, 17 ECG = 0x0005, 18 HUMIDITY = 0x0006, 19 PRESSURE = 0x0007, 20 MAGNETIC_FLUX_DENSITY = 0x0008, 21 22 CUSTOM = 0xF000, 23) 24 25resd_header = Struct( 26 "magic" / Const(b"RESD"), 27 "version" / Int8ul, 28 "reserved" / Padding(3) 29) 30 31blob = Struct( 32 "size" / Rebuild(Int32ul, len_(this.data)), 33 "data" / Int8ul[this.size], 34) 35 36data_block_metadata_item = Struct( 37 "key" / NullTerminated(GreedyRange(Int8ub)), 38 "type" / Int8ul, 39 "value" / Switch(this.type, 40 { 41 0x00: Int8sl, 42 0x01: Int8ul, 43 0x02: Int16sl, 44 0x03: Int16ul, 45 0x04: Int32sl, 46 0x05: Int32ul, 47 0x06: Int64sl, 48 0x07: Int64ul, 49 0x08: Float32l, 50 0x09: Float64l, 51 0x0A: NullTerminated(GreedyRange(Int8ul)), 52 0x0B: blob, 53 }), 54) 55 56data_block_metadata = Struct( 57 "size" / Int64ul, 58 "items" / FixedSized(this.size, GreedyRange(data_block_metadata_item)), 59) 60 61data_block_sample = lambda sample_type: Switch(sample_type, { 62 "TEMPERATURE": Int32sl, 63 "ACCELERATION": Struct( 64 "x" / Int32sl, 65 "y" / Int32sl, 66 "z" / Int32sl, 67 ), 68 "ANGULAR_RATE": Struct( 69 "x" / Int32sl, 70 "y" / Int32sl, 71 "z" / Int32sl, 72 ), 73 "VOLTAGE": Int32ul, 74 "ECG": Int32sl, 75 "HUMIDITY": Int32ul, 76 "PRESSURE": Int64ul, 77 "MAGNETIC_FLUX_DENSITY": Struct( 78 "x" / Int32sl, 79 "y" / Int32sl, 80 "z" / Int32sl, 81 ), 82}) 83 84data_block_sample_arbitrary = lambda sample_type: Struct( 85 "timestamp" / Int64ul, 86 "sample" / data_block_sample(sample_type) 87) 88 89data_block_sample_arbitrary_subheader = Struct( 90 "start_time" / Int64ul, 91) 92 93data_block_sample_frequency = lambda sample_type: Struct( 94 "sample" / data_block_sample(sample_type) 95) 96 97data_block_sample_frequency_subheader = Struct( 98 "start_time" / Int64ul, 99 "period" / Int64ul, 100) 101 102data_block_sample_single = lambda type_, sample_type: Switch(type_, { 103 "ARBITRARY_TIMESTAMP": data_block_sample_arbitrary(sample_type), 104 "CONSTANT_FREQUENCY": data_block_sample_frequency(sample_type), 105}) 106 107data_block_subheader = Switch(this.header.block_type, { 108 "ARBITRARY_TIMESTAMP": data_block_sample_arbitrary_subheader, 109 "CONSTANT_FREQUENCY": data_block_sample_frequency_subheader 110}) 111 112data_block_header = Struct( 113 "block_type" / BLOCK_TYPE, 114 "sample_type" / SAMPLE_TYPE, 115 "channel_id" / Int16ul, 116 "data_size" / Int64ul, 117) 118 119data_block = Struct( 120 "header" / data_block_header, 121 "subheader" / data_block_subheader, 122 "metadata" / data_block_metadata, 123 "samples" / GreedyRange(data_block_sample_single(this.header.block_type, this._.header.sample_type)) 124) 125 126resd = Struct( 127 "header" / resd_header, 128 "blocks" / GreedyRange(data_block) 129) 130