fit4ruby 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5db683019a2227bedc32be291a3dfc0944a73608
4
- data.tar.gz: bffd0e1c2afa57b10ccde0f2dc4b2de7574f82c2
3
+ metadata.gz: 65a965e6c32ad68e1372db0c7d84edcec72fee33
4
+ data.tar.gz: e5e0e5c24f2c52438c02a456acb70e9ea03ffa8e
5
5
  SHA512:
6
- metadata.gz: 2361ae4059e936e3757481645e556ff28d83530331cd4bbf4716fc4f89f3e20e204d5e3db9d198ea79eb312004297f82155ce2a8b37d7b0f6112f166975216f4
7
- data.tar.gz: edd160bec64bf6cf04f5af8d3288eb4780d5d709d10e11913f887db9a0ae42a4fe1d2eb629e1f000a85d23f46d18599d6f87a5ad12efb8d330283b2f570449e0
6
+ metadata.gz: 39ac37ed06770fce85694f8d9ce6efc218d9a4e4af8c7c5a5f069c0e9d26fa0e8dfcd453831e1442eb4ad1b59175910c0823117aebf4142e622862b9c11d51a5
7
+ data.tar.gz: 73ccb053c98130d9dda748031d2afcefcd90967a7e4103f60f656155d3d9a6e8fdec7139e9efb265c4fae09155b75a6bb83b6d8920d77c435220f39d818eed07
@@ -15,12 +15,15 @@ require 'fit4ruby/FileId'
15
15
  require 'fit4ruby/EPO_Data'
16
16
  require 'fit4ruby/FileCreator'
17
17
  require 'fit4ruby/DeviceInfo'
18
+ require 'fit4ruby/SensorSettings'
18
19
  require 'fit4ruby/DataSources'
19
20
  require 'fit4ruby/UserProfile'
21
+ require 'fit4ruby/PhysiologicalMetrics'
20
22
  require 'fit4ruby/Session'
21
23
  require 'fit4ruby/Lap'
22
24
  require 'fit4ruby/Record'
23
25
  require 'fit4ruby/HRV'
26
+ require 'fit4ruby/HeartRateZones'
24
27
  require 'fit4ruby/Event'
25
28
  require 'fit4ruby/PersonalRecords'
26
29
 
@@ -32,9 +35,10 @@ module Fit4Ruby
32
35
  class Activity < FitDataRecord
33
36
 
34
37
  attr_accessor :file_id, :epo_data,
35
- :file_creator, :device_infos, :data_sources,
36
- :user_profiles, :sessions, :laps, :records, :hrv,
37
- :events, :personal_records
38
+ :file_creator, :device_infos, :sensor_settings, :data_sources,
39
+ :user_profiles, :physiological_metrics,
40
+ :sessions, :laps, :records, :hrv,
41
+ :heart_rate_zones, :events, :personal_records
38
42
 
39
43
  # Create a new Activity object.
40
44
  # @param field_values [Hash] A Hash that provides initial values for
@@ -48,13 +52,16 @@ module Fit4Ruby
48
52
  @epo_data = nil
49
53
  @file_creator = FileCreator.new
50
54
  @device_infos = []
55
+ @sensor_settings = []
51
56
  @data_sources = []
52
57
  @user_profiles = []
58
+ @physiological_metrics = []
53
59
  @events = []
54
60
  @sessions = []
55
61
  @laps = []
56
62
  @records = []
57
63
  @hrv = []
64
+ @heart_rate_zones = []
58
65
  @personal_records = []
59
66
 
60
67
  @cur_session_laps = []
@@ -78,6 +85,7 @@ module Fit4Ruby
78
85
  Log.fatal "Activity must have at least one device_info section"
79
86
  end
80
87
  @device_infos.each.with_index { |d, index| d.check(index) }
88
+ @sensor_settings.each.with_index { |s, index| s.check(index) }
81
89
  unless @num_sessions == @sessions.count
82
90
  Log.fatal "Activity record requires #{@num_sessions}, but "
83
91
  "#{@sessions.length} session records were found in the "
@@ -128,6 +136,9 @@ module Fit4Ruby
128
136
  # Laps must have a consecutively growing message index.
129
137
  @laps.each.with_index do |lap, index|
130
138
  lap.check(index)
139
+ # If we have heart rate zone records, there should be one for each
140
+ # lap
141
+ @heart_rate_zones[index].check(index) if @heart_rate_zones[index]
131
142
  end
132
143
  @sessions.each { |s| s.check(self) }
133
144
  end
@@ -271,8 +282,10 @@ module Fit4Ruby
271
282
  @file_id.write(io, id_mapper)
272
283
  @file_creator.write(io, id_mapper)
273
284
 
274
- (@device_infos + @data_sources + @user_profiles + @events +
275
- @sessions + @laps + @records + @personal_records).sort.each do |s|
285
+ (@device_infos + @sensor_settings + @data_sources + @user_profiles +
286
+ @physiological_metrics + @events +
287
+ @sessions + @laps + @records + @heart_rate_zones +
288
+ @personal_records).sort.each do |s|
276
289
  s.write(io, id_mapper)
277
290
  end
278
291
  super
@@ -320,6 +333,14 @@ module Fit4Ruby
320
333
  new_fit_data_record('old_user_profile', field_values)
321
334
  end
322
335
 
336
+ # Add a new PhysiologicalMetrics to the Activity.
337
+ # @param field_values [Hash] A Hash that provides initial values for
338
+ # certain fields of the FitDataRecord.
339
+ # @return [PhysiologicalMetrics]
340
+ def new_physiological_metrics(field_values = {})
341
+ new_fit_data_record('physiological_metrics', field_values)
342
+ end
343
+
323
344
  # Add a new Event to the Activity.
324
345
  # @param field_values [Hash] A Hash that provides initial values for
325
346
  # certain fields of the FitDataRecord.
