fit_parser 0.0.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ce4c1fb626d5bb6a55bb391a1e7866d3ebd1731
4
- data.tar.gz: 1c3c23c7559acfd7a53b60e89444770fc08768e7
3
+ metadata.gz: c5a9b2aa672b5b76113b211fe1cb1f9ee699abd2
4
+ data.tar.gz: 71dc6534e61ca9a129f05f508973c4cbc78880da
5
5
  SHA512:
6
- metadata.gz: 66c26eab5d161cd18e02d9d47732614ba61ee84a681df341e6837440deb13fb758c3d7485d202f3bd5da901b4f9946934a010f0f1c4f3752a46d3cdb3e30d7c8
7
- data.tar.gz: dd7968418eed7a3cc97c5aeea89ded49b45ea72f7f066e9e669003529c9d958eb63299fe30a7858dac9aa238d5f0476e41c7b60b6e3632030180d1e2a5b75b0e
6
+ metadata.gz: 1ebd8c2da5930fc9bbd21d3110c6575f2e4e18fdbe030b548ee589d02a5073872bb736770fb460c1ad5f56507f4e76c879f44f71d639362f88816f2b57a38250
7
+ data.tar.gz: e51a26600a8bbefab0550e85a8507fa31224cdc78b2c0b58770313e7235f15e3d3df3917ad37aad9ff2744056d6060e459b1406fc588ca3b599546d11aea1557
@@ -0,0 +1,28 @@
1
+ # Override DSLFieldValidator#ensure_valid_name from bindata/lib/dsl.rb
2
+ # gem bindata
3
+ # because we should not raise error on duplicate name
4
+ module BinData
5
+ module DSLMixin
6
+ class DSLFieldValidator
7
+ def ensure_valid_name(name)
8
+ if name and not option?(:fieldnames_are_values)
9
+ if malformed_name?(name)
10
+ raise NameError.new("", name), "field '#{name}' is an illegal fieldname"
11
+ end
12
+
13
+ if duplicate_name?(name)
14
+ # raise SyntaxError, "duplicate field '#{name}'"
15
+ end
16
+
17
+ if name_shadows_method?(name)
18
+ raise NameError.new("", name), "field '#{name}' shadows an existing method"
19
+ end
20
+
21
+ if name_is_reserved?(name)
22
+ raise NameError.new("", name), "field '#{name}' is a reserved name"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -2,13 +2,15 @@ module FitParser
2
2
  class File
3
3
  class Data < BinData::Record
4
4
  class_attribute :global_message_number, instance_writer: false
5
+ class_attribute :dev_definitions, instance_writer: false
5
6
 
6
- def self.generate(definition)
7
+ def self.generate(definition, dev_definitions = nil)
7
8
  msg_num = definition.global_message_number.snapshot
8
9
  type = Definitions.get_name(msg_num) || "data_record_#{msg_num}"
9
10
 
10
11
  Class.new(self) do
11
12
  self.global_message_number = msg_num
13
+ self.dev_definitions = dev_definitions
12
14
 
13
15
  endian definition.endianness
14
16
 
@@ -36,7 +38,57 @@ module FitParser
36
38
  code << "def #{field.name}\n"
37
39
 
38
40
  if field.scale && field.scale != 1
