def parse_location_data_bytes(location_data_bytes): if len(location_data_bytes) > 0: location_data_content = location_data_bytes[0] location_data_bytes = location_data_bytes[1:] location_data_content_name = LOCATION_DATA_CONTENT_NAMES[ location_data_content] else: location_data_content = None location_data_content_name = None if (location_data_content == 0 or location_data_content == 2): if len(location_data_bytes) < 13: raise ValueError( 'Location data content byte indicated position data was included but less than 13 bytes follow' ) position_bytes = location_data_bytes[:13] location_data_bytes = location_data_bytes[13:] position_data = bitstruct.unpack_dict( 's32s32s32u8<', ['x_position', 'y_position', 'z_position', 'quality'], position_bytes) else: position_data = None if (location_data_content == 1 or location_data_content == 2): if len(location_data_bytes) < 1: raise ValueError( 'Location data content byte indicated distance data was included but no bytes follow' ) distance_count = location_data_bytes[0] location_data_bytes = location_data_bytes[1:] if len(location_data_bytes) < 7 * distance_count: raise ValueError( 'Distance count byte indicated that {} distance values would follow so expected {} bytes but only {} bytes follow' .format(distance_count, 7 * distance_count, len(location_data_bytes))) distance_data = [] for distance_data_index in range(distance_count): distance_datum_bytes = location_data_bytes[:7] location_data_bytes = location_data_bytes[7:] distance_datum = bitstruct.unpack_dict( 'u16u32u8<', ['node_id', 'distance', 'quality'], distance_datum_bytes) distance_data.append(distance_datum) else: distance_data = None return { 'location_data_content': location_data_content, 'location_data_content_name': location_data_content_name, 'position_data': position_data, 'distance_data': distance_data }
def HexToCmd(hex): """convert the raw tlf35584 command to physical meaning.""" unpacked = bitstruct.unpack_dict('u1u6u8u1', ['RW', 'Addr', 'Value', 'P'], bytearray.fromhex(hex)) for k, v in unpacked.items(): print("{:<6} {:#04x}".format(k, v)) return unpacked
def _parse_location_data_bytes(self, location_data_bytes) -> {}: if len(location_data_bytes) > 0: location_data_content = location_data_bytes[0] location_data_bytes = location_data_bytes[1:] else: location_data_content = None if (location_data_content == 0 or location_data_content == 2): if len(location_data_bytes) < AMOUNT_OF_BYTES_FOR_POSITION: raise ValueError( 'Location data content byte indicated position data but less than 13 bytes follow' ) position_data = bitstruct.unpack_dict( 's32s32s32u8<', ['x', 'y', 'z', 'quality'], location_data_bytes[:AMOUNT_OF_BYTES_FOR_POSITION]) else: position_data = None return { 'location_data_content_name': LOCATION_DATA_CONTENT_NAMES[location_data_content] if location_data_content else None, 'position_data': position_data }
def load(cls, data, xing_quality): encoder = data.read(9) if not encoder.startswith(b'LAME'): raise InvalidHeader('Valid LAME header not found.') version_match = re.search(rb'LAME(\d+)\.(\d+)', encoder) if version_match: version = tuple(int(part) for part in version_match.groups()) else: version = None revision, bitrate_mode_ = bitstruct.unpack('u4 u4', data.read(1)) bitrate_mode = LAMEBitrateMode(bitrate_mode_) # TODO: Decide what, if anything, to do with the different meanings in LAME. # quality = (100 - xing_quality) % 10 # vbr_quality = (100 - xing_quality) // 10 lowpass_filter = struct.unpack('B', data.read(1))[0] * 100 replay_gain = LAMEReplayGain.load(data) flags_ath = bitstruct.unpack_dict('b1 b1 b1 b1 u4', [ 'nogap_continuation', 'nogap_continued', 'nssafejoint', 'nspsytune', 'ath_type' ], data.read(1)) ath_type = flags_ath.pop('ath_type') encoding_flags = LAMEEncodingFlags(flags_ath['nogap_continuation'], flags_ath['nogap_continued'], flags_ath['nssafejoint'], flags_ath['nspsytune']) # TODO: Different representation for VBR minimum bitrate vs CBR/ABR specified bitrate? # Can only go up to 255. bitrate = struct.unpack('B', data.read(1))[0] * 1000 delay, padding = bitstruct.unpack('u12 u12', data.read(3)) source_sample_rate, unwise_settings_used, channel_mode_, noise_shaping = bitstruct.unpack( 'u2 u1 u3 u2', data.read(1)) channel_mode = LAMEChannelMode(channel_mode_) mp3_gain = bitstruct.unpack('s8', data.read(1))[0] surround_info_, preset_used_ = bitstruct.unpack( 'p2 u3 u11', data.read(2)) surround_info = LAMESurroundInfo(surround_info_) preset = LAMEPreset(preset_used_) audio_size, audio_crc, lame_crc = struct.unpack('>I2s2s', data.read(8)) return cls(lame_crc, version, revision, ath_type, audio_crc, audio_size, bitrate, bitrate_mode, channel_mode, delay, encoding_flags, lowpass_filter, mp3_gain, noise_shaping, padding, preset, replay_gain, source_sample_rate, surround_info, unwise_settings_used)
def parse_operation_mode_bytes(operation_mode_bytes): operation_mode_data = bitstruct.unpack_dict('u1u2u1b1b1b1b1b1b1b1u4', [ 'device_type', 'uwb_mode', 'fw_version', 'accelerometer_enable', 'led_enable', 'fw_update_enable', 'reserved_01', 'initiator', 'low_power_mode', 'location_engine', 'reserved_02' ], operation_mode_bytes) operation_mode_data['device_type_name'] = DEVICE_TYPE_NAMES[ operation_mode_data['device_type']] operation_mode_data['uwb_mode_name'] = UWB_MODE_NAMES[ operation_mode_data['uwb_mode']] operation_mode_data['fw_version_name'] = FW_VERSION_NAMES[ operation_mode_data['fw_version']] return operation_mode_data
def parse_proxy_positions_bytes(proxy_positions_bytes): if len(proxy_positions_bytes) > 0: num_elements = proxy_positions_bytes[0] proxy_positions_bytes = proxy_positions_bytes[1:] proxy_positions_data = [] for element_index in range(num_elements): position_bytes = proxy_positions_bytes[:15] proxy_positions_bytes = proxy_positions_bytes[15:] position_data = bitstruct.unpack_dict('u16s32s32s32u8<', [ 'node_id', 'x_position', 'y_position', 'z_position', 'quality' ], position_bytes) proxy_positions_data.append(position_data) return proxy_positions_data else: return None
def unpack(cls, packet): # the options field may extend into sname/file # so we have to extract the options into their own variable # TODO: check option overload option before reading options out of sname/file options_idx = packet.index(DHCP_OPTIONS_MAGIC_COOKIE, DHCP_CORE_HEADER_LENGTH) header_bytes = packet[:options_idx].rjust(DHCP_FULL_HEADER_LENGTH, b"\x00") options_bytes = packet[options_idx + len(DHCP_OPTIONS_MAGIC_COOKIE):] params = bitstruct.unpack_dict(DHCP_STRUCT, DHCP_NAMES, header_bytes) options = list(DHCPOption.parse_multiple(options_bytes)) params["chaddr"] = params["chaddr"][:params["hlen"]] params["sname"] = params["sname"][:params["sname"].index(b"\x00")] params["file"] = params["file"][:params["file"].index(b"\x00")] return cls(**params, options=options)
def load(cls, data): if data.read(3) != b"ID3": raise InvalidHeader("Valid ID3v2 header not found.") major, revision, flags_, sync_size = struct.unpack( 'BBs4s', data.read(7)) try: version = ID3Version((2, major)) except ValueError: raise ValueError(f"Unsupported ID3 version (2.{major}).") flags = bitstruct.unpack_dict( 'b1 b1 b1 b1', ['unsync', 'extended', 'experimental', 'footer', 'ath_type'], flags_) size = decode_synchsafe_int(sync_size, 7) return cls(size, version, flags)
def unpack(cls, bytes): params = bitstruct.unpack_dict(IP_HEADER_STRUCT, IP_HEADER_NAMES, bytes[:IP_HEADER_LENGTH]) return cls(**params, data=bytes[params["ihl"] * 4:])
def load(cls, data, xing_quality): if not isinstance(data, DataReader): # pragma: nocover data = DataReader(data) encoder = data.read(9) if not encoder.startswith(b'LAME'): raise InvalidHeader('Valid LAME header not found.') version_match = re.search(rb'LAME(\d+)\.(\d+)', encoder) if version_match: version = tuple(int(part) for part in version_match.groups()) else: version = None revision, bitrate_mode_ = bitstruct.unpack('u4 u4', data.read(1)) bitrate_mode = LAMEBitrateMode(bitrate_mode_) # TODO: Decide what, if anything, to do with the different meanings in LAME. # quality = (100 - xing_quality) % 10 # vbr_quality = (100 - xing_quality) // 10 lowpass_filter = struct.unpack('B', data.read(1))[0] * 100 gain_data = struct.unpack('4s2s2s', data.read(8)) track_gain = LAMEReplayGain.load(gain_data[0] + gain_data[1]) album_gain = LAMEReplayGain.load(gain_data[0] + gain_data[2]) flags_ath = bitstruct.unpack_dict('b1 b1 b1 b1 u4', [ 'nogap_continuation', 'nogap_continued', 'nssafejoint', 'nspsytune', 'ath_type' ], data.read(1)) encoding_flags = { k: v for k, v in flags_ath.items() if k != 'ath_type' } ath_type = flags_ath['ath_type'] # TODO: Different representation for VBR minimum bitrate vs CBR/ABR specified bitrate? # Can only go up to 255. bitrate = struct.unpack('B', data.read(1))[0] * 1000 delay, padding = bitstruct.unpack('u12 u12', data.read(3)) source_sample_rate, unwise_settings_used, channel_mode_, noise_shaping = bitstruct.unpack( 'u2 u1 u3 u2', data.read(1)) channel_mode = LAMEChannelMode(channel_mode_) # lame_header_data = struct.unpack('>IHH', data.read(36)) mp3_gain = bitstruct.unpack('s8', data.read(1))[0] # mp3_gain = lame_header_data[12] & 127 # if lame_header_data[12] & 1: # mp3_gain *= -1 surround_info_, preset_used_ = bitstruct.unpack( 'p2 u3 u11', data.read(2)) surround_info = LAMESurroundInfo(surround_info_) try: preset = LAMEPreset(preset_used_) except ValueError: # 8-320 are used for bitrates and aren't defined in LAMEPreset. preset = f"{preset_used_} Kbps" audio_size, audio_crc, lame_crc = struct.unpack('>I2s2s', data.read(8)) return cls(lame_crc, version, revision, album_gain, ath_type, audio_crc, audio_size, bitrate, bitrate_mode, channel_mode, delay, encoding_flags, lowpass_filter, mp3_gain, noise_shaping, padding, preset, source_sample_rate, surround_info, track_gain, unwise_settings_used)
def unpack(cls, packet): params = bitstruct.unpack_dict(UDP_HEADER_STRUCT, UDP_HEADER_NAMES, packet[:8]) return cls(**params, data=packet[8:params["length"]])
def parse_update_rate_bytes(update_rate_bytes): update_rate_data = bitstruct.unpack_dict( 'u32u32<', ['moving_update_rate', 'stationary_update_rate'], update_rate_bytes) return update_rate_data
def parse_device_info_bytes(device_info_bytes): device_info_data = bitstruct.unpack_dict('u64u32u32u32u32u32b1u7<', [ 'node_id', 'hw_version', 'fw1_version', 'fw2_version', 'fw1_checksum', 'fw2_checksum', 'bridge', 'unknown' ], device_info_bytes) return device_info_data
def __init__(self, buf): self.rx_epoch = int(time.time()) self.logger = logging.getLogger(__file__) self.adv = tuple() self.rsp = tuple() self.flags_dict = dict() self.bd_addr = "" self.name = "" self.adv_valid = False self.rsp_valid = False self.rsp_has_versions = False if (len(buf) % 2) == 0: b = bytes.fromhex(buf) else: b = bytes() self.logger.debug(f"Advertisement Length {len(buf)} -> {len(b)}") try: self.adv = namedtuple("adv", FOB_ADV_FIELDS)._make( struct.unpack_from(FOB_ADV_FORMAT, b)) self.adv_valid = self._validate_ad() h = self.adv.bluetooth_address.hex() self.bd_addr = h[10:12] + h[8:10] + \ h[6:8] + h[4:6] + h[2:4] + h[0:2] except: self.logger.info("Error in parsing advertisement") if self.adv_valid: if verbose: self.logger.debug(self.adv.flags) try: x = struct.pack('>H', self.adv.flags) if verbose: self.logger.debug(x) self.flags_dict = bitstruct.unpack_dict( FOB_FLAGS_FORMAT, FOB_FLAGS_NAMES, (x)) self.logger.debug(self.flags_dict) except: self.logger.debug("Unable to unpack flags in advertisement") # # Adv and Scan response are done individually for debug reasons # try: rsp_format = namedtuple("format_type", "type")._make( struct.unpack_from('<B', b, RSP_START_INDEX)) if rsp_format.type == VSP_ADTYPE_LENGTH: self.rsp = namedtuple("rsp", FOB_RSP_FIELDS1)._make( struct.unpack_from(FOB_RSP_FORMAT1, b, RSP_START_INDEX)) self.rsp_valid = self._validate_rsp1() else: self.rsp = namedtuple("rsp", FOB_RSP_FIELDS2)._make( struct.unpack_from(FOB_RSP_FORMAT2, b, RSP_START_INDEX)) self.rsp_valid = self._validate_rsp2() self.rsp_has_versions = self.rsp_valid # The length of the name is variable length = self.rsp.name_length - 1 self.name = namedtuple("name", "name")._make( struct.unpack_from(f'<{length}s', b, (RSP_START_INDEX + rsp_format.type + RSP_NAME_OFFSET))).name.decode('utf-8') except: self.logger.info("Error in parsing scan response")
def unpack(cls, packet): params = bitstruct.unpack_dict(ARP_STRUCT, ARP_NAMES, packet) return cls(**params)
def unpack(cls, packet): params = bitstruct.unpack_dict(TCP_HEADER_STRUCT, TCP_HEADER_NAMES, packet[:TCP_HEADER_LENGTH]) return cls(**params, data=packet[params["offset"] * 4:])
def unpack(cls, packet): params = bitstruct.unpack_dict(ETHERNET_HEADER_STRUCT, ETHERNET_HEADER_NAMES, packet[:ETHERNET_HEADER_LENGTH]) return cls(**params, data=packet[ETHERNET_HEADER_LENGTH:])