@@ -351,6 +372,14 @@ module Fit4Ruby
351
372
  new_fit_data_record('lap', field_values)
352
373
  end
353
374
 
375
+ # Add a new HeartRateZones record to the Activity.
376
+ # @param field_values [Heash] A Hash that provides initial values for
377
+ # certain fields of the FitDataRecord.
378
+ # @return [HeartRateZones]
379
+ def new_heart_rate_zones(field_values = {})
380
+ new_fit_data_record('heart_rate_zones', field_values)
381
+ end
382
+
354
383
  # Add a new PersonalRecord to the Activity.
355
384
  # @param field_values [Hash] A Hash that provides initial values for
356
385
  # certain fields of the FitDataRecord.
@@ -375,8 +404,11 @@ module Fit4Ruby
375
404
  super(a) && @file_id == a.file_id &&
376
405
  @file_creator == a.file_creator &&
377
406
  @device_infos == a.device_infos &&
407
+ @sensor_settings == a.sensor_settings &&
378
408
  @data_sources == a.data_sources &&
409
+ @physiological_metrics == a.physiological_metrics &&
379
410
  @user_profiles == a.user_profiles &&
411
+ @heart_rate_zones == a.heart_rate_zones &&
380
412
  @events == a.events &&
381
413
  @sessions == a.sessions && personal_records == a.personal_records
382
414
  end
@@ -397,10 +429,15 @@ module Fit4Ruby
397
429
  @file_creator = (record = FileCreator.new(field_values))
398
430
  when 'device_info'
399
431
  @device_infos << (record = DeviceInfo.new(field_values))
432
+ when 'sensor_settings'
433
+ @sensor_settings << (record = SensorSettings.new(field_values))
400
434
  when 'data_sources'
401
435
  @data_sources << (record = DataSources.new(field_values))
402
436
  when 'old_user_profile'
403
437
  @user_profiles << (record = UserProfile.new(field_values))
438
+ when 'physiological_metrics'
439
+ @physiological_metrics <<
440
+ (record = PhysiologicalMetrics.new(field_values))
404
441
  when 'event'
405
442
  @events << (record = Event.new(field_values))
406
443
  when 'session'
@@ -424,6 +461,8 @@ module Fit4Ruby
424
461
  @records << record
425
462
  when 'hrv'
426
463
  @hrv << (record = HRV.new(field_values))
464
+ when 'heart_rate_zones'
465
+ @heart_rate_zones << (record = HeartRateZones.new(field_values))
427
466
  when 'personal_records'
428
467
  @personal_records << (record = PersonalRecords.new(field_values))
429
468
  else
@@ -20,7 +20,8 @@ module Fit4Ruby
20
20
  include Converters
21
21
 
22
22
  RecordOrder = [ 'old_user_profile', 'device_info', 'data_sources', 'event',
23
- 'record', 'lap', 'session', 'personal_records' ]
23
+ 'record', 'lap', 'session', 'heart_rate_zones',
24
+ 'personal_records' ]
24
25
 
25
26
  attr_reader :message
26
27
 
@@ -65,6 +66,8 @@ module Fit4Ruby
65
66
  def get_as(name, to_unit)
66
67
  value = respond_to?(name) ? send(name) : get(name)
67
68
  return nil if value.nil?
69
+ # If the requested unit is empty we return the value as is.
70
+ return value if to_unit.nil? || to_unit.empty?
68
71
 
69
72
  if @meta_field_units.include?(name)
70
73
  unit = @meta_field_units[name]
@@ -38,38 +38,40 @@ module Fit4Ruby
38
38
  end
39
39
 
40
40
  entities = []
41
- while !io.eof?
42
- offset = io.pos
43
-
44
- header = FitHeader.read(io)
45
- header.check
46
-
47
- check_crc(io, io.pos, offset + header.end_pos)
48
-
49
- entity = FitFileEntity.new
50
- # This Array holds the raw data of the records that may be needed to
51
- # dump a human readable form of the FIT file.
52
- records = []
53
- # This hash will hold a counter for each record type. The counter is
54
- # incremented each time the corresponding record type is found.
55
- record_counters = Hash.new { 0 }
56
- while io.pos < offset + header.end_pos
57
- record = FitRecord.new(definitions)
58
- record.read(io, entity, filter, record_counters)
59
- records << record if filter
41
+ begin
42
+ while !io.eof?
43
+ offset = io.pos
44
+
45
+ header = FitHeader.read(io)
46
+ header.check
47
+
48
+ check_crc(io, io.pos, offset + header.end_pos)
49
+
50
+ entity = FitFileEntity.new
51
+ # This Array holds the raw data of the records that may be needed to
52
+ # dump a human readable form of the FIT file.
53
+ records = []
54
+ # This hash will hold a counter for each record type. The counter is
55
+ # incremented each time the corresponding record type is found.
56
+ record_counters = Hash.new { 0 }
57
+ while io.pos < offset + header.end_pos
58
+ record = FitRecord.new(definitions)
59
+ record.read(io, entity, filter, record_counters)
60
+ records << record if filter
61
+ end
62
+ # Skip the 2 CRC bytes
63
+ io.seek(2, :CUR)
64
+
65
+ header.dump if filter && filter.record_numbers.nil?
66
+ dump_records(records) if filter
67
+
68
+ entity.check
69
+ entities << entity
60
70
  end
61
- # Skip the 2 CRC bytes
62
- io.seek(2, :CUR)
63
-
64
- header.dump if filter && filter.record_numbers.nil?
65
- dump_records(records) if filter
66
-
67
- entity.check
68
- entities << entity
71
+ ensure
72
+ io.close
69
73
  end
70
74
 
71
- io.close
72
-
73
75
  entities[0].top_level_record
74
76
  end
75
77
 