39
- code << "scale = #{field.scale.inspect}.0\n"
41
+ scale = field.scale
42
+ if scale.is_a?(Integer)
43
+ code << "scale = #{scale.inspect}.0\n"
44
+ else
45
+ code << "scale = #{scale.inspect}\n"
46
+ end
47
+ else
48
+ code << "scale = nil\n"
49
+ end
50
+
51
+ if field.dyn_data
52
+ code << "dyn = #{field.dyn_data}\n"
53
+ else
54
+ code << "dyn = nil\n"
55
+ end
56
+ code << <<-RUBY
57
+ get_value #{field.raw_name}.snapshot, '#{field.real_type}', scale, dyn
58
+ end
59
+ RUBY
60
+
61
+ class_eval code, __FILE__, __LINE__ + 1
62
+ end
63
+
64
+ definition.dev_fields_arr.each do |field|
65
+ data = dev_definitions[field[:developer_data_index].to_s][field[:field_number].to_s]
66
+ field.base_type_number = data[:raw_field_2]
67
+ field.name = data[:raw_field_3].downcase.gsub(' ', '_')
68
+ field.scale = data[:raw_field_6] && data[:raw_field_6] != 255 ? data[:raw_field_6] : nil
69
+ code = ''
70
+
71
+ # in case the field size is a multiple of the field length, we must build an array
72
+ if field.type != 'string' && field.field_size > field.length
73
+ code << "array :#{field.raw_name}, :type => :#{field.type}, :initial_length => #{field.field_size/field.length}\n"
74
+ else
75
+ # string are not null terminated when they have exactly the lenght of the field
76
+ code << "#{field.type} :#{field.raw_name}"
77
+ if field.type == 'string'
78
+ code << ", :read_length => #{field.field_size}, :trim_padding => true"
79
+ end
80
+ code << "\n"
81
+ end
82
+
83
+ code << "def #{field.name}\n"
84
+
85
+ if field.scale && field.scale != 1
86
+ scale = field.scale
87
+ if scale.is_a?(Integer)
88
+ code << "scale = #{scale.inspect}.0\n"
89
+ else
90
+ code << "scale = #{scale.inspect}\n"
91
+ end
40
92
  else
41
93
  code << "scale = nil\n"
42
94
  end
@@ -1,6 +1,82 @@
1
1
  module FitParser
2
2
  class File
3
3
  class Definition < BinData::Record
4
+ class DevField < BinData::Record
5
+ uint8 :field_number
6
+ uint8 :field_size
7
+ uint8 :developer_data_index
8
+
9
+ attr_accessor :base_type_number, :name, :scale
10
+
11
+ def raw_name
12
+ "raw_#{name}"
13
+ end
14
+
15
+ def dyn_data
16
+ nil
17
+ end
18
+
19
+ def type
20
+ case base_type_number
21
+ when 0 # enum
22
+ build_int_type 8, false
23
+ when 1 # sint8
24
+ build_int_type 8, true
25
+ when 2 # uint8
26
+ build_int_type 8, false
27
+ when 131 # sint16
28
+ build_int_type 16, true
29
+ when 132 # uint16
30
+ build_int_type 16, false
31
+ when 133 # sint32
32
+ build_int_type 32, true
33
+ when 134 # uint32
34
+ build_int_type 32, false
35
+ when 7 # string
36
+ # some cases found where string has the max field length
37
+ # and is therefore not null terminated
38
+ @length = 1
39
+ 'string'
40
+ when 136 # float32
41
+ @length = 4
42
+ 'float'
43
+ when 137 # float64
44
+ @length = 8
45
+ 'double'
46
+ when 10 # uint8z
47
+ build_int_type 8, false
48
+ when 139 # uint16z
49
+ build_int_type 16, false
50
+ when 140 # uint32z
51
+ build_int_type 32, false
52
+ when 13 # array of bytes
53
+ build_int_type 8, false
54
+ when 142 # sint64
55
+ build_int_type 64, true
56
+ when 143 # uint64
57
+ build_int_type 64, false
58
+ when 144 # uint64z
59
+ build_int_type 64, false
60
+ else
61
+ fail "Can't map base_type_number #{base_type_number} to a data type"
62
+ end
63
+ end
64
+ alias :real_type :type
65
+
66
+ # return the length in byte of the given type
67
+ def length
68
+ @length
69
+ end
70
+
71
+ private
72
+
73
+ def build_int_type(length, signed)
74
+ # @length is in byte not in bits, so divide by 8
75
+ @length = length / 8
76
+ (signed ? '' : 'u') << 'int' << length.to_s
77
+ end
78
+ end
79
+
4
80
  class Field < BinData::Record
5
81
  hide :reserved_bits
6
82
 
@@ -72,6 +148,12 @@ module FitParser
72
148
  build_int_type 32, false
73
149
  when 13 # array of bytes
74
150
  build_int_type 8, false
151
+ when 14 # sint64
152
+ build_int_type 64, true
153
+ when 15 # uint64
154
+ build_int_type 64, false
155
+ when 16 # uint64z
156
+ build_int_type 64, false
75
157
  else
