fit4ruby 1.5.1 → 1.6.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: 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: