fit4ruby 3.1.0 → 3.2.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 +4 -4
- data/lib/fit4ruby/Activity.rb +1 -1
- data/lib/fit4ruby/FieldDescription.rb +4 -2
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +39 -5
- data/lib/fit4ruby/FitFileEntity.rb +4 -0
- data/lib/fit4ruby/FitMessageRecord.rb +34 -1
- data/lib/fit4ruby/GlobalFitDictionaries.rb +27 -0
- data/lib/fit4ruby/GlobalFitMessages.rb +178 -20
- data/lib/fit4ruby/Metrics.rb +78 -0
- data/lib/fit4ruby/TrainingStatus.rb +46 -0
- data/lib/fit4ruby/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 247b4e5fd81ffc3c5e12bc1d3235196126fdb8cc
|
4
|
+
data.tar.gz: b493e5b073e63d977ed28edc3600dac73519d0b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88b2fe75bdf8a1bfb4a6f3d4892db4253f942a3a251118fc054f4671f9f3927960552fe9005334da6f884e95990babae029071edbf287740efaff2450748824b
|
7
|
+
data.tar.gz: f8aa4152a1d37f682d0ca526045d10a19628ba79bad41eebbf3b3e3e963fcb971fc82d38fef8756b2bfa50eaefd3eea80388c849cb1bc0bf34aa79d64754e7eb
|
data/lib/fit4ruby/Activity.rb
CHANGED
@@ -264,7 +264,7 @@ module Fit4Ruby
|
|
264
264
|
# Then check the user_data entries for a metmax entry. METmax * 3.5
|
265
265
|
# is same value as VO2max.
|
266
266
|
@user_data.each do |u|
|
267
|
-
return
|
267
|
+
return u.metmax * 3.5 if u.metmax
|
268
268
|
end
|
269
269
|
|
270
270
|
nil
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FieldDescription.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2017, 2018 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2017, 2018, 2019 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -32,17 +32,20 @@ module Fit4Ruby
|
|
32
32
|
unless (gfm = GlobalFitMessages[@native_mesg_num])
|
33
33
|
Log.error "Developer field description references unknown global " +
|
34
34
|
"message number #{@native_mesg_num}"
|
35
|
+
return
|
35
36
|
end
|
36
37
|
|
37
38
|
if @developer_data_index >=
|
38
39
|
fit_entity.top_level_record.developer_data_ids.size
|
39
40
|
Log.error "Developer data index #{@developer_data_index} is too large"
|
41
|
+
return
|
40
42
|
end
|
41
43
|
|
42
44
|
msg = messages[@native_mesg_num] ||
|
43
45
|
messages.message(@native_mesg_num, gfm.name)
|
44
46
|
unless (@fit_base_type_id & 0x7F) < FIT_TYPE_DEFS.size
|
45
47
|
Log.error "fit_base_type_id #{@fit_base_type_id} is too large"
|
48
|
+
return
|
46
49
|
end
|
47
50
|
options = {}
|
48
51
|
options[:scale] = @scale if @scale
|
@@ -58,4 +61,3 @@ module Fit4Ruby
|
|
58
61
|
|
59
62
|
end
|
60
63
|
|
61
|
-
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitDeveloperDataFieldDefinition.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2017, 2018 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2017, 2018, 2019 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -41,22 +41,56 @@ module Fit4Ruby
|
|
41
41
|
size_in_bytes
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
def undefined_value
|
45
|
+
FIT_TYPE_DEFS[checked_base_type_number][2]
|
46
|
+
end
|
45
47
|
|
46
48
|
def find_field_definition
|
49
|
+
return @field_definition if @field_definition
|
50
|
+
|
47
51
|
tlr = parent.parent.fit_entity.top_level_record
|
48
|
-
|
52
|
+
@field_definition = tlr.field_descriptions.find do |fd|
|
49
53
|
fd.field_definition_number == field_number.snapshot &&
|
50
54
|
fd.developer_data_index == developer_data_index.snapshot
|
51
55
|
end
|
52
|
-
unless
|
56
|
+
unless @field_definition
|
53
57
|
Log.error "Unknown developer field #{field_number.snapshot} " +
|
54
58
|
"for developer #{developer_data_index.snapshot}"
|
59
|
+
return nil
|
55
60
|
end
|
56
61
|
|
57
|
-
|
62
|
+
@field_definition
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s(value)
|
66
|
+
return '' if value.nil?
|
67
|
+
|
68
|
+
if (field_definition = find_field_definition)
|
69
|
+
"#{value} #{find_field_definition.units}"
|
70
|
+
else
|
71
|
+
if value.kind_of?(Array)
|
72
|
+
s = '[ '
|
73
|
+
value.each do |v|
|
74
|
+
v /= @field_def.scale.to_f if @field_def.scale
|
75
|
+
v -= @fielid_def.offset if @field_def.offset
|
76
|
+
s << to_s(v) + ' '
|
77
|
+
end
|
78
|
+
s + ']'
|
79
|
+
|
80
|
+
return s
|
81
|
+
else
|
82
|
+
field_number = field_definition_number.snapshot
|
83
|
+
|
84
|
+
value /= @field_def.scale.to_f if @field_def.scale
|
85
|
+
value -= @fielid_def.offset if @field_def.offset
|
86
|
+
|
87
|
+
return value.to_s
|
88
|
+
end
|
89
|
+
end
|
58
90
|
end
|
59
91
|
|
92
|
+
private
|
93
|
+
|
60
94
|
def checked_base_type_number
|
61
95
|
field = find_field_definition
|
62
96
|
base_type_number = field.fit_base_type_id & 0x7F
|
@@ -13,6 +13,7 @@
|
|
13
13
|
require 'fit4ruby/Activity'
|
14
14
|
require 'fit4ruby/Monitoring_B'
|
15
15
|
require 'fit4ruby/GlobalFitMessage'
|
16
|
+
require 'fit4ruby/Metrics'
|
16
17
|
|
17
18
|
module Fit4Ruby
|
18
19
|
|
@@ -49,6 +50,9 @@ module Fit4Ruby
|
|
49
50
|
when 32, 'monitoring_b'
|
50
51
|
@top_level_record = Monitoring_B.new
|
51
52
|
@type = 'monitoring_b'
|
53
|
+
when 44, 'metrics'
|
54
|
+
@top_level_record = Metrics.new
|
55
|
+
@type = 'metrics'
|
52
56
|
else
|
53
57
|
Log.error "Unsupported FIT file type #{type}"
|
54
58
|
return nil
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitMessageRecord.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2015, 2018, 2019 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -98,6 +98,39 @@ module Fit4Ruby
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
@definition.developer_fields.each do |field|
|
102
|
+
# Find the corresponding field description for the given developer and
|
103
|
+
# field number.
|
104
|
+
field_number = field.field_number.snapshot
|
105
|
+
|
106
|
+
unless (field_description = field.find_field_definition)
|
107
|
+
Log.error "There is no field definition for developer " +
|
108
|
+
"#{field.developer_data_index} field #{field_number}"
|
109
|
+
next
|
110
|
+
end
|
111
|
+
|
112
|
+
field_name = field_description.field_name
|
113
|
+
units = field_description.units
|
114
|
+
type = field.type
|
115
|
+
native_message_number = field_description.native_mesg_num
|
116
|
+
native_field_number = field_description.native_field_num
|
117
|
+
|
118
|
+
value = @message_record[field.name].snapshot
|
119
|
+
value = nil if value == field.undefined_value
|
120
|
+
|
121
|
+
if filter && fields_dump &&
|
122
|
+
(filter.field_names.nil? ||
|
123
|
+
filter.field_names.include?(field_name)) &&
|
124
|
+
!(((value.respond_to?('count') &&
|
125
|
+
(value.count(field.undefined_value) == value.length)) ||
|
126
|
+
value == field.undefined_value) && filter.ignore_undef)
|
127
|
+
fields_dump << DumpedField.new(
|
128
|
+
native_message_number,
|
129
|
+
256 * (1 + field.developer_data_index) + field_number,
|
130
|
+
field_name, type, field.to_s(value))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
101
134
|
if @name == 'field_description'
|
102
135
|
obj.create_global_definition(fit_entity)
|
103
136
|
end
|
@@ -75,6 +75,10 @@ module Fit4Ruby
|
|
75
75
|
entry 4, 'low'
|
76
76
|
entry 5, 'critical'
|
77
77
|
|
78
|
+
dict 'date_mode'
|
79
|
+
entry 0, 'day_month'
|
80
|
+
entry 1, 'month_day'
|
81
|
+
|
78
82
|
dict 'body_location'
|
79
83
|
entry 0, 'left_leg'
|
80
84
|
entry 1, 'left_calf'
|
@@ -245,6 +249,7 @@ module Fit4Ruby
|
|
245
249
|
entry 45, 'elev_high_alert'
|
246
250
|
entry 46, 'elev_low_alert'
|
247
251
|
entry 47, 'comm_timeout'
|
252
|
+
entry 48, 'functional_threshold_power' # guess (in Watt)
|
248
253
|
entry 49, 'lactate_threshold_heart_rate' # guess (in BPM)
|
249
254
|
entry 50, 'lactate_threshold_speed' # guess (in m/s)
|
250
255
|
|
@@ -276,6 +281,10 @@ module Fit4Ruby
|
|
276
281
|
entry 20, 'activity_summary'
|
277
282
|
entry 28, 'monitoring_daily'
|
278
283
|
entry 32, 'monitoring_b'
|
284
|
+
entry 34, 'segment'
|
285
|
+
entry 35, 'segment_list'
|
286
|
+
entry 40, 'exd_configuration'
|
287
|
+
entry 44, 'metrics'
|
279
288
|
|
280
289
|
dict 'fitness_equipment_state'
|
281
290
|
entry 0, 'ready'
|
@@ -344,6 +353,8 @@ module Fit4Ruby
|
|
344
353
|
entry 2593, 'running_dynamics_pod'
|
345
354
|
entry 2691, 'fr935'
|
346
355
|
entry 2697, 'fenix5'
|
356
|
+
entry 2957, 'fenix5_gps_galileo' # Just a guess
|
357
|
+
entry 3111, 'fenix5x_plus'
|
347
358
|
entry 10007, 'sdm4'
|
348
359
|
entry 20119, 'training_center'
|
349
360
|
entry 65532, 'android_antplus_plugin'
|
@@ -651,6 +662,22 @@ module Fit4Ruby
|
|
651
662
|
entry 59, 'obstacle '
|
652
663
|
entry 254, 'all'
|
653
664
|
|
665
|
+
dict 'training_status'
|
666
|
+
entry 0, 'overreaching'
|
667
|
+
entry 1, 'detraining'
|
668
|
+
entry 2, 'unproductive'
|
669
|
+
entry 3, 'recovery'
|
670
|
+
entry 4, 'maintaining'
|
671
|
+
entry 5, 'productive'
|
672
|
+
entry 6, 'peaking'
|
673
|
+
entry 7, 'productive'
|
674
|
+
|
675
|
+
dict 'training_status_trend'
|
676
|
+
entry 0, 'undefined'
|
677
|
+
entry 1, 'down'
|
678
|
+
entry 2, 'maintaining'
|
679
|
+
entry 3, 'up'
|
680
|
+
|
654
681
|
end
|
655
682
|
|
656
683
|
end
|
@@ -44,8 +44,12 @@ module Fit4Ruby
|
|
44
44
|
field 14, 'uint8', 'undocumented_field_14'
|
45
45
|
field 15, 'uint8', 'undocumented_field_15'
|
46
46
|
field 22, 'enum', 'undocumented_field_22'
|
47
|
+
field 23, 'enum', 'undocumented_field_23'
|
48
|
+
field 25, 'enum', 'undocumented_field_25'
|
47
49
|
field 26, 'enum', 'undocumented_field_26'
|
48
50
|
field 28, 'enum', 'undocumented_field_28'
|
51
|
+
field 30, 'enum', 'undocumented_field_30'
|
52
|
+
field 31, 'enum', 'undocumented_field_31'
|
49
53
|
field 34, 'enum', 'undocumented_field_34'
|
50
54
|
field 35, 'enum', 'undocumented_field_35'
|
51
55
|
field 36, 'enum', 'activity_tracker_enabled'
|
@@ -56,6 +60,7 @@ module Fit4Ruby
|
|
56
60
|
field 44, 'enum', 'undocumented_field_44'
|
57
61
|
field 45, 'enum', 'undocumented_field_45'
|
58
62
|
field 46, 'enum', 'move_alert_enabled'
|
63
|
+
field 47, 'enum', 'date_mode'
|
59
64
|
field 48, 'enum', 'undocumented_field_48'
|
60
65
|
field 49, 'uint16', 'undocumented_field_49'
|
61
66
|
field 51, 'enum', 'undocumented_field_51'
|
@@ -75,6 +80,8 @@ module Fit4Ruby
|
|
75
80
|
field 68, 'enum', 'undocumented_field_68'
|
76
81
|
field 69, 'enum', 'undocumented_field_69'
|
77
82
|
field 75, 'enum', 'undocumented_field_75'
|
83
|
+
field 76, 'enum', 'undocumented_field_76'
|
84
|
+
field 77, 'enum', 'undocumented_field_77'
|
78
85
|
field 80, 'enum', 'lactate_threshold_autodetect_enabled'
|
79
86
|
field 81, 'enum', 'undocumented_field_81'
|
80
87
|
field 82, 'enum', 'undocumented_field_82'
|
@@ -84,6 +91,7 @@ module Fit4Ruby
|
|
84
91
|
field 87, 'enum', 'undocumented_field_87'
|
85
92
|
field 90, 'uint32', 'auto_activity_detect'
|
86
93
|
field 94, 'uint8', 'number_of_screens'
|
94
|
+
field 96, 'enum', 'undocumented_field_96'
|
87
95
|
field 97, 'uint8z', 'undocumented_field_97'
|
88
96
|
field 101, 'enum', 'undocumented_field_101'
|
89
97
|
field 104, 'enum', 'undocumented_field_104'
|
@@ -93,14 +101,27 @@ module Fit4Ruby
|
|
93
101
|
field 110, 'enum', 'undocumented_field_110'
|
94
102
|
field 111, 'enum', 'undocumented_field_111'
|
95
103
|
field 112, 'enum', 'undocumented_field_112'
|
104
|
+
field 116, 'enum', 'undocumented_field_116'
|
105
|
+
field 117, 'enum', 'undocumented_field_117'
|
96
106
|
field 124, 'uint8', 'undocumented_field_124'
|
97
107
|
field 125, 'uint8', 'undocumented_field_125'
|
98
108
|
field 126, 'enum', 'undocumented_field_126'
|
99
109
|
field 127, 'enum', 'undocumented_field_127'
|
100
110
|
field 128, 'enum', 'undocumented_field_128'
|
111
|
+
field 129, 'enum', 'undocumented_field_129'
|
112
|
+
field 130, 'enum', 'undocumented_field_130'
|
113
|
+
field 131, 'enum', 'undocumented_field_131'
|
114
|
+
field 132, 'enum', 'undocumented_field_132'
|
101
115
|
field 133, 'enum', 'undocumented_field_133'
|
116
|
+
field 137, 'enum', 'undocumented_field_137'
|
102
117
|
field 138, 'enum', 'undocumented_field_138'
|
118
|
+
field 139, 'enum', 'undocumented_field_139'
|
119
|
+
field 141, 'uint8', 'undocumented_field_141'
|
120
|
+
field 142, 'uint8', 'undocumented_field_142'
|
121
|
+
field 143, 'uint8', 'undocumented_field_143'
|
103
122
|
field 144, 'enum', 'true_up_enabled'
|
123
|
+
field 148, 'enum', 'undocumented_field_148'
|
124
|
+
field 149, 'enum', 'undocumented_field_149'
|
104
125
|
|
105
126
|
message 3, 'user_profile'
|
106
127
|
field 0, 'string', 'friendly_name'
|
@@ -124,7 +145,7 @@ module Fit4Ruby
|
|
124
145
|
field 30, 'enum', 'height_setting', :dict => 'display_measure'
|
125
146
|
field 31, 'uint16', 'user_running_step_length'
|
126
147
|
field 32, 'uint16', 'user_walking_step_length'
|
127
|
-
field 33, 'uint16', 'undocumented_field_33'
|
148
|
+
field 33, 'uint16', 'undocumented_field_33' # varies between 800 to 1600, seems VO2max related
|
128
149
|
field 34, 'uint16', 'undocumented_field_34'
|
129
150
|
field 35, 'uint32', 'undocumented_field_35'
|
130
151
|
field 36, 'uint8', 'undocumented_field_36'
|
@@ -132,11 +153,54 @@ module Fit4Ruby
|
|
132
153
|
field 38, 'uint16', 'undocumented_field_38'
|
133
154
|
field 39, 'float32', 'undocumented_field_39'
|
134
155
|
field 40, 'float32', 'undocumented_field_40'
|
135
|
-
field 41, 'uint32', '
|
156
|
+
field 41, 'uint32', 'time_last_lthr_update', :type => 'date_time'
|
136
157
|
field 42, 'uint32', 'undocumented_field_42'
|
137
158
|
field 43, 'enum', 'undocumented_field_43'
|
159
|
+
field 47, 'enum', 'undocumented_field_47'
|
138
160
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
139
161
|
|
162
|
+
message 5, 'sdm_profile'
|
163
|
+
field 0, 'bool', 'enabled'
|
164
|
+
field 1, 'uint16z', 'sdm_ant_id'
|
165
|
+
field 2, 'uint16', 'sdm_cal_factor', :scale => 10, :unit => '%'
|
166
|
+
field 3, 'uint32', 'odometer', :scale => 100, :unit => 'm'
|
167
|
+
field 4, 'bool', 'speed_source'
|
168
|
+
field 5, 'uint8z', 'sdm_ant_id_trans_type'
|
169
|
+
field 7, 'uint8', 'odometer_rollover'
|
170
|
+
|
171
|
+
message 6, 'bike_profile'
|
172
|
+
field 0, 'string', 'name'
|
173
|
+
field 1, 'sport', 'sport'
|
174
|
+
field 2, 'sub_sport', 'sub_sport'
|
175
|
+
field 3, 'uint32', 'odometer', :scale => 100, :unit => 'm'
|
176
|
+
field 4, 'uint16z', 'bike_spd_ant_id'
|
177
|
+
field 5, 'uint16z', 'bike_cad_ant_id'
|
178
|
+
field 6, 'uint16z', 'bike_spdcad_ant_id'
|
179
|
+
field 7, 'uint16z', 'bike_power_ant_id'
|
180
|
+
field 8, 'uint16', 'custom_wheelsize', :scale => 1000, :unit => 'm'
|
181
|
+
field 9, 'uint16', 'auto_wheelsize', :scale => 1000, :unit => 'm'
|
182
|
+
field 10, 'uint16', 'bike_weight', :scale => 10, :unit => 'kg'
|
183
|
+
field 11, 'uint16', 'power_cal_factor', :scale => 10, :unit => '%'
|
184
|
+
field 12, 'bool', 'auto_wheel_cal'
|
185
|
+
field 13, 'bool', 'auto_power_zero'
|
186
|
+
field 14, 'uint8', 'id'
|
187
|
+
field 15, 'bool', 'spd_enabled'
|
188
|
+
field 16, 'bool', 'cad_enabled'
|
189
|
+
field 17, 'bool', 'spdcad_enabled'
|
190
|
+
field 18, 'bool', 'power_enabled'
|
191
|
+
field 19, 'uint8', 'crank_length', :scale => 2, :offset => -110, :unit => 'mm'
|
192
|
+
field 20, 'bool', 'enabled'
|
193
|
+
field 21, 'uint8z', 'bike_spd_ant_id_trans_type'
|
194
|
+
field 22, 'uint8z', 'bike_cad_ant_id_trans_type'
|
195
|
+
field 23, 'uint8z', 'bike_spdcad_ant_id_trans_type'
|
196
|
+
field 24, 'uint8z', 'bike_power_ant_id_trans_type'
|
197
|
+
field 37, 'uint8', 'odometer_rollover'
|
198
|
+
field 38, 'uint8z', 'front_gear_num', :array => true
|
199
|
+
field 39, 'uint8z', 'front_gear'
|
200
|
+
field 40, 'uint8z', 'rear_gear_num', :array => true
|
201
|
+
field 41, 'uint8z', 'rear_gear'
|
202
|
+
field 44, 'bool', 'shimano_di2_enabled'
|
203
|
+
|
140
204
|
message 7, 'zones_target'
|
141
205
|
field 1, 'uint8', 'max_heart_rate'
|
142
206
|
field 2, 'uint8', 'threshold_heart_rate'
|
@@ -157,10 +221,13 @@ module Fit4Ruby
|
|
157
221
|
field 4, 'uint16', 'undocumented_field_4'
|
158
222
|
field 5, 'enum', 'undocumented_field_5'
|
159
223
|
field 6, 'enum', 'undocumented_field_6'
|
224
|
+
field 9, 'uint8', 'undocumented_field_9'
|
160
225
|
field 10, 'uint8', 'undocumented_field_10', :array => true
|
161
226
|
field 11, 'enum', 'undocumented_field_11'
|
162
|
-
field 12, 'uint8', 'undocumented_field_12'
|
227
|
+
field 12, 'uint8', 'undocumented_field_12', :array => true
|
163
228
|
field 13, 'enum', 'undocumented_field_13'
|
229
|
+
field 15, 'enum', 'undocumented_field_15'
|
230
|
+
field 19, 'enum', 'undocumented_field_19', :array => true
|
164
231
|
|
165
232
|
# Not part of the official ANT SDK doc.
|
166
233
|
message 13, 'undocumented_13'
|
@@ -198,14 +265,23 @@ module Fit4Ruby
|
|
198
265
|
field 40, 'enum', 'undocumented_field_40'
|
199
266
|
field 41, 'sint32', 'undocumented_field_41'
|
200
267
|
field 42, 'uint8', 'undocumented_field_42'
|
268
|
+
field 43, 'enum', 'undocumented_field_43'
|
269
|
+
field 44, 'enum', 'undocumented_field_44'
|
270
|
+
field 45, 'enum', 'undocumented_field_45'
|
201
271
|
field 46, 'enum', 'undocumented_field_46'
|
272
|
+
field 47, 'enum', 'undocumented_field_47'
|
273
|
+
field 48, 'enum', 'undocumented_field_48'
|
202
274
|
field 53, 'enum', 'undocumented_field_53'
|
203
275
|
field 54, 'uint32', 'undocumented_field_54'
|
204
276
|
field 55, 'enum', 'undocumented_field_55'
|
205
277
|
field 57, 'enum', 'undocumented_field_57'
|
206
278
|
field 60, 'enum', 'undocumented_field_60'
|
279
|
+
field 62, 'enum', 'undocumented_field_62'
|
280
|
+
field 63, 'enum', 'undocumented_field_63'
|
281
|
+
field 64, 'uint16', 'undocumented_field_64'
|
207
282
|
field 65, 'enum', 'undocumented_field_65'
|
208
283
|
field 66, 'enum', 'undocumented_field_66'
|
284
|
+
field 76, 'enum', 'undocumented_field_76'
|
209
285
|
field 254, 'uint16', 'message_index'
|
210
286
|
|
211
287
|
message 18, 'session'
|
@@ -304,10 +380,15 @@ module Fit4Ruby
|
|
304
380
|
field 121, 'uint16', 'max_power_position', :array => true, :unit => 'watts'
|
305
381
|
field 122, 'uint8', 'avg_cadence_position', :array => true, :unit => 'rpm'
|
306
382
|
field 123, 'uint8', 'max_cadence_position', :array => true, :unit => 'rpm'
|
383
|
+
field 124, 'uint32', 'enhanced_avg_speed', :scale => 1000, :unit => 'm/s'
|
384
|
+
field 125, 'uint32', 'enhanced_max_speed', :scale => 1000, :unit => 'm/s'
|
385
|
+
field 126, 'uint32', 'enhanced_avg_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
386
|
+
field 127, 'uint32', 'enhanced_min_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
387
|
+
field 128, 'uint32', 'enhanced_max_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
307
388
|
field 132, 'uint16', 'avg_vertical_ratio', :scale => 100, :unit => '%'
|
308
389
|
field 133, 'uint16', 'avg_stance_time_balance', :scale => 100, :unit => '%'
|
309
|
-
field 134, 'uint16', 'avg_step_length', :scale =>
|
310
|
-
field 137, 'uint8', '
|
390
|
+
field 134, 'uint16', 'avg_step_length', :scale => 10, :unit => 'mm'
|
391
|
+
field 137, 'uint8', 'total_anaerobic_training_effect', :scale => 10
|
311
392
|
field 138, 'uint8', 'undocumented_field_138'
|
312
393
|
field 150, 'sint8', 'min_temperature', :unit => 'C' # guessed
|
313
394
|
field 151, 'uint16', 'undocumented_field_151'
|
@@ -316,6 +397,7 @@ module Fit4Ruby
|
|
316
397
|
field 158, 'uint16', 'undocumented_field_158'
|
317
398
|
field 153, 'enum', 'undocumented_field_153'
|
318
399
|
field 154, 'enum', 'undocumented_field_154'
|
400
|
+
field 184, 'enum', 'undocumented_field_184'
|
319
401
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
320
402
|
field 254, 'uint16', 'message_index'
|
321
403
|
|
@@ -403,9 +485,14 @@ module Fit4Ruby
|
|
403
485
|
field 107, 'uint16', 'max_power_position', :array => true, :unit => 'watts'
|
404
486
|
field 108, 'uint8', 'avg_cadence_position', :array => true, :unit => 'rpm'
|
405
487
|
field 109, 'uint8', 'max_cadence_position', :array => true, :unit => 'rpm'
|
406
|
-
field
|
407
|
-
field
|
408
|
-
field
|
488
|
+
field 110, 'uint32', 'enhanced_avg_speed', :scale => 1000, :unit => 'm/s'
|
489
|
+
field 111, 'uint32', 'enhanced_max_speed', :scale => 1000, :unit => 'm/s'
|
490
|
+
field 112, 'uint32', 'enhanced_avg_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
491
|
+
field 113, 'uint32', 'enhanced_min_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
492
|
+
field 114, 'uint32', 'enhanced_max_altitude', :scale => 5, :offset => 500, :unit => 'm'
|
493
|
+
field 118, 'uint16', 'avg_vertical_ratio', :scale => 100, :unit => '%'
|
494
|
+
field 119, 'uint16', 'avg_stance_time_balance', :scale => 100, :unit => '%'
|
495
|
+
field 120, 'uint16', 'avg_step_length', :scale => 10000, :unit => 'm'
|
409
496
|
field 124, 'sint8', 'min_temperature', :unit => 'C' # guessed
|
410
497
|
field 125, 'uint16', 'undocumented_field_125'
|
411
498
|
field 126, 'uint16', 'undocumented_field_126'
|
@@ -488,6 +575,7 @@ module Fit4Ruby
|
|
488
575
|
field 'recovery_time', 'uint32', 'recovery_time', :unit => 'min'
|
489
576
|
field 'recovery_info', 'uint32', 'recovery_info', :unit => 'min'
|
490
577
|
field 'vo2max', 'uint32', 'vo2max'
|
578
|
+
field 'functional_threshold_power', 'uint32', 'functional_threshold_power', :unit => 'W'
|
491
579
|
field 'lactate_threshold_heart_rate', 'uint32', 'lactate_threshold_heart_rate', :unit => 'bpm'
|
492
580
|
field 'lactate_threshold_speed', 'uint32', 'lactate_threshold_speed', :scale => 1000, :unit => 'm/s'
|
493
581
|
end
|
@@ -495,6 +583,8 @@ module Fit4Ruby
|
|
495
583
|
field 14, 'enum', 'undocumented_field_14'
|
496
584
|
field 15, 'uint32', 'undocumented_field_15'
|
497
585
|
field 16, 'enum', 'undocumented_field_16'
|
586
|
+
field 19, 'uint8', 'undocumented_field_19'
|
587
|
+
field 20, 'uint8', 'undocumented_field_20'
|
498
588
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
499
589
|
|
500
590
|
# Possibly which device is used as metering source.
|
@@ -642,7 +732,7 @@ module Fit4Ruby
|
|
642
732
|
|
643
733
|
# Not part of the official ANT SDK doc
|
644
734
|
message 79, 'user_data'
|
645
|
-
field 0, 'uint16', 'metmax', :scale =>
|
735
|
+
field 0, 'uint16', 'metmax', :scale => 1024, :unit => 'MET' # VO2max / 3.5
|
646
736
|
field 1, 'uint8', 'age', :unit => 'years'
|
647
737
|
field 2, 'uint8', 'height', :scale => 100, :unit => 'm'
|
648
738
|
field 3, 'uint16', 'weight', :scale => 10, :unit => 'kg'
|
@@ -652,9 +742,9 @@ module Fit4Ruby
|
|
652
742
|
field 7, 'sint8', 'undocumented_field_7' # seems to be always 1
|
653
743
|
field 8, 'uint16', 'recovery_time', :scale => 60, :unit => 'hours'
|
654
744
|
field 9, 'uint16', 'undocumented_field_9' # maybe activity measurement
|
655
|
-
field 10, 'uint8', '
|
745
|
+
field 10, 'uint8', 'avg_resting_heart_rate', :unit => 'bpm'
|
656
746
|
field 11, 'uint16', 'running_lactate_threshold_heart_rate', :unit => 'bpm'
|
657
|
-
field 12, 'uint16', '
|
747
|
+
field 12, 'uint16', 'functional_threshold_power', :unit => 'W'
|
658
748
|
field 13, 'uint16', 'undocumented_field_13'
|
659
749
|
field 14, 'uint8', 'undocumented_field_14'
|
660
750
|
field 15, 'uint8', 'undocumented_field_15'
|
@@ -722,18 +812,18 @@ module Fit4Ruby
|
|
722
812
|
# All known fields so far seem to be physiological values. We'll use the
|
723
813
|
# name physiological_metrics for now.
|
724
814
|
message 140, 'physiological_metrics'
|
725
|
-
field 0, 'uint8', '
|
726
|
-
field 1, 'uint8', '
|
815
|
+
field 0, 'uint8', 'min_heart_rate', :unit => 'bpm'
|
816
|
+
field 1, 'uint8', 'max_heart_rate', :unit => 'bpm'
|
727
817
|
field 2, 'sint32', 'undocumented_field_2'
|
728
818
|
field 3, 'sint32', 'undocumented_field_3'
|
729
819
|
field 4, 'uint8', 'aerobic_training_effect', :scale => 10
|
730
820
|
field 5, 'sint32', 'undocumented_field_5'
|
731
821
|
field 6, 'sint32', 'undocumented_field_6'
|
732
|
-
field 7, 'sint32', '
|
822
|
+
field 7, 'sint32', 'metmax', :scale => 65536, :unit => 'MET'
|
733
823
|
# Field 8 used to be uint8 but recent devices use sint8. We model this
|
734
824
|
# with an alt_field. The switch field is randomly picked as we have no
|
735
825
|
# details why the type has been changed.
|
736
|
-
alt_field 8, '
|
826
|
+
alt_field 8, 'max_heart_rate' do
|
737
827
|
field :default, 'sint8', 'undocumented_field_8s'
|
738
828
|
field 255, 'uint8', 'undocumented_field_8u'
|
739
829
|
end
|
@@ -755,9 +845,10 @@ module Fit4Ruby
|
|
755
845
|
field 24, 'sint32', 'undocumented_field_24'
|
756
846
|
field 25, 'uint8', 'undocumented_field_25'
|
757
847
|
field 26, 'sint32', 'undocumented_field_26'
|
758
|
-
field 29, 'sint32', '
|
848
|
+
field 29, 'sint32', 'metmax_running', :scale => 65536, :unit => 'MET'
|
759
849
|
field 34, 'enum', 'undocumented_field_34'
|
760
850
|
field 35, 'uint32', 'undocumented_field_35'
|
851
|
+
field 36, 'uint32', 'undocumented_field_36'
|
761
852
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
762
853
|
|
763
854
|
# Not part of the official ANT SDK doc. The message name is guessed and
|
@@ -824,6 +915,9 @@ module Fit4Ruby
|
|
824
915
|
field 58, 'enum', 'undocumented_field_58'
|
825
916
|
field 59, 'uint8', 'undocumented_field_59'
|
826
917
|
field 62, 'uint8', 'undocumented_field_62'
|
918
|
+
field 63, 'enum', 'undocumented_field_63'
|
919
|
+
field 64, 'uint32', 'undocumented_field_64'
|
920
|
+
field 65, 'uint32', 'undocumented_field_65'
|
827
921
|
field 254, 'uint16', 'message_index'
|
828
922
|
|
829
923
|
# Not part of the official ANT SDK doc.
|
@@ -881,6 +975,74 @@ module Fit4Ruby
|
|
881
975
|
field 1, 'uint32', 'stress_level_time', :type => 'date_time'
|
882
976
|
field 2, 'sint8', 'undocumented_field_2'
|
883
977
|
|
978
|
+
# Not part of the official ANT SDK doc.
|
979
|
+
message 229, 'undocumented_229'
|
980
|
+
field 0, 'uint32', 'time', :type => 'date_time'
|
981
|
+
field 1, 'sint32', 'metmax', :scale => 65536, :unit => 'MET'
|
982
|
+
field 2, 'uint16', 'vo2max', :scale => 10, :unit => 'ml/kg/min'
|
983
|
+
field 3, 'sint8', 'undocumented_field_3'
|
984
|
+
field 4, 'sint8', 'undocumented_field_4'
|
985
|
+
field 5, 'enum', 'undocumented_field_5'
|
986
|
+
field 6, 'enum', 'undocumented_field_6'
|
987
|
+
field 7, 'enum', 'undocumented_field_7'
|
988
|
+
field 8, 'enum', 'undocumented_field_8'
|
989
|
+
field 9, 'enum', 'undocumented_field_9'
|
990
|
+
|
991
|
+
# Not part of the official ANT SDK doc.
|
992
|
+
message 232, 'training_status'
|
993
|
+
field 0, 'enum', 'undocumented_0'
|
994
|
+
field 1, 'enum', 'undocumented_1'
|
995
|
+
field 2, 'enum', 'current_status', :dict => 'training_status'
|
996
|
+
field 3, 'enum', 'fitness', :dict => 'training_status_trend'
|
997
|
+
field 4, 'enum', 'load', :dict => 'training_status_trend'
|
998
|
+
field 5, 'uint16', 'training_load'
|
999
|
+
field 6, 'uint16', 'low_training_load'
|
1000
|
+
field 7, 'uint16', 'high_training_load'
|
1001
|
+
field 8, 'uint16', 'max_training_load'
|
1002
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
1003
|
+
|
1004
|
+
# Not part of the official ANT SDK doc.
|
1005
|
+
message 233, 'undocumented_233'
|
1006
|
+
field 2, 'byte', 'undocumented_field_2'
|
1007
|
+
|
1008
|
+
# Not part of the official ANT SDK doc.
|
1009
|
+
message 241, 'metrics'
|
1010
|
+
field 0, 'uint32', 'localtime', :type => 'date_time'
|
1011
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
1012
|
+
|
1013
|
+
# Not part of the official ANT SDK doc.
|
1014
|
+
message 243, 'media_player_info'
|
1015
|
+
field 0, 'uint32', 'undocumented_field_0'
|
1016
|
+
field 1, 'uint16', 'undocumented_field_1'
|
1017
|
+
field 2, 'string', 'track_1'
|
1018
|
+
field 3, 'string', 'track_2'
|
1019
|
+
field 4, 'string', 'track_3'
|
1020
|
+
field 5, 'uint16', 'undocumented_field_5'
|
1021
|
+
field 6, 'uint16', 'undocumented_field_6'
|
1022
|
+
|
1023
|
+
# Not part of the official ANT SDK doc.
|
1024
|
+
message 244, 'undocumented_244'
|
1025
|
+
field 0, 'uint32', 'undocumented_field_0'
|
1026
|
+
field 1, 'enum', 'undocumented_field_1'
|
1027
|
+
field 2, 'uint16', 'undocumented_field_2'
|
1028
|
+
|
1029
|
+
# Not part of the official ANT SDK doc.
|
1030
|
+
message 269, 'undocumented_269'
|
1031
|
+
field 0, 'uint8', 'undocumented_field_0'
|
1032
|
+
field 1, 'uint8', 'undocumented_field_1'
|
1033
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
1034
|
+
|
1035
|
+
# Not part of the official ANT SDK doc.
|
1036
|
+
message 279, 'undocumented_279'
|
1037
|
+
field 0, 'uint32', 'undocumented_field_0'
|
1038
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
1039
|
+
|
1040
|
+
# Not part of the official ANT SDK doc.
|
1041
|
+
message 284, 'training_load'
|
1042
|
+
field 0, 'uint16', 'load'
|
1043
|
+
field 1, 'uint32', 'timestamp', :type => 'date_time'
|
1044
|
+
|
1045
|
+
# Not part of the official ANT SDK doc.
|
884
1046
|
message 1024, 'undocumented_1024'
|
885
1047
|
field 0, 'enum', 'undocumented_field_0'
|
886
1048
|
field 2, 'enum', 'undocumented_field_2'
|
@@ -890,10 +1052,6 @@ module Fit4Ruby
|
|
890
1052
|
field 247, 'enum', 'undocumented_field_247'
|
891
1053
|
field 255, 'enum', 'undocumented_field_255'
|
892
1054
|
|
893
|
-
# Not part of the official ANT SDK doc.
|
894
|
-
message 233, 'undocumented_233'
|
895
|
-
field 2, 'byte', 'undocumented_field_2'
|
896
|
-
|
897
1055
|
end
|
898
1056
|
|
899
1057
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = Metrics.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2018 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'fit4ruby/FitDataRecord'
|
14
|
+
require 'fit4ruby/FileId'
|
15
|
+
require 'fit4ruby/FileCreator'
|
16
|
+
require 'fit4ruby/DeviceInfo'
|
17
|
+
require 'fit4ruby/TrainingStatus'
|
18
|
+
|
19
|
+
module Fit4Ruby
|
20
|
+
|
21
|
+
# The Metrics object is a FIT file class. It's a top-level object that
|
22
|
+
# holds all references to other FIT records that are part of the FIT file.
|
23
|
+
# Each of the objects it references are direct equivalents of the message
|
24
|
+
# record structures used in the FIT file.
|
25
|
+
#
|
26
|
+
# This is not part of the officially documented FIT API. Names may change in
|
27
|
+
# the future if the real Garmin names get known.
|
28
|
+
class Metrics < FitDataRecord
|
29
|
+
|
30
|
+
attr_accessor :field_descriptions, :file_id, :file_creator, :device_infos
|
31
|
+
|
32
|
+
# Create a new Metrics object.
|
33
|
+
# @param field_values [Hash] A Hash that provides initial values for
|
34
|
+
# certain fields of the FitDataRecord.
|
35
|
+
def initialize(field_values = {})
|
36
|
+
super('metrics')
|
37
|
+
|
38
|
+
@field_descriptions = []
|
39
|
+
|
40
|
+
@file_id = FileId.new
|
41
|
+
@device_infos = []
|
42
|
+
@file_creator = nil
|
43
|
+
@training_statuses = []
|
44
|
+
end
|
45
|
+
|
46
|
+
# Perform some basic logical checks on the object and all references sub
|
47
|
+
# objects. Any errors will be reported via the Log object.
|
48
|
+
def check
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create a new FitDataRecord.
|
52
|
+
# @param record_type [String] Type that identifies the FitDataRecord
|
53
|
+
# derived class to create.
|
54
|
+
# @param field_values [Hash] A Hash that provides initial values for
|
55
|
+
# certain fields of the FitDataRecord.
|
56
|
+
# @return FitDataRecord
|
57
|
+
def new_fit_data_record(record_type, field_values = {})
|
58
|
+
case record_type
|
59
|
+
when 'file_id'
|
60
|
+
@file_id = (record = FileId.new(field_values))
|
61
|
+
when 'file_creator'
|
62
|
+
@software = (record = FileCreator.new(field_values))
|
63
|
+
when 'device_info'
|
64
|
+
@device_infos << (record = DeviceInfo.new(field_values))
|
65
|
+
when 'training_status'
|
66
|
+
@training_statuses << (record = TrainingStatus.new(field_values))
|
67
|
+
else
|
68
|
+
record = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
record
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = TrainingStatus.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2018 by Chris Schlaeger <cs@taskjuggler.org>
|
7
|
+
#
|
8
|
+
# This program is free software; you can redistribute it and/or modify
|
9
|
+
# it under the terms of version 2 of the GNU General Public License as
|
10
|
+
# published by the Free Software Foundation.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'fit4ruby/FitDataRecord'
|
14
|
+
|
15
|
+
module Fit4Ruby
|
16
|
+
|
17
|
+
# This class corresponds to the training_status message.
|
18
|
+
#
|
19
|
+
# This is not part of the officially documented FIT API. Names may change in
|
20
|
+
# the future if the real Garmin names get known.
|
21
|
+
class TrainingStatus < FitDataRecord
|
22
|
+
|
23
|
+
def initialize(field_values = {})
|
24
|
+
super('training_status')
|
25
|
+
set_field_values(field_values)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Ensure that FitDataRecords have a deterministic sequence. Device infos
|
29
|
+
# are sorted by device_index.
|
30
|
+
def <=>(fdr)
|
31
|
+
@timestamp == fdr.timestamp ?
|
32
|
+
@message.name == fdr.message.name ?
|
33
|
+
@device_index <=> fdr.device_index :
|
34
|
+
RecordOrder.index(@message.name) <=>
|
35
|
+
RecordOrder.index(fdr.message.name) :
|
36
|
+
@timestamp <=> fdr.timestamp
|
37
|
+
end
|
38
|
+
|
39
|
+
def check(index)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
data/lib/fit4ruby/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fit4ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- lib/fit4ruby/HeartRateZones.rb
|
120
120
|
- lib/fit4ruby/Lap.rb
|
121
121
|
- lib/fit4ruby/Log.rb
|
122
|
+
- lib/fit4ruby/Metrics.rb
|
122
123
|
- lib/fit4ruby/Monitoring.rb
|
123
124
|
- lib/fit4ruby/MonitoringInfo.rb
|
124
125
|
- lib/fit4ruby/Monitoring_B.rb
|
@@ -129,6 +130,7 @@ files:
|
|
129
130
|
- lib/fit4ruby/SensorSettings.rb
|
130
131
|
- lib/fit4ruby/Session.rb
|
131
132
|
- lib/fit4ruby/Software.rb
|
133
|
+
- lib/fit4ruby/TrainingStatus.rb
|
132
134
|
- lib/fit4ruby/UserData.rb
|
133
135
|
- lib/fit4ruby/UserProfile.rb
|
134
136
|
- lib/fit4ruby/version.rb
|