76
158
  fail "Can't map base_type_number #{base_type_number} to a data type"
77
159
  end
@@ -104,6 +186,21 @@ module FitParser
104
186
  end
105
187
  bit8 :field_count
106
188
  array :fields_arr, type: Field, initial_length: :field_count
189
+ bit8 :dev_field_count, :onlyif => :dev_data_flag?
190
+ array :dev_fields_arr, type: DevField, initial_length: :dev_field_count, :onlyif => :dev_data_flag?
191
+
192
+ def self.attributes
193
+ @attributes ||= Hash.new { |h, k| h[k] = {} }
194
+ end
195
+
196
+ def self.attributes=(val)
197
+ @attributes = val
198
+ end
199
+
200
+ def self.read(io, attrs = {})
201
+ self.attributes = attrs
202
+ super(io)
203
+ end
107
204
 
108
205
  def endianness
109
206
  architecture.snapshot == 0 ? :little : :big
@@ -112,6 +209,12 @@ module FitParser
112
209
  def record_type
113
210
  :definition
114
211
  end
212
+
213
+ def dev_data_flag?
214
+ dev_data_flag = Definition.attributes[:dev_data_flag]
215
+ return true if dev_data_flag && dev_data_flag == 1
216
+ false
217
+ end
115
218
  end
116
219
  end
117
220
  end
