def decode_field(self, field_definition: FieldDefinition) -> RecordField: raw_bytes = self.reader.read_bytes( field_definition.size) # TODO endianness type_class = BASE_TYPE_NUMBER_TO_CLASS[field_definition.base_type] decoded_value = type_class.from_bytes(raw_bytes) if field_definition.number == Decoder.MESSAGE_INDEX_FIELD_NUMBER: if field_definition.base_type != UnsignedInt16.metadata( ).base_type_number: raise FITFileContentError( 'Message Index field number {} is expected to be of type {}, {} found', Decoder.MESSAGE_INDEX_FIELD_NUMBER, UnsignedInt16.__name__, type_class.__name__) if field_definition.number == Decoder.PART_INDEX_FIELD_NUMBER: if field_definition.base_type != UnsignedInt32.metadata( ).base_type_number: raise FITFileContentError( 'Part Index field number {} is expected to be of type {}, {} found', Decoder.MESSAGE_INDEX_FIELD_NUMBER, UnsignedInt32.__name__, type_class.__name__) if field_definition.number == Decoder.TIMESTAMP_FIELD_NUMBER: if field_definition.base_type != UnsignedInt32.metadata( ).base_type_number: raise FITFileContentError( 'Timestamp field number {} is expected to be of type {}, {} found', Decoder.TIMESTAMP_FIELD_NUMBER, UnsignedInt32.__name__, type_class.__name__) self.most_recent_timestamp = decoded_value return RecordField(decoded_value)
def decode_message_definition( self, header: NormalRecordHeader) -> MessageDefinition: reserved_byte = self.reader.read_byte() if reserved_byte: raise FITFileContentError( 'Reserved byte after record header is not 0') architecture = Architecture(self.reader.read_byte()) global_message_number = UnsignedInt16.from_bytes( self.reader.read_bytes(2)) number_of_fields = self.reader.read_byte() field_definitions = tuple([ self.decode_field_definition() for _ in range(0, number_of_fields) ]) number_of_developer_fields = self.reader.read_byte( ) if header.has_developer_data else 0 developer_field_definitions = tuple([ self.decode_field_definition() for _ in range(0, number_of_developer_fields) ]) definition = MessageDefinition(reserved_byte, architecture, global_message_number, field_definitions, developer_field_definitions) self.message_definitions[header.local_message_type] = definition return definition
def decode_crc(self, allow_zero) -> UnsignedInt16: computed_crc = self.reader.crc_calculator.current expected_crc = self.reader.read_double_byte() self.reader.crc_calculator.reset() if allow_zero and expected_crc == UnsignedInt16(0): return expected_crc if computed_crc != expected_crc: raise FITFileContentError( f'Invalid CRC. Expected: {expected_crc}, computed: {computed_crc}' ) return expected_crc
def read_double_byte(self) -> UnsignedInt16: return UnsignedInt16( np.array([self.read_byte() for _ in range(0, 2)]).view(UnsignedInt16)[0])
def reset(self) -> None: self.current = UnsignedInt16(0)
def __init__(self): self.current = UnsignedInt16(0)
class CRCCalculator: CRC_TABLE = [ UnsignedInt16(0x0000), UnsignedInt16(0xCC01), UnsignedInt16(0xD801), UnsignedInt16(0x1400), UnsignedInt16(0xF001), UnsignedInt16(0x3C00), UnsignedInt16(0x2800), UnsignedInt16(0xE401), UnsignedInt16(0xA001), UnsignedInt16(0x6C00), UnsignedInt16(0x7800), UnsignedInt16(0xB401), UnsignedInt16(0x5000), UnsignedInt16(0x9C01), UnsignedInt16(0x8801), UnsignedInt16(0x4400), ] x000F = UnsignedInt16(0x000F) x0FFF = UnsignedInt16(0x0FFF) def __init__(self): self.current = UnsignedInt16(0) def reset(self) -> None: self.current = UnsignedInt16(0) def new_byte(self, byte) -> None: crc = self.current tmp = CRCCalculator.CRC_TABLE[ crc & CRCCalculator.x000F] # tmp = crc_table[crc & 0xF]; crc = (crc >> 4) & CRCCalculator.x0FFF # crc = (crc >> 4) & 0x0FFF; crc = crc ^ tmp ^ CRCCalculator.CRC_TABLE[ byte & CRCCalculator.x000F] # crc = crc ^ tmp ^ crc_table[byte & 0xF]; tmp = CRCCalculator.CRC_TABLE[ crc & CRCCalculator.x000F] # tmp = crc_table[crc & 0xF]; crc = (crc >> 4) & CRCCalculator.x0FFF # crc = (crc >> 4) & 0x0FFF; crc = crc ^ tmp ^ CRCCalculator.CRC_TABLE[ (byte >> 4) & CRCCalculator. x000F] # crc = crc ^ tmp ^ crc_table[(byte >> 4) & 0xF]; self.current = crc