@@ -80,25 +82,27 @@ module Fit4Ruby
80
82
  Log.fatal "Cannot open FIT file '#{file_name}': #{e.message}"
81
83
  end
82
84
 
83
- # Create a header object, but don't yet write it into the file.
84
- header = FitHeader.new
85
- start_pos = header.header_size
86
- # Move the pointer behind the header section.
87
- io.seek(start_pos)
88
- id_mapper = FitMessageIdMapper.new
89
- top_level_record.write(io, id_mapper)
90
- end_pos = io.pos
91
-
92
- crc = write_crc(io, start_pos, end_pos)
93
-
94
- # Complete the data of the header section and write it at the start of
95
- # the file.
96
- header.data_size = end_pos - start_pos
97
- header.crc = crc
98
- io.seek(0)
99
- header.write(io)
100
-
101
- io.close
85
+ begin
86
+ # Create a header object, but don't yet write it into the file.
87
+ header = FitHeader.new
88
+ start_pos = header.header_size
89
+ # Move the pointer behind the header section.
90
+ io.seek(start_pos)
91
+ id_mapper = FitMessageIdMapper.new
92
+ top_level_record.write(io, id_mapper)
93
+ end_pos = io.pos
94
+
95
+ crc = write_crc(io, start_pos, end_pos)
96
+
97
+ # Complete the data of the header section and write it at the start of
98
+ # the file.
99
+ header.data_size = end_pos - start_pos
100
+ header.crc = crc
101
+ io.seek(0)
102
+ header.write(io)
103
+ ensure
104
+ io.close
105
+ end
102
106
  end
103
107
 
104
108
  private
@@ -78,7 +78,9 @@ module Fit4Ruby
78
78
  if filter && fields_dump &&
79
79
  (filter.field_names.nil? ||
80
80
  filter.field_names.include?(field_name)) &&
