def section_size(section): """ Returns the size of a section :param section: The definition of the format for this section :returns: int -- An integer representing the size in bits of the section """ return calcsize(section['format'])
def interpretPacket(bits): if type(bits) != bytearray: bits = bytearray(bits) frameFormat = 'u16u2u1u1u12u32' frameEndianSwap ='224' frameAddressFormat = 'u64u48u6u1u1u8' frameAddressEndianSwap = '8611' protocolHeaderFormat ='u64u16u16' # bit structures from LIFX packet protocol protocolHeaderEndianSwap = '822' frameLength = int(calcsize(frameFormat)/8) frameAddressLength = int(calcsize(frameAddressFormat)/8) protocolHeaderLength = int(calcsize(protocolHeaderFormat)/8) # all /8 since we want bytes not bits # parse through packet start = 0 end = frameLength frameFormatBits = bits[start:end] frameData = unpack(frameFormat,byteswap(frameEndianSwap,frameFormatBits)) #unpack bits into big-endian values start = end end = start + frameAddressLength frameAddressBits = bits[start:end] frameAddressData = unpack(frameAddressFormat,byteswap(frameAddressEndianSwap, frameAddressBits)) start = end end = start + protocolHeaderLength protocolHeaderBits = bits[start:end] protocolHeaderData = unpack(protocolHeaderFormat,byteswap(protocolHeaderEndianSwap,protocolHeaderBits)) #print('frame:',frameData) #print('frame address:', frameAddressData) #print('protocol header:',protocolHeaderData) return protocolHeaderData[1]
def deserialize_bitfield(): nonlocal bit_fmt, bit_fields, remainder if bit_fmt == '': return bit_length = bitstruct.calcsize(bit_fmt) // 8 bit_data, remainder = remainder[:bit_length], remainder[bit_length:] logging.debug(f'{self.__class__.__name__}: parse {bit_fmt} from {bin2hex_helper(bit_data)}') if not self._mergeBitfield: values = bitstruct.unpack(bit_fmt + '<', bit_data) else: values = bitstruct.unpack(bit_fmt, bit_data[::-1]) for f, v in zip(bit_fields, values): f.from_serialized(v) bit_fmt = '' bit_fields = []
def main(): """Testing 'bitstruct' package""" parser = argparse.ArgumentParser() parser.add_argument( "-v", "--verbosity", dest="verbosity", action="count", default=0, help="set verbosity level", ) args = parser.parse_args() if args.verbosity == 1: logging.basicConfig(level=logging.INFO) elif args.verbosity > 1: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.ERROR) assert bitstruct.pack("u1u3u4s16", 1, 2, 3, -4) == b"\xa3\xff\xfc" assert bitstruct.unpack("u1u3u4s16", b"\xa3\xff\xfc") == (1, 2, 3, -4) assert bitstruct.calcsize("u1u3u4s16") == 24
def deserialize(cls, input): header_fmt_complt = MultirecordEntry._multirecord_header_fmt + 'u8' header_len = bitstruct.calcsize(header_fmt_complt) // 8 type_id, end_of_list, _, format_version, \ payload_len, payload_cksum, _ = bitstruct.unpack(header_fmt_complt, input) header, remainder = input[:header_len], input[header_len:] payload, remainder = remainder[:payload_len], remainder[payload_len:] logging.debug( f"{cls.__name__}: Trying to deserialize multirecord type_id=0x{type_id:02x}, len={len(header)+len(payload)}" ) logging.debug( f"{cls.__name__}: header: {bin2hex_helper(header)}, payload: {bin2hex_helper(payload)}" ) try: if sum(header) & 0xff != 0: end_of_list = 1 raise RuntimeError("MultirecordEntry header checksum invalid") if cls.opalkelly_workaround_enabled and len(payload) == 0: # Opal Kelly seems to mark the end of list with an empty payload multirecord end_of_list = 1 return None, remainder, end_of_list if (sum(payload) + payload_cksum) & 0xff != 0: end_of_list = 1 raise RuntimeError("MultirecordEntry payload checksum invalid") try: cls_id = rec_lookup_by_id(FruRecordType.ipmi_multirecord, type_id) except KeyError: raise RuntimeError(f"Unknown multirecord type 0x{type_id:02x}") if hasattr(cls_id, 'from_payload'): new_entry = cls_id.from_payload(payload) else: new_entry = cls_id() new_entry._deserialize(payload) new_entry._type_id = type_id new_entry._format_version = format_version new_entry.end_of_list = end_of_list except RuntimeError as e: logging.warning( f"Failed to deserialize multirecord, type_id=0x{type_id:02x}, end_of_list={end_of_list}, " f"format_version={format_version}, len={len(header)+len(payload)}" ) logging.warning(f"reason: {e}") logging.warning( f"header: {bin2hex_helper(header)}, payload: {bin2hex_helper(payload)}" ) new_entry = None except ValueError as e: # Vendor ID mismatch: Don't issue a warning, just ignore it logging.debug(f"{e}") logging.debug( f"Silently ignoring private / proprietary multirecord") new_entry = None except EOFError as e: # Empty payload: Issue warning, but try to proceed logging.warning(f"{e}") new_entry = None return new_entry, remainder, end_of_list
def bit_size(self) -> int: return bitstruct.calcsize(self._format)
def sizeof(format): return calcsize(format)
def num_bytes(self): """Return the number of bytes described in this BitStructInfo""" num_bits = bitstruct.calcsize(self.from_bitstruct) if num_bits % 8 != 0: raise TypeError("Attributes do not add up to a multiple of 8 bits") return num_bits // 8
# CHANNEL_ID (8 bits) (1 byte) # DRS4_OFFSET (12 bits) (1.5 bytes) # SEQ (4 bits) (0.5 bytes) # HIT_PAYLOAD_SIZE (16 bits, representing byte length of all seq packet payloads WITHIN THIS HIT) (1.5 bytes) # TRIGGER_TIMESTAMP_L (32 bits) (4 bytes) # ------------------------------------ (bitstruct for the above fixed header, 11 bytes) # PAYLOAD (arbitrary, but less than an Ethernet MTU for sure) # HIT_FOOTER_MAGIC (16 bits) hit_fmt = "u16 u8 u16 u8 u16 u32" hitpacker = bitstruct.compile(hit_fmt, [ "magic", "channel_id", "drs4_offset", "seq", "hit_payload_size", "trigger_timestamp_l" ]) globals()['HIT_MAGIC'] = 0x39a globals()['HIT_FOOTER_MAGIC'] = 1024 globals()['HIT_HEADER_SIZE'] = bitstruct.calcsize(hit_fmt) >> 3 # Define the format of an event header packet # EVT_HEADER_MAGIC_WORD (16 bits) - just pick something easily readable in the hex stream for now # BOARD_ID (48 bits) - Low 48 bits of the Xilinx Device DNA, also equal to the board MAC address apart from a broadcast bit. # EVT_TYPE (8 bits) - encode ADC bit width, compression level if any, etc. # ---> ADC_BIT_WIDTH (3 bits) # ---> RESERVED (5 bits) # EVT_NUMBER (16 bits) - global event identifier, assumed sequential # EVT_SIZE (16 bits) - event size in bytes # NUM_HITS (8 bits) - for easy alignment and reading # TRIGGER_TIMESTAMP_H (32-bits) # TRIGGER_TIMESTAMP_L (32-bits) # RESERVED (64-bits) event_fmt = "u16 r48 p8 u3 p5 u16 u16 u8 p8 u32 u32 p64" eventpacker = bitstruct.compile(event_fmt, [
import time import cbitstruct import bitstruct import timeit import unittest import string import random import cbitstruct import bitstruct fmt = "s12u45p127f32f64s32r13p2P8r32u16u2s12" nbytes = (bitstruct.calcsize(fmt) + 7) // 8 random.seed(0) data = bytes([random.randint(0, 255) for _ in range(nbytes)]) dst = bytearray([0] * nbytes) values = bitstruct.unpack(fmt, data) names = string.ascii_letters[:len(values)] values_dict = {n: v for n, v in zip(names, values)} bs = bitstruct.compile(fmt) cbs = cbitstruct.compile(fmt) dbs = bitstruct.compile(fmt, names) cdbs = cbitstruct.compile(fmt, names) NBS = 10000 NCBS = 100000