@@ -70,6 +70,7 @@ FitParser::File::Definitions.add_field(0, 2, 'garmin_product', type: :garmin_pro
70
70
  FitParser::File::Definitions.add_field(0, 3, 'serial_number', type: :uint32z)
71
71
  FitParser::File::Definitions.add_field(0, 4, 'time_created', type: :date_time)
72
72
  FitParser::File::Definitions.add_field(0, 5, 'number', type: :uint16)
73
+ FitParser::File::Definitions.add_field(0, 8, 'product_number', type: :string)
73
74
 
74
75
  FitParser::File::Definitions.add_name(49, 'file_creator')
75
76
  FitParser::File::Definitions.add_field(49, 0, 'software_version', type: :uint16)
@@ -119,7 +120,26 @@ FitParser::File::Definitions.add_field 39, 3, 'count', type: :uint16
119
120
  FitParser::File::Definitions.add_name 2, 'device_settings'
120
121
  FitParser::File::Definitions.add_field 2, 0, 'active_time_zone', type: :uint8, scale: 1
121
122
  FitParser::File::Definitions.add_field 2, 1, 'utc_offset', type: :uint32
123
+ FitParser::File::Definitions.add_field 2, 2, 'time_offset', type: :uint32
124
+ FitParser::File::Definitions.add_field 2, 4, 'time_mode', type: :type_mode
122
125
  FitParser::File::Definitions.add_field 2, 5, 'time_zone_offset', type: :sint8, scale: 4, unit: 'hr'
126
+ FitParser::File::Definitions.add_field 2, 12, 'backlight_mode', type: :backlight_mode
127
+ FitParser::File::Definitions.add_field 2, 36, 'activity_tracker_enabled', type: :bool
128
+ FitParser::File::Definitions.add_field 2, 39, 'clock_time', type: :date_time
129
+ FitParser::File::Definitions.add_field 2, 40, 'pages_enabled', type: :uint16
130
+ FitParser::File::Definitions.add_field 2, 46, 'move_alert_enabled', type: :bool
131
+ FitParser::File::Definitions.add_field 2, 47, 'date_mode', type: :date_mode
132
+ FitParser::File::Definitions.add_field 2, 55, 'display_orientation', type: :display_orientation
133
+ FitParser::File::Definitions.add_field 2, 56, 'mounting_side', type: :side
134
+ FitParser::File::Definitions.add_field 2, 57, 'default_page', type: :uint16
135
+ FitParser::File::Definitions.add_field 2, 58, 'autosync_min_steps', type: :uint16
136
+ FitParser::File::Definitions.add_field 2, 59, 'autosync_min_time', type: :uint16
137
+ FitParser::File::Definitions.add_field 2, 80, 'lactate_threshold_autodetect_enabled', type: :bool
138
+ FitParser::File::Definitions.add_field 2, 86, 'ble_auto_upload_enabled', type: :bool
139
+ FitParser::File::Definitions.add_field 2, 89, 'auto_sync_frequency', type: :auto_sync_frequency
140
+ FitParser::File::Definitions.add_field 2, 90, 'auto_activity_detect', type: :auto_activity_detect
141
+ FitParser::File::Definitions.add_field 2, 94, 'number_of_screens', type: :uint8
142
+ FitParser::File::Definitions.add_field 2, 95, 'smart_notification_display_orientation', type: :display_orientation
123
143
 
124
144
  FitParser::File::Definitions.add_name 3, 'user_profile'
125
145
  FitParser::File::Definitions.add_field 3, 254, 'message_index', type: :message_index
@@ -145,6 +165,8 @@ FitParser::File::Definitions.add_field 3, 21, 'temperature_setting', type: :disp
145
165
  FitParser::File::Definitions.add_field 3, 22, 'local_id', type: :user_local_id
146
166
  FitParser::File::Definitions.add_field 3, 23, 'global_id', type: :byte
147
167
  FitParser::File::Definitions.add_field 3, 30, 'height_setting', type: :display_measure
168
+ FitParser::File::Definitions.add_field 3, 31, 'user_running_step_length', type: :uint16, scale: 1000, unit: 'm'
169
+ FitParser::File::Definitions.add_field 3, 32, 'user_walking_step_length', type: :uint16, scale: 1000, unit: 'm'
148
170
 
149
171
  FitParser::File::Definitions.add_name 4, 'hrm_profile'
150
172
  FitParser::File::Definitions.add_field 4, 254, 'message_index', type: :message_index, scale: 1
@@ -195,6 +217,7 @@ FitParser::File::Definitions.add_field 6, 38, 'front_gear_num', type: :uint8z
195
217
  FitParser::File::Definitions.add_field 6, 39, 'front_gear', type: :uint8z
196
218
  FitParser::File::Definitions.add_field 6, 40, 'rear_gear_num', type: :uint8z
197
219
  FitParser::File::Definitions.add_field 6, 41, 'rear_gear', type: :uint8z
220
+ FitParser::File::Definitions.add_field 6, 44, 'shimano_di2_enabled', type: :bool
198
221
 
199
222
  FitParser::File::Definitions.add_name 7, 'zones_target'
200
223
  FitParser::File::Definitions.add_field 7, 1, 'max_heart_rate', type: :uint8, scale: 1
@@ -247,6 +270,7 @@ FitParser::File::Definitions.add_field 15, 7, 'target_value', type: :uint32, sca
247
270
  FitParser::File::Definitions.add_field 15, 8, 'recurrence', type: :goal_recurrence, scale: 1
248
271
  FitParser::File::Definitions.add_field 15, 9, 'recurrence_value', type: :uint16, scale: 1
249
272
  FitParser::File::Definitions.add_field 15, 10, 'enabled', type: :bool, scale: 1
273
+ FitParser::File::Definitions.add_field 15, 11, 'source', type: :goal_source
250
274
 
251
275
  FitParser::File::Definitions.add_name 34, 'activity'
252
276
  FitParser::File::Definitions.add_field 34, 253, 'timestamp', type: :date_time
@@ -354,6 +378,31 @@ FitParser::File::Definitions.add_field 18, 102, 'avg_right_torque_effectiveness'
354
378
  FitParser::File::Definitions.add_field 18, 103, 'avg_left_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
355
379
  FitParser::File::Definitions.add_field 18, 104, 'avg_right_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
356
380
  FitParser::File::Definitions.add_field 18, 105, 'avg_combined_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
381
+ FitParser::File::Definitions.add_field 18, 111, 'sport_index', type: :uint8
382
+ FitParser::File::Definitions.add_field 18, 112, 'time_standing', type: :uint32, scale: 1000, units: 's'
383
+ FitParser::File::Definitions.add_field 18, 113, 'stand_count', type: :uint16
384
+ FitParser::File::Definitions.add_field 18, 114, 'avg_left_pco', type: :sint8, units: 'mm'
385
+ FitParser::File::Definitions.add_field 18, 115, 'avg_right_pco', type: :sint8, units: 'mm'
386
+ FitParser::File::Definitions.add_field 18, 116, 'avg_left_power_phase', type: :uint8, scale: 0.7111111, units: 'degrees'
387
+ FitParser::File::Definitions.add_field 18, 117, 'avg_left_power_phase_peak', type: :uint8, scale: 0.7111111, units: 'degrees'
388
+ FitParser::File::Definitions.add_field 18, 118, 'avg_right_power_phase', type: :uint8, scale: 0.7111111, units: 'degrees'
389
+ FitParser::File::Definitions.add_field 18, 119, 'avg_right_power_phase_peak', type: :uint8, scale: 0.7111111, units: 'degrees'
390
+ FitParser::File::Definitions.add_field 18, 120, 'avg_power_position', type: :uint16, units: 'watts'
391
+ FitParser::File::Definitions.add_field 18, 121, 'max_power_position', type: :uint16, units: 'watts'
392
+ FitParser::File::Definitions.add_field 18, 122, 'avg_cadence_position', type: :uint8, units: 'rpm'
393
+ FitParser::File::Definitions.add_field 18, 123, 'max_cadence_position', type: :uint8, units: 'rpm'
394
+ FitParser::File::Definitions.add_field 18, 124, 'enhanced_avg_speed', type: :uint32, scale: 1000, units: 'm/s'
395
+ FitParser::File::Definitions.add_field 18, 125, 'enhanced_max_speed', type: :uint32, scale: 1000, units: 'm/s'
396
+ FitParser::File::Definitions.add_field 18, 126, 'enhanced_avg_altitude', type: :uint32, scale: 5, offset: 500, units: 'm'
397
+ FitParser::File::Definitions.add_field 18, 127, 'enhanced_min_altitude', type: :uint32, scale: 5, offset: 500, units: 'm'
398
+ FitParser::File::Definitions.add_field 18, 128, 'enhanced_max_altitude', type: :uint32, scale: 5, offset: 500, units: 'm'
399
+ FitParser::File::Definitions.add_field 18, 129, 'avg_lev_motor_power', type: :uint16, units: 'watts'
400
+ FitParser::File::Definitions.add_field 18, 130, 'max_lev_motor_power', type: :uint16, units: 'watts'
401
+ FitParser::File::Definitions.add_field 18, 131, 'lev_battery_consumption', type: :uint8, scale: 2, units: 'percent'
402
+ FitParser::File::Definitions.add_field 18, 132, 'avg_vertical_ratio', type: :uint16, scale: 100, units: 'percent'
403
+ FitParser::File::Definitions.add_field 18, 133, 'avg_stance_time_balance', type: :uint16, scale: 100, units: 'percent'
404
+ FitParser::File::Definitions.add_field 18, 134, 'avg_step_length', type: :uint16, scale: 10, units: 'mm'
405
+ FitParser::File::Definitions.add_field 18, 137, 'total_anaerobic_training_effect', type: :uint8, scale: 10
357
406
 
358
407
  FitParser::File::Definitions.add_name 19, 'lap'
359
408
  FitParser::File::Definitions.add_field 19, 254, 'message_index', type: :message_index, scale: 1
@@ -441,6 +490,29 @@ FitParser::File::Definitions.add_field 19, 92, 'avg_right_torque_effectiveness',
441
490
  FitParser::File::Definitions.add_field 19, 93, 'avg_left_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
442
491
  FitParser::File::Definitions.add_field 19, 94, 'avg_right_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
443
492
  FitParser::File::Definitions.add_field 19, 95, 'avg_combined_pedal_smoothness', type: :uint8, scale: 2, unit: 'percent'
493
+ FitParser::File::Definitions.add_field 19, 98, 'time_standing', type: :uint32, scale: 1000, unit: 's'
494
+ FitParser::File::Definitions.add_field 19, 99, 'stand_count', type: :uint16
495
+ FitParser::File::Definitions.add_field 19, 100, 'avg_left_pco', type: :sint8, unit: 'mm'
496
+ FitParser::File::Definitions.add_field 19, 101, 'avg_right_pco', type: :sint8, unit: 's'
497
+ FitParser::File::Definitions.add_field 19, 102, 'avg_left_power_phase', type: :uint8, scale: 0.7111111, unit: 'degrees'
498
+ FitParser::File::Definitions.add_field 19, 103, 'avg_left_power_phase_peak', type: :uint8, scale: 0.7111111, unit: 'degrees'
499
+ FitParser::File::Definitions.add_field 19, 104, 'avg_right_power_phase', type: :uint8, scale: 0.7111111, unit: 'degrees'
500
+ FitParser::File::Definitions.add_field 19, 105, 'avg_right_power_phase_peak', type: :uint8, scale: 0.7111111, unit: 'degrees'
501
+ FitParser::File::Definitions.add_field 19, 106, 'avg_power_position', type: :uint16, unit: 'watts'
502
+ FitParser::File::Definitions.add_field 19, 107, 'max_power_position', type: :uint16, unit: 'watts'
503
+ FitParser::File::Definitions.add_field 19, 108, 'avg_cadence_position', type: :uint8, unit: 'rpm'
504
+ FitParser::File::Definitions.add_field 19, 109, 'max_cadence_position', type: :uint8, unit: 'rpm'
505
+ FitParser::File::Definitions.add_field 19, 110, 'enhanced_avg_speed', type: :uint32, scale: 1000, unit: 'm/s'
506
+ FitParser::File::Definitions.add_field 19, 111, 'enhanced_max_speed', type: :uint32, scale: 1000, unit: 'm/s'
507
+ FitParser::File::Definitions.add_field 19, 112, 'enhanced_avg_altitude', type: :uint32, scale: 5, offset: 500, unit: 'm'
508
+ FitParser::File::Definitions.add_field 19, 113, 'enhanced_min_altitude', type: :uint32, scale: 5, offset: 500, unit: 'm'
509
+ FitParser::File::Definitions.add_field 19, 114, 'enhanced_max_altitude', type: :uint32, scale: 5, offset: 500, unit: 'm'
510
+ FitParser::File::Definitions.add_field 19, 115, 'avg_lev_motor_power', type: :uint16, unit: 'watts'
511
+ FitParser::File::Definitions.add_field 19, 116, 'max_lev_motor_power', type: :uint16, unit: 'watts'
512
+ FitParser::File::Definitions.add_field 19, 117, 'lev_battery_consumption', type: :uint8, scale: 2, unit: 'percent'
513
+ FitParser::File::Definitions.add_field 19, 118, 'avg_vertical_ratio', type: :uint16, scale: 100, unit: 'percent'
514
+ FitParser::File::Definitions.add_field 19, 119, 'avg_stance_time_balance', type: :uint16, scale: 100, unit: 'percent'
515
+ FitParser::File::Definitions.add_field 19, 120, 'avg_step_length', type: :uint16, scale: 10, unit: 'mm'
444
516
 
445
517
  FitParser::File::Definitions.add_name 101, 'length'
446
518
  FitParser::File::Definitions.add_field 101, 254, 'message_index', type: :message_index, scale: 1
@@ -509,6 +581,19 @@ FitParser::File::Definitions.add_field 20, 57, 'saturated_hemoglobin_percent', t
509
581
  FitParser::File::Definitions.add_field 20, 58, 'saturated_hemoglobin_percent_min', type: :uint16, scale: 10, unit: '%'
510
582
  FitParser::File::Definitions.add_field 20, 59, 'saturated_hemoglobin_percent_max', type: :uint16, scale: 10, unit: '%'
511
583
  FitParser::File::Definitions.add_field 20, 62, 'device_index', type: :device_index
584
+ FitParser::File::Definitions.add_field 20, 67, 'left_pco', type: :sint8, unit: 'mm'
585
+ FitParser::File::Definitions.add_field 20, 68, 'right_pco', type: :sint8, unit: 'mm'
586
+ FitParser::File::Definitions.add_field 20, 69, 'left_power_phase', type: :uint8, scale: 0.7111111, unit: 'degrees'
587
+ FitParser::File::Definitions.add_field 20, 70, 'left_power_phase_peak', type: :uint8, scale: 0.7111111, unit: 'degrees'
588
+ FitParser::File::Definitions.add_field 20, 71, 'right_power_phase', type: :uint8, scale: 0.7111111, unit: 'degrees'
589
+ FitParser::File::Definitions.add_field 20, 72, 'right_power_phase_peak', type: :uint8, scale: 0.7111111, unit: 'degrees'
590
+ FitParser::File::Definitions.add_field 20, 73, 'enhanced_speed', type: :uint32, scale: 1000, unit: 'm/s'
591
+ FitParser::File::Definitions.add_field 20, 78, 'enhanced_altitude', type: :uint32, scale: 5, offset: 500, unit: 'm'
592
+ FitParser::File::Definitions.add_field 20, 81, 'battery_soc', type: :uint8, scale: 2, unit: 'percent'
593
+ FitParser::File::Definitions.add_field 20, 82, 'motor_power', type: :uint16, unit: 'watts'
594
+ FitParser::File::Definitions.add_field 20, 83, 'vertical_ratio', type: :uint16, scale: 100, unit: 'percent'
595
+ FitParser::File::Definitions.add_field 20, 84, 'stance_time_balance', type: :uint16, scale: 100, unit: 'percent'
596
+ FitParser::File::Definitions.add_field 20, 85, 'step_length', type: :uint16, scale: 10, unit: 'mm'
512
597
 
513
598
  FitParser::File::Definitions.add_name 21, 'event'
514
599
  FitParser::File::Definitions.add_field 21, 253, 'timestamp', type: :date_time, unit: 's'
@@ -541,6 +626,7 @@ FitParser::File::Definitions.add_field 21, 9, 'front_gear_num', type: :uint8z
541
626
  FitParser::File::Definitions.add_field 21, 10, 'front_gear', type: :uint8z
542
627
  FitParser::File::Definitions.add_field 21, 11, 'rear_gear_num', type: :uint8z
543
628
  FitParser::File::Definitions.add_field 21, 12, 'rear_gear', type: :uint8z
629
+ FitParser::File::Definitions.add_field 21, 13, 'device_index'
544
630
 
545
631
  FitParser::File::Definitions.add_name 23, 'device_info'
546
632
  FitParser::File::Definitions.add_field 23, 253, 'timestamp', type: :date_time, scale: 1, unit: 's'
@@ -562,6 +648,7 @@ FitParser::File::Definitions.add_field 23, 20, 'ant_transmission_type', type: :u
562
648
  FitParser::File::Definitions.add_field 23, 21, 'ant_device_number', type: :uint16z
563
649
  FitParser::File::Definitions.add_field 23, 22, 'ant_network', type: :ant_network
564
650
  FitParser::File::Definitions.add_field 23, 25, 'source_type', type: :source_type
651
+ FitParser::File::Definitions.add_field 23, 27, 'product_name', type: :string
565
652
 
566
653
  FitParser::File::Definitions.add_name 72, 'training_file'
567
654
  FitParser::File::Definitions.add_field 72, 253, 'timestamp', type: :date_time
@@ -579,6 +666,7 @@ FitParser::File::Definitions.add_name 31, 'course'
579
666
  FitParser::File::Definitions.add_field 31, 4, 'sport', type: :sport
580
667
  FitParser::File::Definitions.add_field 31, 5, 'name', type: :string
581
668
  FitParser::File::Definitions.add_field 31, 6, 'capabilities', type: :course_capabilities
669
+ FitParser::File::Definitions.add_field 31, 7, 'sub_sport', type: :sub_sport
582
670
 
583
671
  FitParser::File::Definitions.add_name 32, 'course_point'
584
672
  FitParser::File::Definitions.add_field 32, 254, 'message_index', type: :message_index
@@ -588,6 +676,7 @@ FitParser::File::Definitions.add_field 32, 3, 'position_long', type: :sint32, sc
588
676
  FitParser::File::Definitions.add_field 32, 4, 'distance', type: :uint32, scale: 100, unit: 'm'
589
677
  FitParser::File::Definitions.add_field 32, 5, 'type', type: :course_point, scale: 1
590
678
  FitParser::File::Definitions.add_field 32, 6, 'name', type: :string
679
+ FitParser::File::Definitions.add_field 32, 8, 'favorite', type: :bool
591
680
 
592
681
  FitParser::File::Definitions.add_name 26, 'workout'
593
682
  FitParser::File::Definitions.add_field 26, 4, 'sport', type: :sport, scale: 1
@@ -648,6 +737,7 @@ FitParser::File::Definitions.add_field 33, 3, 'sport', type: :sport
648
737
  FitParser::File::Definitions.add_field 33, 4, 'elapsed_time', type: :uint32, unit: 's'
649
738
  FitParser::File::Definitions.add_field 33, 5, 'sessions', type: :uint16
650
739
  FitParser::File::Definitions.add_field 33, 6, 'active_time', type: :uint32, unit: 's'
740
+ FitParser::File::Definitions.add_field 33, 9, 'sport_index', type: :uint8
651
741
 
652
742
  FitParser::File::Definitions.add_name 30, 'weight_scale'
653
743
  FitParser::File::Definitions.add_field 30, 253, 'timestamp', type: :date_time, scale: 1, unit: 's'
@@ -712,7 +802,11 @@ FitParser::File::Definitions.add_field 55, 26, 'timestamp_16', type: :uint16, un
712
802
  FitParser::File::Definitions.add_field 55, 27, 'heart_rate', type: :uint8, unit: 'bpm'
713
803
  FitParser::File::Definitions.add_field 55, 28, 'intensity', type: :uint8, scale: 10
714
804
  FitParser::File::Definitions.add_field 55, 29, 'duration_min', type: :uint16, unit: 'min'
715
- FitParser::File::Definitions.add_field(55, 30, 'duration', type: :uint32, unit: 's')
805
+ FitParser::File::Definitions.add_field 55, 30, 'duration', type: :uint32, unit: 's'
806
+ FitParser::File::Definitions.add_field 55, 31, 'ascent', type: :uint32, scale: 1000, unit: 'm'
807
+ FitParser::File::Definitions.add_field 55, 32, 'descent', type: :uint32, scale: 1000, unit: 'm'
808
+ FitParser::File::Definitions.add_field 55, 33, 'moderate_activity_minutes', type: :uint16, unit: 'minutes'
809
+ FitParser::File::Definitions.add_field 55, 34, 'vigorous_activity_minutes', type: :uint16, unit: 'minutes'
716
810
 
717
811
  FitParser::File::Definitions.add_name(145, 'memo_glob')
718
812
  FitParser::File::Definitions.add_field(145, 250, 'part_index', type: :uint32)
@@ -3,8 +3,9 @@ module FitParser
3
3
  class Record
4
4
  attr_reader :header, :content, :definitions
5
5
 
6
- def initialize(definitions)
6
+ def initialize(definitions, dev_definitions)
7
7
  @definitions = definitions
8
+ @dev_definitions = dev_definitions
8
9
  end
9
10
 
10
11
  def read(io)
@@ -12,8 +13,12 @@ module FitParser
12
13
 
13
14
  @content = case @header.message_type.snapshot
14
15
  when 1
15
- Definition.read(io).tap do |definition|
16
- @definitions[@header.local_message_type.snapshot] = Data.generate(definition)
16
+ Definition.read(io, { dev_data_flag: @header.dev_data_flag }).tap do |definition|
17
+ if @header.dev_data_flag == 1
18
+ @definitions[@header.local_message_type.snapshot] = Data.generate(definition, @dev_definitions)
19
+ else
20
+ @definitions[@header.local_message_type.snapshot] = Data.generate(definition)
21
+ end
17
22
  end
18
23
  when 0
19
24
  definition = @definitions[@header.local_message_type.snapshot]
@@ -6,7 +6,8 @@ module FitParser
6
6
  bit1 :header_type
7
7
 
8
8
  bit1 :message_type, :onlyif => :normal?
9
- bit2 :reserved_bits, :onlyif => :normal?
9
+ bit1 :dev_data_flag, :onlyif => :normal?
10
+ bit1 :reserved_bits, :onlyif => :normal?
10
11
 
11
12
  choice :local_message_type, :selection => :header_type do
12
13
  bit4 0