Skip to content

Commit 0cfa1be

Browse files
committed
Add FitFileEncoder for writing FIT files
1 parent 00ba277 commit 0cfa1be

11 files changed

+927
-71
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 (
@@ -98,6 +90,7 @@ def _parse_file_header(self):
9890

9991
# Initialize data
10092
self._accumulators = {}
93+
self.data_size = 0
10194
self._bytes_left = -1
10295
self._complete = False
10396
self._compressed_ts_accumulator = 0
@@ -110,7 +103,7 @@ def _parse_file_header(self):
110103
raise FitHeaderError("Invalid .FIT File Header")
111104

112105
# Larger fields are explicitly little endian from SDK
113-
header_size, protocol_ver_enc, profile_ver_enc, data_size = self._read_struct('2BHI4x', data=header_data)
106+
header_size, protocol_ver_enc, profile_ver_enc, self.data_size = self._read_struct('2BHI4x', data=header_data)
114107

115108
# Decode the same way the SDK does
116109
self.protocol_version = float("%d.%d" % (protocol_ver_enc >> 4, protocol_ver_enc & ((1 << 4) - 1)))
@@ -131,7 +124,7 @@ def _parse_file_header(self):
131124
self._read(extra_header_size - 2)
132125

133126
# After we've consumed the header, set the bytes left to be read
134-
self._bytes_left = data_size
127+
self._bytes_left = self.data_size
135128

136129
def _parse_message(self):
137130
# When done, calculate the CRC and return None
@@ -243,7 +236,7 @@ def _parse_definition_message(self, header):
243236
def _parse_raw_values_from_data_message(self, def_mesg):
244237
# Go through mesg's field defs and read them
245238
raw_values = []
246-
for field_def in def_mesg.field_defs + def_mesg.dev_field_defs:
239+
for field_def in def_mesg.all_field_defs():
247240
base_type = field_def.base_type
248241
is_byte = base_type.name == 'byte'
249242
# Struct to read n base types (field def size / base type size)
@@ -284,18 +277,6 @@ def _resolve_subfield(field, def_mesg, raw_values):
284277
return sub_field, field
285278
return field, None
286279

287-
def _apply_scale_offset(self, field, raw_value):
288-
# Apply numeric transformations (scale+offset)
289-
if isinstance(raw_value, tuple):
290-
# Contains multiple values, apply transformations to all of them
291-
return tuple(self._apply_scale_offset(field, x) for x in raw_value)
292-
elif isinstance(raw_value, num_types):
293-
if field.scale:
294-
raw_value = float(raw_value) / field.scale
295-
if field.offset:
296-
raw_value = raw_value - field.offset
297-
return raw_value
298-
299280
@staticmethod
300281
def _apply_compressed_accumulation(raw_value, accumulation, num_bits):
301282
max_value = (1 << num_bits)
@@ -318,7 +299,7 @@ def _parse_data_message(self, header):
318299

319300
# TODO: Maybe refactor this and make it simpler (or at least broken
320301
# up into sub-functions)
321-
for field_def, raw_value in zip(def_mesg.field_defs + def_mesg.dev_field_defs, raw_values):
302+
for field_def, raw_value in zip(def_mesg.all_field_defs(), raw_values):
322303
field, parent_field = field_def.field, None
323304
if field:
324305
field, parent_field = self._resolve_subfield(field, def_mesg, raw_values)
@@ -339,7 +320,7 @@ def _parse_data_message(self, header):
339320

340321
# Apply scale and offset from component, not from the dynamic field
341322
# as they may differ
342-
cmp_raw_value = self._apply_scale_offset(component, cmp_raw_value)
323+
cmp_raw_value = component.apply_scale_offset(cmp_raw_value)
343324

344325
# Extract the component's dynamic field from def_mesg
345326
cmp_field = def_mesg.mesg_type.fields[component.def_num]
@@ -361,7 +342,8 @@ def _parse_data_message(self, header):
361342

362343
# TODO: Do we care about a base_type and a resolved field mismatch?
363344
# My hunch is we don't
364-
value = self._apply_scale_offset(field, field.render(raw_value))
345+
value = field.render(raw_value)
346+
value = field.apply_scale_offset(value)
365347
else:
366348
value = raw_value
367349

0 commit comments

Comments
 (0)