81
- (value != field.undefined_value || !filter.ignore_undef)
81
+ !(((value.respond_to?('count') &&
82
+ (value.count(field.undefined_value) == value.length)) ||
83
+ value == field.undefined_value) && filter.ignore_undef)
82
84
  fields_dump << DumpedField.new(
83
85
  @global_message_number,
84
86
  field.field_definition_number.snapshot,
@@ -59,6 +59,15 @@ module Fit4Ruby
59
59
  entry 2, 'antfs'
60
60
  entry 3, 'private'
61
61
 
62
+ dict 'backlight_mode'
63
+ entry 0, 'off'
64
+ entry 1, 'manual'
65
+ entry 2, 'key_and_messages'
66
+ entry 3, 'auto_brightness'
67
+ entry 4, 'smart_notifications'
68
+ entry 5, 'key_and_messages_night'
69
+ entry 6, 'key_and_messages_and_smart_notifications'
70
+
62
71
  dict 'battery_status'
63
72
  entry 1, 'new'
64
73
  entry 2, 'good'
@@ -66,13 +75,54 @@ module Fit4Ruby
66
75
  entry 4, 'low'
67
76
  entry 5, 'critical'
68
77
 
78
+ dict 'body_location'
79
+ entry 0, 'left_leg'
80
+ entry 1, 'left_calf'
81
+ entry 2, 'left_shin'
82
+ entry 3, 'left_hamstring'
83
+ entry 4, 'left_quad'
84
+ entry 5, 'left_glute'
85
+ entry 6, 'right_leg'
86
+ entry 7, 'right_calf'
87
+ entry 8, 'right_shin'
88
+ entry 9, 'right_hamstring'
89
+ entry 10, 'right_quad'
90
+ entry 11, 'right_glute'
91
+ entry 12, 'torso_back'
92
+ entry 13, 'left_lower_back'
93
+ entry 14, 'left_upper_back'
94
+ entry 15, 'right_lower_back'
95
+ entry 16, 'right_upper_back'
96
+ entry 17, 'torso_front'
97
+ entry 18, 'left_abdomen'
98
+ entry 19, 'left_chest'
99
+ entry 20, 'right_abdomen'
100
+ entry 21, 'right_chest'
101
+ entry 22, 'left_arm'
102
+ entry 23, 'left_shoulder'
103
+ entry 24, 'left_bicep'
104
+ entry 25, 'left_tricep'
105
+ entry 26, 'left_brachioradialis'
106
+ entry 27, 'left_forearm_extensors'
107
+ entry 28, 'right_arm'
108
+ entry 29, 'right_shoulder'
109
+ entry 30, 'right_bicep'
110
+ entry 31, 'right_tricep'
111
+ entry 32, 'right_brachioradialis'
112
+ entry 33, 'right_forearm_extensors'
113
+ entry 34, 'neck'
114
+ entry 35, 'throat'
115
+ entry 36, 'waist_mid_back'
116
+ entry 37, 'waist_front'
117
+ entry 38, 'waist_left'
118
+ entry 39, 'waist_right'
119
+
69
120
  dict 'comm_timeout_type'
70
121
  entry 0, 'wildcard_paring_timeout'
71
122
  entry 1, 'pairing_timeout'
72
123
  entry 2, 'connection_lost'
73
124
  entry 3, 'connection_timeout'
74
125
 
75
-
76
126
  dict 'device_type'
77
127
  entry 0, 'gps' # Just a guess
78
128
  entry 3, 'acceleration' # Just a guess
@@ -97,9 +147,63 @@ module Fit4Ruby
97
147
  entry 123, 'bike_speed'
98
148
  entry 124, 'stride_speed_distance'
99
149
 
150
+ dict 'display_heart'
151
+ entry 0, 'bpm'
152
+ entry 1, 'max'
153
+ entry 2, 'reserve'
154
+
100
155
  dict 'display_measure'
101
156
  entry 0, 'metric'
102
157
  entry 1, 'statute'
158
+ entry 2, 'nautical'
159
+
160
+ dict 'display_position'
161
+ entry 0, 'degree'
162
+ entry 1, 'degree_minute'
163
+ entry 2, 'degree_minute_second'
164
+ entry 3, 'austrian_grid'
165
+ entry 4, 'british_grid'
166
+ entry 5, 'dutch_grid'
167
+ entry 6, 'hungarian_grid'
168
+ entry 7, 'finnish_grid'
169
+ entry 8, 'german_grid'
170
+ entry 9, 'icelandic_grid'
171
+ entry 10, 'indonesian_equatorial'
172
+ entry 11, 'indonesian_irian'
173
+ entry 12, 'indonesian_southern'
174
+ entry 13, 'india_zone_0'
175
+ entry 14, 'india_zone_IA'
176
+ entry 15, 'india_zone_IB'
177
+ entry 16, 'india_zone_IIA'
178
+ entry 17, 'india_zone_IIB'
179
+ entry 18, 'india_zone_IIIA'
180
+ entry 19, 'india_zone_IIIB'
181
+ entry 20, 'india_zone_IVA'
182
+ entry 21, 'india_zone_IVB'
183
+ entry 22, 'irish_transverse'
184
+ entry 23, 'irish_grid'
185
+ entry 24, 'loran'
186
+ entry 25, 'maidenhead_grid'
187
+ entry 26, 'mgrs_grid'
188
+ entry 27, 'new_zealand_grid'
189
+ entry 28, 'new_zealand_transverse'
190
+ entry 29, 'qatar_grid'
191
+ entry 30, 'modified_swedish_grid'
192
+ entry 31, 'swedish_grid'
193
+ entry 32, 'south_african_grid'
194
+ entry 33, 'swiss_grid'
195
+ entry 34, 'taiwan_grid'
196
+ entry 35, 'united_states_grid'
197
+ entry 36, 'utm_ups_grid'
198
+ entry 37, 'west_malayan'
199
+ entry 38, 'borneo_rso'
200
+ entry 39, 'estonian_grid'
201
+ entry 40, 'latvian_grid'
202
+ entry 41, 'swedish_ref_99_grid'
203
+
204
+ dict 'display_power'
205
+ entry 0, 'watts'
206
+ entry 1, 'percent_ftp'
103
207
 
104
208
  dict 'event'
105
209
  entry 0, 'timer'
@@ -185,12 +289,14 @@ module Fit4Ruby
185
289
  # The Fenix3 is rumored to have a Mediatek MT3333 GPS chipset. Not sure if
186
290
  # that would be a beter name.
187
291
  entry 1620, 'fenix3_gps' # Just a guess
292
+ entry 1621, 'fenix5_gps' # Just a guess
188
293
  entry 1623, 'fr620'
189
294
  entry 1632, 'fr220'
190
295
  # The FR620 is rumored to have a MediaTek MT3339 GPS chipset while the
191
296
  # FR920XT is rumored to have a MT3333. Not sure why they have the same ID
192
297
  # in the FIT file for the GPS device.
193
298
  entry 1689, 'fr620_fr920xt_gps' # Just a guess
299
+ entry 1743, 'hrm_tri'
194
300
  entry 1752, 'hrm_run'
195
301
  entry 1765, 'fr920xt'
196
302
  entry 1928, 'fr620_japan'
@@ -208,7 +314,15 @@ module Fit4Ruby
208
314
  entry 2173, 'fr620_taiwan'
209
315
  entry 2188, 'fenix3_china'
210
316
  entry 2189, 'fenix3_twn'
317
+ entry 2327, 'hrm4_run'
211
318
  entry 2413, 'fenix3_hr'
319
+ entry 2431, 'fr235'
320
+ entry 2432, 'fenix3_chronos'
321
+ entry 2544, 'fenix5s'
322
+ entry 2604, 'fenix5x'
323
+ entry 2593, 'running_dynamics_pod'
324
+ entry 2691, 'fr935'
325
+ entry 2697, 'fenix5'
212
326
  entry 10007, 'sdm4'
213
327
  entry 20119, 'training_center'
214
328
  entry 65532, 'android_antplus_plugin'
@@ -224,6 +338,11 @@ module Fit4Ruby
224
338
  entry 2, 'warmup'
225
339
  entry 3, 'cooldown'
226
340
 
341
+ dict 'hr_zone_calc'
342
+ entry 0, 'custom'
343
+ entry 1, 'percent_max_hr'
344
+ entry 2, 'percent_hrr'
345
+
227
346
  dict 'lap_trigger'
228
347
  entry 0, 'manual'
229
348
  entry 1, 'time'
@@ -339,6 +458,10 @@ module Fit4Ruby
339
458
  entry 0x7000, 'reserved'
340
459
  entry 0x8000, 'selected'
341
460
 
461
+ dict 'pwr_zone_calc'
462
+ entry 0, 'custom'
463
+ entry 1, 'percent_ftp'
464
+
342
465
  dict 'rider_position_type'
343
466
  entry 0, 'seated'
344
467
  entry 1, 'standing'
@@ -34,12 +34,12 @@ module Fit4Ruby
34
34
  field 2, 'uint32', 'time_offset', :array => true
35
35
  field 3, 'enum', 'undocumented_field_3'
36
36
  field 4, 'enum', 'time_mode', :array => true
37
- field 5, 'sint8', 'time_zone_offset', :array => true
37
+ field 5, 'sint8', 'time_zone_offset', :array => true, :scale => 4
38
38
  field 8, 'uint16', 'undocumented_field_8'
39
39
  field 9, 'enum', 'undocumented_field_9'
40
40
  field 10, 'enum', 'undocumented_field_10'
41
41
  field 11, 'enum', 'undocumented_field_11'
42
- field 12, 'enum', 'backlight_mode'
42
+ field 12, 'enum', 'backlight_mode', :dict => 'backlight_mode'
43
43
  field 13, 'uint8', 'undocumented_field_13'
44
44
  field 14, 'uint8', 'undocumented_field_14'
45
45
  field 15, 'uint8', 'undocumented_field_15'
@@ -61,6 +61,7 @@ module Fit4Ruby
61
61
  field 51, 'enum', 'undocumented_field_51'
62
62
  field 52, 'enum', 'undocumented_field_52'
63
63
  field 53, 'enum', 'undocumented_field_53'
64
+ field 54, 'enum', 'undocumented_field_54'
64
65
  field 56, 'enum', 'mounting_side'
65
66
  field 58, 'uint16', 'autosync_min_steps'
66
67
  field 59, 'uint16', 'autosync_min_time'
@@ -72,6 +73,7 @@ module Fit4Ruby
72
73
  field 67, 'enum', 'undocumented_field_67'
73
74
  field 68, 'enum', 'undocumented_field_68'
74
75
  field 69, 'enum', 'undocumented_field_69'
76
+ field 75, 'enum', 'undocumented_field_75'
75
77
  field 80, 'enum', 'lactate_threshold_autodetect_enabled'
76
78
  field 81, 'enum', 'undocumented_field_81'
77
79
  field 82, 'enum', 'undocumented_field_82'
@@ -79,26 +81,44 @@ module Fit4Ruby
79
81
  field 84, 'enum', 'undocumented_field_84'
80
82
  field 85, 'enum', 'undocumented_field_85'
81
83
  field 87, 'enum', 'undocumented_field_87'
84
+ field 90, 'uint32', 'auto_activity_detect'
82
85
  field 94, 'uint8', 'number_of_screens'
86
+ field 97, 'uint8z', 'undocumented_field_97'
87
+ field 101, 'enum', 'undocumented_field_101'
88
+ field 104, 'enum', 'undocumented_field_104'
89
+ field 107, 'enum', 'undocumented_field_107'
90
+ field 108, 'enum', 'undocumented_field_108'
91
+ field 109, 'enum', 'undocumented_field_109'
92
+ field 110, 'enum', 'undocumented_field_110'
93
+ field 111, 'enum', 'undocumented_field_111'
94
+ field 112, 'enum', 'undocumented_field_112'
95
+ field 124, 'uint8', 'undocumented_field_124'
96
+ field 125, 'uint8', 'undocumented_field_125'
97
+ field 126, 'enum', 'undocumented_field_126'
98
+ field 127, 'enum', 'undocumented_field_127'
99
+ field 128, 'enum', 'undocumented_field_128'
100
+ field 133, 'enum', 'undocumented_field_133'
83
101
 
84
102
  message 3, 'user_profile'
103
+ field 0, 'string', 'friendly_name'
85
104
  field 1, 'enum', 'gender', :dict => 'gender'
86
- field 3, 'uint8', 'height'
87
- field 4, 'uint16', 'weight'
105
+ field 2, 'uint8', 'age'
106
+ field 3, 'uint8', 'height', :scale => 100, :unit => 'm'
107
+ field 4, 'uint16', 'weight', :scale => 10, :unit => 'kg'
88
108
  field 5, 'enum', 'language'
89
109
  field 6, 'enum', 'elev_setting'
90
110
  field 7, 'enum', 'weight_setting'
91
- field 8, 'uint8', 'resting_heart_rate'
92
- field 12, 'enum', 'hr_setting'
93
- field 13, 'enum', 'speed_setting'
94
- field 14, 'enum', 'dist_setting'
111
+ field 8, 'uint8', 'resting_heart_rate', :unit => 'bpm'
112
+ field 12, 'enum', 'hr_setting', :dict => 'display_heart'
113
+ field 13, 'enum', 'speed_setting', :dict => 'display_measure'
114
+ field 14, 'enum', 'dist_setting', :dict => 'display_measure'
95
115
  field 17, 'enum', 'activity_class'
96
- field 18, 'enum', 'position_setting'
97
- field 21, 'enum', 'temperature_setting'
116
+ field 18, 'enum', 'position_setting', :dict => 'display_position'
117
+ field 21, 'enum', 'temperature_setting', :dict => 'display_measure'
98
118
  field 24, 'uint8', 'undocumented_field_24'
99
- field 28, 'uint32', 'wake_time'
100
- field 29, 'uint32', 'sleep_time'
101
- field 30, 'enum', 'height_setting'
119
+ field 28, 'uint32', 'wake_time', :type => 'duration'
120
+ field 29, 'uint32', 'sleep_time', :type => 'duration'
121
+ field 30, 'enum', 'height_setting', :dict => 'display_measure'
102
122
  field 31, 'uint16', 'user_running_step_length'
103
123
  field 32, 'uint16', 'user_walking_step_length'
104
124
  field 33, 'uint16', 'undocumented_field_33'
@@ -111,13 +131,14 @@ module Fit4Ruby
111
131
  field 40, 'float32', 'undocumented_field_40'
112
132
  field 41, 'uint32', 'undocumented_field_41'
113
133
  field 42, 'uint32', 'undocumented_field_42'
134
+ field 43, 'enum', 'undocumented_field_43'
114
135
 
115
136
  message 7, 'zones_target'
116
137
  field 1, 'uint8', 'max_heart_rate'
117
138
  field 2, 'uint8', 'threshold_heart_rate'
118
139
  field 3, 'uint16', 'functional_threshold_power'
119
- field 5, 'enum', 'hr_zone_calc'
120
- field 7, 'enum', 'pwr_zone_calc'
140
+ field 5, 'enum', 'hr_zone_calc', :dict => 'hr_zone_calc'
141
+ field 7, 'enum', 'pwr_zone_calc', :dict => 'pwr_zone_calc'
121
142
  field 8, 'uint16', 'undocumented_field_8'
122
143
  field 9, 'enum', 'undocumented_field_9'
123
144
  field 10, 'enum', 'undocumented_field_10'
@@ -134,6 +155,8 @@ module Fit4Ruby
134
155
  field 6, 'enum', 'undocumented_field_6'
135
156
  field 10, 'uint8', 'undocumented_field_10', :array => true
136
157
  field 11, 'enum', 'undocumented_field_11'
158
+ field 12, 'uint8', 'undocumented_field_12'
159
+ field 13, 'enum', 'undocumented_field_13'
137
160
 
138
161
  # Not part of the official ANT SDK doc.
139
162
  message 13, 'undocumented_13'
@@ -172,6 +195,10 @@ module Fit4Ruby
172
195
  field 41, 'sint32', 'undocumented_field_41'
173
196
  field 42, 'uint8', 'undocumented_field_42'
174
197
  field 46, 'enum', 'undocumented_field_46'
198
+ field 53, 'enum', 'undocumented_field_53'
199
+ field 54, 'uint32', 'undocumented_field_54'
200
+ field 55, 'enum', 'undocumented_field_55'
201
+ field 57, 'enum', 'undocumented_field_57'
175
202
  field 254, 'uint16', 'message_index'
176
203
 
177
204
  message 18, 'session'
@@ -221,6 +248,8 @@ module Fit4Ruby
221
248
  field 35, 'uint16', 'training_stress_score', :scale => 10, :unit => 'tss'
222
249
  field 36, 'uint16', 'intensity_factor', :scale => 1000, :unit => 'if'
223
250
  field 37, 'uint16', 'left_right_balance', :dict => 'left_right_balance_100'
251
+ field 38, 'sint32', 'undocumented_field_38'
252
+ field 39, 'sint32', 'undocumented_field_39'
224
253
  field 41, 'uint32', 'avg_stroke_count', :scale => 10, :unit => 'strokes/lap'
225
254
  field 42, 'uint16', 'avg_stroke_distance', :scale => 100, :unit => 'm'
226
255
  field 43, 'enum', 'swim_stroke', :dict => 'swim_stroke'
@@ -251,6 +280,7 @@ module Fit4Ruby
251
280
  field 103, 'uint8', 'avg_left_pedal_smoothness', :scale => 2, :unit => 'percent'
252
281
  field 104, 'uint8', 'avg_right_pedal_smoothness', :scale => 2, :unit => 'percent'
253
282
  field 105, 'uint8', 'avg_combined_pedal_smoothness', :scale => 2, :unit => 'percent'
283
+ field 106, 'uint16', 'undocumented_field_106'
254
284
  field 107, 'uint16', 'undefined_value_107'
255
285
  field 108, 'uint16', 'undefined_value_108'
256
286
  field 109, 'uint8', 'undefined_value_109'
@@ -270,6 +300,8 @@ module Fit4Ruby
270
300
  field 132, 'uint16', 'vertical_ratio', :scale => 100, :unit => '%' # guessed
271
301
  field 133, 'uint16', 'avg_gct_balance', :scale => 100, :unit => '%' # guessed
272
302
  field 134, 'uint16', 'avg_stride_length', :scale => 10000, :unit => 'm' # guessed
303
+ field 137, 'uint8', 'g_effect', :scale => 10
304
+ field 138, 'uint8', 'undocumented_field_138'
273
305
  field 253, 'uint32', 'timestamp', :type => 'date_time'
274
306
  field 254, 'uint16', 'message_index'
275
307
 
@@ -402,6 +434,7 @@ module Fit4Ruby
402
434
  field 85, 'uint16', 'stride_length', :scale => 10000, :unit => 'm' # guessed
403
435
  field 87, 'uint16', 'undefined_value_87' # first seen on F3 FW6.80
404
436
  field 88, 'uint16', 'undefined_value_88' # first seen on F3HR FW3.60
437
+ field 90, 'sint8', 'performance_condition' # guessed
405
438
  field 253, 'uint32', 'timestamp', :type => 'date_time'
406
439
 
407
440
  message 21, 'event'
@@ -434,6 +467,9 @@ module Fit4Ruby
434
467
  field 'lactate_threshold_speed', 'uint32', 'lactate_threshold_speed', :scale => 1000, :unit => 'm/s'
435
468
  end
436
469
  field 4, 'uint8', 'event_group'
470
+ field 14, 'enum', 'undocumented_field_14'
471
+ field 15, 'uint32', 'undocumented_field_15'
472
+ field 16, 'enum', 'undocumented_field_16'
437
473
  field 253, 'uint32', 'timestamp', :type => 'date_time'
438
474
 
439
475
  # Possibly which device is used as metering source.
@@ -447,6 +483,7 @@ module Fit4Ruby
447
483
  field 5, 'enum', 'mode' # 0 or 3 seen, unknown meaning
448
484
  field 6, 'uint8', 'power' # First found in FR920XT
449
485
  field 14, 'uint8', 'calories' # First found in FR920XT
486
+ field 15, 'uint8', 'undocumented_field_15'
450
487
  field 253, 'uint32', 'timestamp', :type => 'date_time'
451
488
 
452
489
  message 23, 'device_info'
@@ -465,15 +502,19 @@ module Fit4Ruby
465
502
  field 9, 'uint8', 'undocumented_field_9'
466
503
  field 10, 'uint16', 'battery_voltage', :scale => 256, :unit => 'V'
467
504
  field 11, 'uint8', 'battery_status', :dict => 'battery_status'
505
+ field 13, 'uint16', 'undocumented_field_13'
468
506
  field 15, 'uint32', 'rx_packets_ok' # just a guess
469
507
  field 16, 'uint32', 'rx_packets_err' # just a guess
470
508
  field 17, 'string', 'undocumented_field_17'
509
+ field 18, 'enum', 'sendor_position', :dict => 'body_location'
471
510
  field 20, 'uint8z', 'ant_transmission_type'
472
511
  field 21, 'uint16z', 'ant_device_number'
473
512
  field 22, 'enum', 'ant_network', :dict => 'ant_network'
474
513
  field 23, 'uint8', 'undocumented_field_23'
475
- field 24, 'uint32z', 'undocumented_field_24'
514
+ field 24, 'uint32z', 'ant_id' # just a guess
476
515
  field 25, 'enum', 'source_type', :dict => 'source_type'
516
+ field 29, 'uint8', 'undocumented_field_29'
517
+ field 30, 'uint8', 'undocumented_field_30'
477
518
  field 253, 'uint32', 'timestamp', :type => 'date_time'
478
519
 
479
520
  # This message was first seen on the Fenix3HR with firmware 3.0.
@@ -620,6 +661,14 @@ module Fit4Ruby
620
661
  field 8, 'enum', 'undocumented_field_8', :array => true
621
662
  field 253, 'uint32', 'timestamp', :type => 'date_time'
622
663
 
664
+ # Not part of the official ANT SDK doc
665
+ message 104, 'battery'
666
+ field 0, 'uint16', 'unit_voltage', :unit => 'V', :scale => 1000
667
+ field 1, 'sint16', 'undocumented_field_1'
668
+ field 2, 'uint8', 'percent', :unit => '%'
669
+ field 3, 'sint8', 'current', :unit => 'mA' # just a wild guess
670
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
671
+
623
672
  # Not part of the official ANT SDK doc
624
673
  message 113, 'personal_records'
625
674
  field 0, 'uint16', 'longest_distance'
@@ -641,30 +690,40 @@ module Fit4Ruby
641
690
  field 253, 'uint32', 'timestamp', :type => 'date_time'
642
691
 
643
692
  # Not part of the official ANT SDK doc
644
- # The values in this message seem to be related to the activity history.
645
- # If no HRM is used, most of them are 0. Fields 4, 7, 9 and 10 always have
646
- # non-zero values.
647
- message 140, 'undocumented_140'
693
+ # All known fields so far seem to be physiological values. We'll use the
694
+ # name physiological_metrics for now.
695
+ message 140, 'physiological_metrics'
648
696
  field 0, 'uint8', 'max_heart_rate', :unit => 'bpm'
649
697
  field 1, 'uint8', 'undocumented_field_1'
650
698
  field 2, 'sint32', 'undocumented_field_2'
651
699
  field 3, 'sint32', 'undocumented_field_3'
652
- field 4, 'uint8', 'total_training_effect', :scale => 10
700
+ field 4, 'uint8', 'aerobic_training_effect', :scale => 10
653
701
  field 5, 'sint32', 'undocumented_field_5'
654
702
  field 6, 'sint32', 'undocumented_field_6'
655
703
  field 7, 'sint32', 'undocumented_field_7'
656
- field 8, 'uint8', 'undocumented_field_8'
704
+ # Field 8 used to be uint8 but recent devices use sint8. We model this
705
+ # with an alt_field. The switch field is randomly picked as we have no
706
+ # details why the type has been changed.
707
+ alt_field 8, 'undocumented_field_1' do
708
+ field :default, 'sint8', 'undocumented_field_8s'
709
+ field 255, 'uint8', 'undocumented_field_8u'
710
+ end
657
711
  field 9, 'uint16', 'recovery_time', :scale => 60, :unit => 'hours'
658
- field 10, 'uint16', 'undocumented_field_10' # always seems to be 340
712
+ field 10, 'uint16', 'undocumented_field_10'
659
713
  field 11, 'enum', 'undocumented_field_11'
660
714
  field 12, 'enum', 'undocumented_field_12'
661
715
  field 13, 'uint8', 'undocumented_field_13'
662
716
  field 14, 'uint16', 'running_lactate_threshold_heart_rate', :unit => 'bpm'
663
717
  field 15, 'uint16', 'running_lactate_threshold_speed', :scale => 100, :unit => 'm/s'
664
718
  field 16, 'uint16', 'undocumented_field_16' # very correlated to 14 and 15
665
- field 17, 'sint8', 'undocumented_field_17'
719
+ field 17, 'sint8', 'performance_condition'
666
720
  field 18, 'uint8', 'undocumented_field_18'
667
721
  field 19, 'uint8', 'undocumented_field_19'
722
+ field 20, 'uint8', 'anaerobic_training_effect', :scale => 10
723
+ field 21, 'sint32', 'undocumented_field_21'
724
+ field 22, 'uint8', 'undocumented_field_22'
725
+ field 23, 'uint8', 'undocumented_field_23'
726
+ field 24, 'sint32', 'undocumented_field_24'
668
727
  field 253, 'uint32', 'timestamp', :type => 'date_time'
669
728
 
670
729
  # Not part of the official ANT SDK doc. The message name is guessed and
@@ -679,10 +738,10 @@ module Fit4Ruby
679
738
  field 253, 'uint32', 'timestamp', :type => 'date_time'
680
739
 
681
740
  # Not part of the official ANT SDK doc.
682
- message 147, 'undocumented_147'
683
- field 0, 'uint32z', 'undocumented_field_0'
741
+ message 147, 'sensor_settings'
742
+ field 0, 'uint32z', 'ant_id'
684
743
  field 1, 'uint8', 'undocumented_field_1'
685
- field 2, 'string', 'undocumented_field_2'
744
+ field 2, 'string', 'name'
686
745
  field 3, 'enum', 'undocumented_field_3'
687
746
  field 4, 'enum', 'undocumented_field_4'
688
747
  field 5, 'enum', 'undocumented_field_5'
@@ -691,7 +750,7 @@ module Fit4Ruby
691
750
  field 8, 'uint8', 'undocumented_field_8'
692
751
  field 9, 'uint8', 'undocumented_field_9'
693
752
  field 10, 'uint16', 'undocumented_field_10'
694
- field 11, 'uint16', 'undocumented_field_11'
753
+ field 11, 'uint16', 'calibration_factor', :scale => 10
695
754
  field 12, 'uint8', 'undocumented_field_12'
696
755
  field 13, 'uint32', 'undocumented_field_13'
697
756
  field 14, 'uint8', 'undocumented_field_14'
@@ -720,6 +779,14 @@ module Fit4Ruby
720
779
  field 45, 'enum', 'undocumented_field_45'
721
780
  field 46, 'enum', 'undocumented_field_46'
722
781
  field 47, 'enum', 'undocumented_field_47'
782
+ field 50, 'uint8', 'undocumented_field_50'
783
+ field 51, 'enum', 'undocumented_field_51'
784
+ field 52, 'uint8', 'undocumented_field_52'
785
+ field 53, 'uint8', 'undocumented_field_53'
786
+ field 55, 'uint16', 'undocumented_field_55'
787
+ field 56, 'uint16', 'undocumented_field_56'
788
+ field 57, 'uint16', 'undocumented_field_57'
789
+ field 58, 'enum', 'undocumented_field_58'
723
790
  field 254, 'uint16', 'message_index'
724
791
 
725
792
  # Not part of the official ANT SDK doc.
@@ -729,21 +796,25 @@ module Fit4Ruby
729
796
  field 253, 'uint32', 'timestamp', :type => 'date_time'
730
797
 
731
798
  # Not part of the official ANT SDK doc.
732
- message 216, 'undocumented_216'
733
- field 0, 'uint16', 'undocumented_field_0'
734
- field 1, 'uint16', 'undocumented_field_1'
735
- field 2, 'uint32', 'undocumented_field_2'
799
+ message 216, 'heart_rate_zones'
800
+ field 0, 'uint16', 'type' # 19 for laps, 18 for sessions
801
+ field 1, 'uint16', 'lap_index'
802
+ field 2, 'uint32', 'time_in_hr_zone', :array => true, :scale => 1000, :unit => 's'
736
803
  field 5, 'uint32', 'undocumented_field_5'
737
- field 6, 'uint8', 'undocumented_field_6'
804
+ field 6, 'uint8', 'heart_rate_zones', :array => true
738
805
  field 9, 'uint16', 'undocumented_field_9'
739
806
  field 10, 'enum', 'undocumented_field_10'
740
- field 11, 'uint8', 'undocumented_field_11'
741
- field 12, 'uint8', 'undocumented_field_12'
807
+ field 11, 'uint8', 'max_heart_rate'
808
+ field 12, 'uint8', 'resting_heart_rate'
742
809
  field 13, 'uint8', 'undocumented_field_13'
743
810
  field 14, 'enum', 'undocumented_field_14'
744
811
  field 15, 'uint16', 'undocumented_field_15'
745
812
  field 253, 'uint32', 'timestamp', :type => 'date_time'
746
813
 
814
+ # Not part of the official ANT SDK doc.
815
+ message 233, 'undocumented_233'
816
+ field 2, 'byte', 'undocumented_field_2'
817
+
747
818
  end
748
819
 
749
820
  end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = HeartRateZones.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2017 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/RecordAggregator'
15
+
16
+ module Fit4Ruby
17
+
18
+ class HeartRateZones < FitDataRecord
19
+
20
+ include RecordAggregator
21
+
22
+ def initialize(field_values)
23
+ super('heart_rate_zones')
24
+
25
+ set_field_values(field_values)
26
+ end
27
+
28
+ def check(index)
29
+ unless @lap_index == index
30
+ Log.fatal "lap_index must be #{index}, not #{@lap_index}"
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = PhysiologicalMetrics.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2017 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 old_user_profile FIT message.
18
+ class PhysiologicalMetrics < FitDataRecord
19
+
20
+ # Create a new PhysiologicalMetrics object.
21
+ # @param field_values [Hash] Hash that provides initial values for certain
22
+ # fields.
23
+ def initialize(field_values = {})
24
+ super('physiological_metrics')
25
+ set_field_values(field_values)
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+
@@ -1,4 +1,4 @@
1
1
  module Fit4Ruby
2
2
  # The version number of the library.
3
- VERSION = '1.5.1'
3
+ VERSION = '1.6.0'
4
4
  end
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: 1.5.1
4
+ version: 1.6.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: 2017-02-24 00:00:00.000000000 Z
11
+ date: 2017-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -110,12 +110,14 @@ files:
110
110
  - lib/fit4ruby/GlobalFitMessage.rb
111
111
  - lib/fit4ruby/GlobalFitMessages.rb
112
112
  - lib/fit4ruby/HRV.rb
113
+ - lib/fit4ruby/HeartRateZones.rb
113
114
  - lib/fit4ruby/Lap.rb
114
115
  - lib/fit4ruby/Log.rb
115
116
  - lib/fit4ruby/Monitoring.rb
116
117
  - lib/fit4ruby/MonitoringInfo.rb
117
118
  - lib/fit4ruby/Monitoring_B.rb
118
119
  - lib/fit4ruby/PersonalRecords.rb
120
+ - lib/fit4ruby/PhysiologicalMetrics.rb
119
121
  - lib/fit4ruby/Record.rb
120
122
  - lib/fit4ruby/RecordAggregator.rb
121
123
  - lib/fit4ruby/Session.rb
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  version: '0'
150
152
  requirements: []
151
153
  rubyforge_project:
152
- rubygems_version: 2.2.2
154
+ rubygems_version: 2.2.5
153
155
  signing_key:
154
156
  specification_version: 4
155
157
  summary: Library to read GARMIN FIT files.
@@ -157,4 +159,3 @@ test_files:
157
159
  - spec/FileNameCoder_spec.rb
158
160
  - spec/FitFile_spec.rb
159
161
  - spec/GeoMath_spec.rb
160
- has_rdoc: