def _parse_data_message(self, header): def_mesg = self._local_mesgs.get(header.local_mesg_num) if not def_mesg: raise FitParseError( 'Got data message with invalid local message type %d' % (header.local_mesg_num)) raw_values = self._parse_raw_values_from_data_message(def_mesg) field_datas = [ ] # TODO: I don't love this name, update on DataMessage too # TODO: Maybe refactor this and make it simpler (or at least broken # up into sub-functions) for field_def, raw_value in zip( def_mesg.field_defs + def_mesg.dev_field_defs, raw_values): field, parent_field = field_def.field, None if field: field, parent_field = self._resolve_subfield( field, def_mesg, raw_values) # Resolve component fields if field.components: for component in field.components: # Render its raw value cmp_raw_value = component.render(raw_value) # Apply accumulated value if component.accumulate: accumulator = self._accumulators[def_mesg.mesg_num] cmp_raw_value = self._apply_compressed_accumulation( cmp_raw_value, accumulator[component.def_num], component.bits, ) accumulator[component.def_num] = cmp_raw_value # Apply scale and offset from component, not from the dynamic field # as they may differ cmp_raw_value = self._apply_scale_offset( component, cmp_raw_value) # Extract the component's dynamic field from def_mesg cmp_field = def_mesg.mesg_type.fields[ component.def_num] # Resolve a possible subfield cmp_field, cmp_parent_field = self._resolve_subfield( cmp_field, def_mesg, raw_values) cmp_value = cmp_field.render(cmp_raw_value) # Plop it on field_datas field_datas.append( FieldData( field_def=None, field=cmp_field, parent_field=cmp_parent_field, value=cmp_value, raw_value=cmp_raw_value, )) # TODO: Do we care about a base_type and a resolved field mismatch? # My hunch is we don't value = self._apply_scale_offset(field, field.render(raw_value)) else: value = raw_value # Update compressed timestamp field if (field_def.def_num == FIELD_TYPE_TIMESTAMP.def_num) and (raw_value is not None): self._compressed_ts_accumulator = raw_value field_datas.append( FieldData( field_def=field_def, field=field, parent_field=parent_field, value=value, raw_value=raw_value, )) # Apply timestamp field if we got a header if header.time_offset is not None: ts_value = self._compressed_ts_accumulator = self._apply_compressed_accumulation( header.time_offset, self._compressed_ts_accumulator, 5, ) field_datas.append( FieldData( field_def=None, field=FIELD_TYPE_TIMESTAMP, parent_field=None, value=FIELD_TYPE_TIMESTAMP.render(ts_value), raw_value=ts_value, )) # Apply data processors for field_data in field_datas: # Apply type name processor self._processor.run_type_processor(field_data) self._processor.run_field_processor(field_data) self._processor.run_unit_processor(field_data) data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) self._processor.run_message_processor(data_message) return data_message
def _parse_data_message(self, header): def_mesg = self._local_mesgs.get(header.local_mesg_num) if not def_mesg: raise FitParseError( 'Got data message with invalid local message type %d' % (header.local_mesg_num)) raw_values = self._parse_raw_values_from_data_message(def_mesg) field_datas = [ ] # TODO: I don't love this name, update on DataMessage too # TODO: Maybe refactor this and make it simpler (or at least broken # up into sub-functions) for field_def, raw_value in zip(def_mesg.field_defs, raw_values): field, parent_field = field_def.field, None if field: if field.components: for component in field.components: # Render it's raw value cmp_raw_value = component.render(raw_value) if component.accumulate: accumulator = self._accumulators[def_mesg.mesg_num] cmp_raw_value = self._apply_compressed_accumulation( cmp_raw_value, accumulator[component.def_num], component.bits, ) accumulator[component.def_num] = cmp_raw_value # Apply scale and offset from component, not from the dynamic field # as they may differ cmp_raw_value = self._apply_scale_offset( component, cmp_raw_value) # Extract the component's dynamic field from def_mesg cmp_field = def_mesg.mesg_type.fields[ component.def_num] # Resolve a possible subfield cmp_field, cmp_parent_field = self._resolve_subfield( cmp_field, def_mesg, raw_values) cmp_value = cmp_field.render(cmp_raw_value) # Plop it on field_datas field_datas.append( FieldData( field_def=None, field=cmp_field, parent_field=cmp_parent_field, value=cmp_value, raw_value=cmp_raw_value, )) else: # Component fields shouldn't also have subfields field, parent_field = self._resolve_subfield( field, def_mesg, raw_values) # TODO: Do we care about a base_type and a resolved field mismatch? # My hunch is we don't value = self._apply_scale_offset(field, field.render(raw_value)) else: value = raw_value # Update compressed timestamp field if (field_def.def_num == FIELD_TYPE_TIMESTAMP.def_num) and (raw_value is not None): self._compressed_ts_accumulator = raw_value field_datas.append( FieldData( field_def=field_def, field=field, parent_field=parent_field, value=value, raw_value=raw_value, )) # Apply timestamp field if we got a header if header.time_offset is not None: ts_value = self._compressed_ts_accumulator = self._apply_compressed_accumulation( header.time_offset, self._compressed_ts_accumulator, 5, ) field_datas.append( FieldData( field_def=None, field=FIELD_TYPE_TIMESTAMP, parent_field=None, value=FIELD_TYPE_TIMESTAMP.render(ts_value), raw_value=ts_value, )) # Apply data processors for field_data in field_datas: # Apply type name processor type_processor = getattr(self._processor, 'process_type_%s' % field_data.type.name, None) if type_processor: type_processor(field_data) # Apply field name processor field_processor = getattr(self._processor, 'process_field_%s' % field_data.name, None) if field_processor: field_processor(field_data) # Apply units name processor if field_data.units: process_func_name = 'process_units_%s' % field_data.units # Do unit name replacements padded with spaces for replace_from, replace_to in self.UNIT_NAME_TO_FUNC_REPLACEMENTS: process_func_name = process_func_name.replace( replace_from, ' %s ' % replace_to, ) # Then strip and convert spaces to underscores process_func_name = process_func_name.strip().replace(' ', '_') units_processor = getattr(self._processor, process_func_name, None) if units_processor: units_processor(field_data) data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) mesg_processor = getattr(self._processor, 'process_message_%s' % def_mesg.name, None) if mesg_processor: mesg_processor(data_message) return data_message
def _parse_data_message(self, header): def_mesg = self._local_mesgs.get(header.local_mesg_num) if not def_mesg: raise FitParseError('Got data message with invalid local message type %d' % ( header.local_mesg_num)) raw_values = self._parse_raw_values_from_data_message(def_mesg) field_datas = [] # TODO: I don't love this name, update on DataMessage too # TODO: Maybe refactor this and make it simpler (or at least broken # up into sub-functions) for field_def, raw_value in zip(def_mesg.field_defs, raw_values): field, parent_field = field_def.field, None if field: if field.components: for component in field.components: # Render it's raw value cmp_raw_value = component.render(raw_value) if component.accumulate: accumulator = self._accumulators[def_mesg.mesg_num] cmp_raw_value = self._apply_compressed_accumulation( cmp_raw_value, accumulator[component.def_num], component.bits, ) accumulator[component.def_num] = cmp_raw_value # Apply scale and offset from component, not from the dynamic field # as they may differ cmp_raw_value = self._apply_scale_offset(component, cmp_raw_value) # Extract the component's dynamic field from def_mesg cmp_field = def_mesg.mesg_type.fields[component.def_num] # Resolve a possible subfield cmp_field, cmp_parent_field = self._resolve_subfield(cmp_field, def_mesg, raw_values) cmp_value = cmp_field.render(cmp_raw_value) # Plop it on field_datas field_datas.append( FieldData( field_def=None, field=cmp_field, parent_field=cmp_parent_field, value=cmp_value, raw_value=cmp_raw_value, ) ) else: # Component fields shouldn't also have subfields field, parent_field = self._resolve_subfield(field, def_mesg, raw_values) # TODO: Do we care about a base_type and a resolved field mismatch? # My hunch is we don't value = self._apply_scale_offset(field, field.render(raw_value)) else: value = raw_value # Update compressed timestamp field if (field_def.def_num == FIELD_TYPE_TIMESTAMP.def_num) and (raw_value is not None): self._compressed_ts_accumulator = raw_value field_datas.append( FieldData( field_def=field_def, field=field, parent_field=parent_field, value=value, raw_value=raw_value, ) ) # Apply timestamp field if we got a header if header.time_offset is not None: ts_value = self._compressed_ts_accumulator = self._apply_compressed_accumulation( header.time_offset, self._compressed_ts_accumulator, 5, ) field_datas.append( FieldData( field_def=None, field=FIELD_TYPE_TIMESTAMP, parent_field=None, value=FIELD_TYPE_TIMESTAMP.render(ts_value), raw_value=ts_value, ) ) # Apply data processors for field_data in field_datas: # Apply type name processor type_processor = getattr(self._processor, 'process_type_%s' % field_data.type.name, None) if type_processor: type_processor(field_data) # Apply field name processor field_processor = getattr(self._processor, 'process_field_%s' % field_data.name, None) if field_processor: field_processor(field_data) # Apply units name processor if field_data.units: process_func_name = 'process_units_%s' % field_data.units # Do unit name replacements padded with spaces for replace_from, replace_to in self.UNIT_NAME_TO_FUNC_REPLACEMENTS: process_func_name = process_func_name.replace( replace_from, ' %s ' % replace_to, ) # Then strip and convert spaces to underscores process_func_name = process_func_name.strip().replace(' ', '_') units_processor = getattr(self._processor, process_func_name, None) if units_processor: units_processor(field_data) data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) mesg_processor = getattr(self._processor, 'process_message_%s' % def_mesg.name, None) if mesg_processor: mesg_processor(data_message) return data_message
def _parse_data_message(self, header): def_mesg = self._local_mesgs.get(header.local_mesg_num) if not def_mesg: raise FitParseError('Got data message with invalid local message type %d' % ( header.local_mesg_num)) raw_values = self._parse_raw_values_from_data_message(def_mesg) field_datas = [] # TODO: I don't love this name, update on DataMessage too # TODO: Maybe refactor this and make it simpler (or at least broken # up into sub-functions) for field_def, raw_value in zip(def_mesg.field_defs + def_mesg.dev_field_defs, raw_values): field, parent_field = field_def.field, None if field: field, parent_field = self._resolve_subfield(field, def_mesg, raw_values) # Resolve component fields if field.components: for component in field.components: # Render its raw value cmp_raw_value = component.render(raw_value) # Apply accumulated value if component.accumulate and cmp_raw_value is not None: accumulator = self._accumulators[def_mesg.mesg_num] cmp_raw_value = self._apply_compressed_accumulation( cmp_raw_value, accumulator[component.def_num], component.bits, ) accumulator[component.def_num] = cmp_raw_value # Apply scale and offset from component, not from the dynamic field # as they may differ cmp_raw_value = self._apply_scale_offset(component, cmp_raw_value) # Extract the component's dynamic field from def_mesg cmp_field = def_mesg.mesg_type.fields[component.def_num] # Resolve a possible subfield cmp_field, cmp_parent_field = self._resolve_subfield(cmp_field, def_mesg, raw_values) cmp_value = cmp_field.render(cmp_raw_value) # Plop it on field_datas field_datas.append( FieldData( field_def=None, field=cmp_field, parent_field=cmp_parent_field, value=cmp_value, raw_value=cmp_raw_value, ) ) # TODO: Do we care about a base_type and a resolved field mismatch? # My hunch is we don't value = self._apply_scale_offset(field, field.render(raw_value)) else: value = raw_value # Update compressed timestamp field if (field_def.def_num == FIELD_TYPE_TIMESTAMP.def_num) and (raw_value is not None): self._compressed_ts_accumulator = raw_value field_datas.append( FieldData( field_def=field_def, field=field, parent_field=parent_field, value=value, raw_value=raw_value, ) ) # Apply timestamp field if we got a header if header.time_offset is not None: ts_value = self._compressed_ts_accumulator = self._apply_compressed_accumulation( header.time_offset, self._compressed_ts_accumulator, 5, ) field_datas.append( FieldData( field_def=None, field=FIELD_TYPE_TIMESTAMP, parent_field=None, value=FIELD_TYPE_TIMESTAMP.render(ts_value), raw_value=ts_value, ) ) # Apply data processors for field_data in field_datas: # Apply type name processor self._processor.run_type_processor(field_data) self._processor.run_field_processor(field_data) self._processor.run_unit_processor(field_data) data_message = DataMessage(header=header, def_mesg=def_mesg, fields=field_datas) self._processor.run_message_processor(data_message) return data_message