def test_simple_strings(self): strings = [ b"123456789", b"0123456789", b"01234567890", b"012345678901", b"0123456789012", b"01234567890123", b"012345678901234", b"0123456789012345", b"01234567890123456" ] crcs = [ 0xbb3d, 0x443d, 0xc585, 0x77c5, 0x8636, 0x0346, 0x2583, 0xb6a4, 0xad37 ] self.assertEqual(len(strings), len(crcs)) for i in range(len(strings)): s = strings[i] crc = compute_crc(io.BytesIO(s), len(s)) self.assertEqual(crc, crcs[i])
def foo(): import io import os filename = "C:\\Users\\jflam\\OneDrive\\Garmin\\2010-03-22-07-25-44.fit" #filename = "C:\\Users\\jflam\\OneDrive\\Garmin\\2010-03-21-20-31-06.fit" stream = io.open(filename, "rb") crc = compute_crc(stream, os.path.getsize(filename)) print(crc)
def parse_fit_file(path, validate_crc = False): """Parse a fit file. Parameters ---------- path: string Path to the .fit file validate_crc: bool Compute the CRC16 of the file and compare with embedded CRC16. Default is False. Yields ------ Message Individual Message objects from the .fit file. Examples -------- >>> for message in parse_fit_file('fit_file.fit'): pass """ stream = io.open(path, "rb") file_header = FileHeader(stream) if validate_crc: pos = stream.seek(0) crc = compute_crc(stream, file_header.size + file_header.data_size) file_crc = read_uint16(stream) # TODO: debug why CRC is failing with real files # print(pos, format(self.crc, "0x"), format(self.file_crc, "0x")) # Seek to the start of the data (past the file header) pos = stream.seek(file_header.size) bytes_to_read = file_header.data_size bytes_read = 0 # Message definitions are parsed internally by the parser and not exposed to # the caller. We store all of them in this dict: local_message_definitions = {} while bytes_read < bytes_to_read: header = read_uint8(stream) # Normal header (vs. timestamp offset header is indicated by bit 7) # Message type is indicated by bit 6 # 1 == definition # 0 == record local_message_number = header & 0xf if (header & 0x80) == 0 and (header & 0x40) == 0x40: # Parse the message definition and store the definition in our array message_definition = MessageDefinition(header, stream) local_message_definitions[local_message_number] = message_definition bytes_read += message_definition.MessageDefinitionSize() + 1 elif (header & 0x80) == 0 and (header & 0x40) == 0: current_message_definition = local_message_definitions[local_message_number] assert current_message_definition is not None # This design reads the current message into an in-memory byte array. # An alternate design would involve passing in the current binary reader # and allowing the caller of Message to read fields using the binary # reader directly instead of creating a MemoryStream over the byte array # and using a different BinaryReader in the Message. I have done # exactly this and measured the performance, and it is actually SLOWER # than this approach. I haven't root caused why, but would assume that # Seek-ing arbitrarily using the BinaryReader over the FileStream is # slow vs. Seek-ing over a BinaryReader over a MemoryStream. message = Message(header, current_message_definition, stream) yield message bytes_read += current_message_definition.size + 1