Skip to content

Commit 66b3399

Browse files
committed
Add FitFileEncoder for writing FIT files
1 parent bef7623 commit 66b3399

10 files changed

+950
-72
lines changed

fitparse/base.py

+8-26
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
1-
import io
21
import os
32
import struct
43

5-
# Python 2 compat
6-
try:
7-
num_types = (int, float, long)
8-
str = basestring
9-
except NameError:
10-
num_types = (int, float)
11-
124
from fitparse.processors import FitFileDataProcessor
135
from fitparse.profile import FIELD_TYPE_TIMESTAMP, MESSAGE_TYPES
146
from fitparse.records import (
@@ -94,6 +86,7 @@ def _parse_file_header(self):
9486

9587
# Initialize data
9688
self._accumulators = {}
89+
self.data_size = 0
9790
self._bytes_left = -1
9891
self._complete = False
9992
self._compressed_ts_accumulator = 0
@@ -106,7 +99,7 @@ def _parse_file_header(self):
10699
raise FitHeaderError("Invalid .FIT File Header")
107100

108101
# Larger fields are explicitly little endian from SDK
109-
header_size, protocol_ver_enc, profile_ver_enc, data_size = self._read_struct('2BHI4x', data=header_data)
102+
header_size, protocol_ver_enc, profile_ver_enc, self.data_size = self._read_struct('2BHI4x', data=header_data)
110103

111104
# Decode the same way the SDK does
112105
self.protocol_version = float("%d.%d" % (protocol_ver_enc >> 4, protocol_ver_enc & ((1 << 4) - 1)))
@@ -127,7 +120,7 @@ def _parse_file_header(self):
127120
self._read(extra_header_size - 2)
128121

129122
# After we've consumed the header, set the bytes left to be read
130-
self._bytes_left = data_size
123+
self._bytes_left = self.data_size
131124

132125
def _parse_message(self):
133126
# When done, calculate the CRC and return None
@@ -239,7 +232,7 @@ def _parse_definition_message(self, header):
239232
def _parse_raw_values_from_data_message(self, def_mesg):
240233
# Go through mesg's field defs and read them
241234
raw_values = []
242-
for field_def in def_mesg.field_defs + def_mesg.dev_field_defs:
235+
for field_def in def_mesg.all_field_defs():
243236
base_type = field_def.base_type
244237
is_byte = base_type.name == 'byte'
245238
# Struct to read n base types (field def size / base type size)
@@ -277,18 +270,6 @@ def _resolve_subfield(field, def_mesg, raw_values):
277270
return sub_field, field
278271
return field, None
279272

280-
def _apply_scale_offset(self, field, raw_value):
281-
# Apply numeric transformations (scale+offset)
282-
if isinstance(raw_value, tuple):
283-
# Contains multiple values, apply transformations to all of them
284-
return tuple(self._apply_scale_offset(field, x) for x in raw_value)
285-
elif isinstance(raw_value, num_types):
286-
if field.scale:
287-
raw_value = float(raw_value) / field.scale
288-
if field.offset:
289-
raw_value = raw_value - field.offset
290-
return raw_value
291-
292273
@staticmethod
293274
def _apply_compressed_accumulation(raw_value, accumulation, num_bits):
294275
max_value = (1 << num_bits)
@@ -311,7 +292,7 @@ def _parse_data_message(self, header):
311292

312293
# TODO: Maybe refactor this and make it simpler (or at least broken
313294
# up into sub-functions)
314-
for field_def, raw_value in zip(def_mesg.field_defs + def_mesg.dev_field_defs, raw_values):
295+
for field_def, raw_value in zip(def_mesg.all_field_defs(), raw_values):
315296
field, parent_field = field_def.field, None
316297
if field:
317298
field, parent_field = self._resolve_subfield(field, def_mesg, raw_values)
@@ -332,7 +313,7 @@ def _parse_data_message(self, header):
332313

333314
# Apply scale and offset from component, not from the dynamic field
334315
# as they may differ
335-
cmp_raw_value = self._apply_scale_offset(component, cmp_raw_value)
316+
cmp_raw_value = component.apply_scale_offset(cmp_raw_value)
336317

337318
# Extract the component's dynamic field from def_mesg
338319
cmp_field = def_mesg.mesg_type.fields[component.def_num]
@@ -354,7 +335,8 @@ def _parse_data_message(self, header):
354335

355336
# TODO: Do we care about a base_type and a resolved field mismatch?
356337
# My hunch is we don't
357-
value = self._apply_scale_offset(field, field.render(raw_value))
338+
value = field.render(raw_value)
339+
value = field.apply_scale_offset(value)
358340
else:
359341
value = raw_value
360342

0 commit comments

Comments
 (0)