fit4ruby 3.5.0 → 3.9.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.
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = GlobalFitMessages.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, 2020 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
@@ -133,8 +133,12 @@ module Fit4Ruby
133
133
  field 148, 'enum', 'undocumented_field_148'
134
134
  field 149, 'enum', 'undocumented_field_149'
135
135
  field 151, 'enum', 'undocumented_field_151'
136
+ field 160, 'enum', 'undocumented_field_160'
137
+ field 163, 'enum', 'undocumented_field_163'
138
+ field 164, 'uint8', 'undocumented_field_164'
136
139
  field 167, 'string', 'undocumented_field_167'
137
140
  field 168, 'enum', 'undocumented_field_168'
141
+ field 170, 'uint8', 'undocumented_field_170'
138
142
 
139
143
  message 3, 'user_profile'
140
144
  field 0, 'string', 'friendly_name'
@@ -175,6 +179,10 @@ module Fit4Ruby
175
179
  field 44, 'uint8', 'undocumented_field_44'
176
180
  field 45, 'uint8z', 'undocumented_field_45'
177
181
  field 47, 'enum', 'undocumented_field_47'
182
+ field 52, 'enum', 'undocumented_field_52'
183
+ field 53, 'uint8', 'undocumented_field_53'
184
+ field 54, 'uint8', 'undocumented_field_54'
185
+ field 57, 'enum', 'undocumented_field_57'
178
186
  field 253, 'uint32', 'timestamp', :type => 'date_time'
179
187
 
180
188
  message 5, 'sdm_profile'
@@ -231,6 +239,8 @@ module Fit4Ruby
231
239
  field 11, 'enum', 'undocumented_field_11'
232
240
  field 12, 'enum', 'undocumented_field_12'
233
241
  field 13, 'enum', 'undocumented_field_13'
242
+ field 15, 'uint16', 'undocumented_field_15'
243
+ field 16, 'uint32', 'undocumented_field_16'
234
244
  field 254, 'uint16', 'message_index'
235
245
 
236
246
  message 12, 'sport'
@@ -251,6 +261,7 @@ module Fit4Ruby
251
261
  field 17, 'enum', 'undocumented_field_17'
252
262
  field 18, 'enum', 'undocumented_field_18'
253
263
  field 19, 'enum', 'undocumented_field_19', :array => true
264
+ field 21, 'enum', 'undocumented_field_21'
254
265
 
255
266
  # Not part of the official ANT SDK doc.
256
267
  message 13, 'undocumented_13'
@@ -318,10 +329,17 @@ module Fit4Ruby
318
329
  field 68, 'sint32','undocumented_field_68'
319
330
  field 69, 'uint16', 'undocumented_field_69'
320
331
  field 70, 'enum', 'undocumented_field_70'
332
+ field 71, 'enum', 'undocumented_field_71'
333
+ field 72, 'enum', 'undocumented_field_72'
321
334
  field 73, 'sint32', 'undocumented_field_73'
322
335
  field 74, 'sint32', 'undocumented_field_74'
323
336
  field 75, 'enum', 'undocumented_field_75'
324
337
  field 76, 'enum', 'undocumented_field_76'
338
+ field 78, 'enum', 'undocumented_field_78'
339
+ field 79, 'enum', 'undocumented_field_79'
340
+ field 81, 'enum', 'undocumented_field_81'
341
+ field 82, 'enum', 'undocumented_field_82'
342
+ field 83, 'enum', 'undocumented_field_83'
325
343
  field 254, 'uint16', 'message_index'
326
344
 
327
345
  message 18, 'session'
@@ -454,6 +472,8 @@ module Fit4Ruby
454
472
  field 188, 'enum', 'undocumented_field_188'
455
473
  field 189, 'uint16', 'undocumented_field_189'
456
474
  field 190, 'uint16', 'undocumented_field_190'
475
+ field 194, 'uint8', 'undocumented_field_194'
476
+ field 195, 'uint8', 'undocumented_field_195'
457
477
  field 253, 'uint32', 'timestamp', :type => 'date_time'
458
478
  field 254, 'uint16', 'message_index'
459
479
 
@@ -581,6 +601,7 @@ module Fit4Ruby
581
601
  field 13, 'sint8', 'temperature', :unit => 'C'
582
602
  field 14, 'uint32', 'undefined_field_14'
583
603
  field 15, 'uint32', 'undefined_field_15'
604
+ field 18, 'uint8', 'undefined_field_18'
584
605
  field 29, 'uint32', 'accumulated_power', :unit => 'watts'
585
606
  field 30, 'uint8', 'left_right_balance', :dict => 'left_right_balance'
586
607
  field 39, 'uint16', 'vertical_oscillation', :scale => 10, :unit => 'mm'
@@ -607,6 +628,12 @@ module Fit4Ruby
607
628
  field 71, 'uint8', 'right_power_phase', :scale => 0.7111111, :unit => 'degrees', :array => true
608
629
  field 72, 'uint8', 'right_power_phase_peak', :scale => 0.7111111, :unit => 'degrees', :array => true
609
630
  field 73, 'uint32', 'enhanced_speed', :scale => 1000, :unit => 'm/s'
631
+ field 74, 'uint32', 'undefined_value_74'
632
+ field 75, 'uint32', 'undefined_value_75'
633
+ field 76, 'uint32', 'undefined_value_76'
634
+ field 77, 'uint32', 'undefined_value_77'
635
+ field 79, 'uint32', 'undefined_value_79'
636
+ field 80, 'uint32', 'undefined_value_80'
610
637
  field 78, 'uint32', 'enhanced_elevation', :scale => 5, :offset => 500, :unit => 'm'
611
638
  field 83, 'uint16', 'vertical_ratio', :scale => 100, :unit => '%' # guessed
612
639
  field 84, 'uint16', 'gct_balance', :scale => 100, :unit => '%' # guessed
@@ -614,7 +641,13 @@ module Fit4Ruby
614
641
  field 87, 'uint16', 'undefined_value_87' # first seen on F3 FW6.80
615
642
  field 88, 'uint16', 'undefined_value_88' # first seen on F3HR FW3.60
616
643
  field 90, 'sint8', 'performance_condition' # guessed
644
+ field 100, 'sint32', 'undocumented_field_100'
645
+ field 101, 'sint32', 'undocumented_field_101'
646
+ field 107, 'enum', 'undocumented_field_107'
647
+ field 116, 'uint16', 'undocumented_field_116'
617
648
  field 108, 'uint16', 'respiration_rate', :scale => 100, :unit => 'brpm' # guessed
649
+ field 135, 'uint8', 'undocumented_field_135'
650
+ field 136, 'uint8', 'undocumented_field_136'
618
651
  field 253, 'uint32', 'timestamp', :type => 'date_time'
619
652
 
620
653
  message 21, 'event'
@@ -826,6 +859,8 @@ module Fit4Ruby
826
859
  field 18, 'sint32', 'undocumented_field_18'
827
860
  field 19, 'sint32', 'undocumented_field_19'
828
861
  field 20, 'uint16', 'undocumented_field_20'
862
+ field 21, 'sint32', 'undocumented_field_21'
863
+ field 22, 'sint32', 'undocumented_field_22'
829
864
  field 253, 'uint32', 'timestamp', :type => 'date_time'
830
865
 
831
866
  message 101, 'length'
@@ -940,6 +975,12 @@ module Fit4Ruby
940
975
  field 39, 'sint32', 'undocumented_field_39'
941
976
  field 40, 'sint32', 'undocumented_field_40'
942
977
  field 41, 'enum', 'undocumented_field_41'
978
+ field 42, 'uint8', 'undocumented_field_42'
979
+ field 43, 'sint16', 'undocumented_field_43'
980
+ field 44, 'sint16', 'undocumented_field_44'
981
+ field 45, 'sint16', 'undocumented_field_45'
982
+ field 46, 'uint8', 'undocumented_field_46'
983
+ field 48, 'uint32', 'undocumented_field_48'
943
984
  field 253, 'uint32', 'timestamp', :type => 'date_time'
944
985
 
945
986
  # Not part of the official ANT SDK doc. The message name is guessed and
@@ -976,7 +1017,7 @@ module Fit4Ruby
976
1017
  field 18, 'uint8z', 'undocumented_field_18'
977
1018
  field 19, 'uint8z', 'undocumented_field_19'
978
1019
  field 20, 'uint8z', 'undocumented_field_20'
979
- field 21, 'uint16', 'undocumented_field_21'
1020
+ field 21, 'uint16', 'wheel_size', :unit => 'mm'
980
1021
  field 25, 'uint16', 'undocumented_field_25'
981
1022
  field 26, 'uint16', 'undocumented_field_26'
982
1023
  field 27, 'uint8', 'undocumented_field_27'
@@ -1004,7 +1045,12 @@ module Fit4Ruby
1004
1045
  field 48, 'enum', 'undocumented_field_48'
1005
1046
  field 50, 'uint8', 'undocumented_field_50'
1006
1047
  field 51, 'enum', 'undocumented_field_51'
1007
- field 52, 'uint8', 'undocumented_field_52'
1048
+ # The type of this field changed from 'uint8' to 'enum' in more recent
1049
+ # devices. No idea why and what the proper selection field should be.
1050
+ alt_field 52, 'undocumented_field_51' do
1051
+ field :default, 'uint8', 'undocumented_field_52_0'
1052
+ field 0, 'enum', 'undocumented_field_52_1'
1053
+ end
1008
1054
  field 53, 'uint8', 'undocumented_field_53'
1009
1055
  field 54, 'enum', 'undocumented_field_54'
1010
1056
  field 55, 'uint16', 'undocumented_field_55'
@@ -1023,6 +1069,11 @@ module Fit4Ruby
1023
1069
  field 73, 'uint16z', 'undocumented_field_73'
1024
1070
  field 254, 'uint16', 'message_index'
1025
1071
 
1072
+ # Not part of the official ANT SDK doc.
1073
+ message 160, 'undocumented_160'
1074
+ field 3, 'uint32', 'undocumented_field_3'
1075
+ field 4, 'uint32', 'undocumented_field_4'
1076
+
1026
1077
  # Not part of the official ANT SDK doc.
1027
1078
  message 188, 'undocumented_188'
1028
1079
  field 0, 'enum', 'undocumented_field_0'
@@ -1166,6 +1217,35 @@ module Fit4Ruby
1166
1217
  field 252, 'uint8', 'undocumented_field_252'
1167
1218
  field 253, 'uint32', 'timestamp', :type => 'date_time'
1168
1219
 
1220
+ # Not part of the official ANT SDK doc.
1221
+ message 325, 'undocumented_325'
1222
+ field 0, 'uint8', 'undocumented_field_0'
1223
+ field 1, 'uint8', 'undocumented_field_1'
1224
+ field 2, 'uint8', 'undocumented_field_2'
1225
+ field 3, 'uint8', 'undocumented_field_3'
1226
+ field 4, 'uint8', 'undocumented_field_4'
1227
+ field 5, 'uint8', 'undocumented_field_5'
1228
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
1229
+
1230
+ # Not part of the official ANT SDK doc.
1231
+ message 326, 'undocumented_326'
1232
+ field 0, 'uint32', 'undocumented_field_0'
1233
+ field 1, 'uint32', 'undocumented_field_1'
1234
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
1235
+
1236
+ # Not part of the official ANT SDK doc.
1237
+ message 327, 'undocumented_327'
1238
+ field 0, 'uint8', 'undocumented_field_0'
1239
+ field 1, 'uint8', 'undocumented_field_1'
1240
+ field 2, 'uint8', 'undocumented_field_2'
1241
+ field 3, 'uint32', 'undocumented_field_3'
1242
+ field 4, 'uint32', 'undocumented_field_4'
1243
+ field 5, 'uint32', 'undocumented_field_5'
1244
+ field 6, 'enum', 'undocumented_field_6'
1245
+ field 251, 'byte', 'undocumented_field_251'
1246
+ field 252, 'uint8', 'undocumented_field_252'
1247
+ field 253, 'uint32', 'timestamp', :type => 'date_time'
1248
+
1169
1249
  # Not part of the official ANT SDK doc.
1170
1250
  message 1024, 'undocumented_1024'
1171
1251
  field 0, 'enum', 'undocumented_field_0'
data/lib/fit4ruby/Lap.rb CHANGED
@@ -12,24 +12,30 @@
12
12
 
13
13
  require 'fit4ruby/FitDataRecord'
14
14
  require 'fit4ruby/RecordAggregator'
15
+ require 'fit4ruby/FDR_DevField_Extension'
15
16
 
16
17
  module Fit4Ruby
17
18
 
18
19
  class Lap < FitDataRecord
19
20
 
20
21
  include RecordAggregator
22
+ include FDR_DevField_Extension
21
23
 
22
24
  attr_reader :records, :lengths
23
25
 
24
26
  # Create a new Lap object.
27
+ # @param top_level_record [FitDataRecord] Top level record that is Lap
28
+ # belongs to.
25
29
  # @param records [Array of Records] Records to associate with the Lap.
26
30
  # @param lengths [Array of Lengths] Lengths to associate with the Lap.
27
31
  # @param first_length_index [Fixnum] Index of the first Length in this Lap.
28
32
  # @param previous_lap [Lap] Previous Lap on same Session.
29
33
  # @param field_values [Hash] Hash that provides initial values for certain
30
34
  # fields.
31
- def initialize(records, previous_lap, field_values, first_length_index, lengths)
35
+ def initialize(top_level_record, records, previous_lap, field_values,
36
+ first_length_index, lengths)
32
37
  super('lap')
38
+ @top_level_record = top_level_record
33
39
  @lengths = lengths
34
40
  @meta_field_units['avg_stride_length'] = 'm'
35
41
  @records = records
@@ -51,6 +57,9 @@ module Fit4Ruby
51
57
  @total_elapsed_time = records.last.timestamp - @start_time
52
58
  end
53
59
 
60
+ # Create instance variables for developer fields
61
+ create_dev_field_instance_variables
62
+
54
63
  set_field_values(field_values)
55
64
  end
56
65
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = Record.rb -- Fit4Ruby - FIT file processing library for Ruby
5
5
  #
6
- # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
6
+ # Copyright (c) 2014, 2020 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
@@ -11,6 +11,7 @@
11
11
  #
12
12
 
13
13
  require 'fit4ruby/FitDataRecord'
14
+ require 'fit4ruby/FDR_DevField_Extension'
14
15
 
15
16
  module Fit4Ruby
16
17
 
@@ -18,13 +19,21 @@ module Fit4Ruby
18
19
  # of primary measurements that are associated with a certain timestamp.
19
20
  class Record < FitDataRecord
20
21
 
22
+ include FDR_DevField_Extension
23
+
21
24
  # Create a new Record object.
25
+ # @param fit_entity The FitEntity this record belongs to
22
26
  # @param field_values [Hash] Hash that provides initial values for certain
23
27
  # fields.
24
- def initialize(field_values = {})
28
+ def initialize(top_level_record, field_values = {})
25
29
  super('record')
30
+ @top_level_record = top_level_record
26
31
  @meta_field_units['pace'] = 'min/km'
27
32
  @meta_field_units['run_cadence'] = 'spm'
33
+
34
+ # Create instance variables for developer fields
35
+ create_dev_field_instance_variables
36
+
28
37
  set_field_values(field_values)
29
38
  end
30
39
 
@@ -1,4 +1,4 @@
1
1
  module Fit4Ruby
2
2
  # The version number of the library.
3
- VERSION = '3.5.0'
3
+ VERSION = '3.9.0'
4
4
  end
data/spec/FitFile_spec.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = FitFile_spec.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, 2020 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
@@ -12,115 +12,147 @@
12
12
 
13
13
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
14
 
15
+ #require "super_diff/rspec"
15
16
  require 'fit4ruby'
16
17
 
17
18
  ENV['TZ'] = 'UTC'
18
19
 
19
20
  describe Fit4Ruby do
21
+ before(:each) do
22
+ File.delete(fit_file) if File.exist?(fit_file)
23
+ expect(File.exist?(fit_file)).to be false
24
+ end
25
+
26
+ after(:each) { File.delete(fit_file) }
27
+
20
28
  let(:fit_file) { 'test.fit' }
21
- let(:timestamp) { Time.now }
22
- let(:activity) do
23
- ts = timestamp
24
- a = Fit4Ruby::Activity.new
25
- a.total_timer_time = 30 * 60.0
26
- a.new_user_data({ :age => 33, :height => 1.78, :weight => 73.0,
27
- :gender => 'male', :activity_class => 4.0,
28
- :max_hr => 178 })
29
-
30
- a.new_event({ :event => 'timer', :event_type => 'start_time' })
31
- a.new_device_info({ :timestamp => ts,
32
- :device_index => 0, :manufacturer => 'garmin',
33
- :garmin_product => 'fenix3',
34
- :serial_number => 123456789 })
35
- a.new_device_info({ :timestamp => ts,
36
- :device_index => 1, :manufacturer => 'garmin',
37
- :garmin_product => 'fenix3_gps'})
38
- a.new_device_info({ :timestamp => ts,
39
- :device_index => 2, :manufacturer => 'garmin',
40
- :garmin_product => 'hrm_run',
41
- :battery_status => 'ok' })
42
- a.new_device_info({ :timestamp => ts,
43
- :device_index => 3, :manufacturer => 'garmin',
44
- :garmin_product => 'sdm4',
45
- :battery_status => 'ok' })
46
- a.new_data_sources({ :timestamp => ts, :distance => 1,
47
- :speed => 1, :cadence => 3, :elevation => 1,
48
- :heart_rate => 2 })
49
- laps = 0
50
- 0.upto(a.total_timer_time / 60) do |mins|
51
- ts += 60
52
- a.new_record({
53
- :timestamp => ts,
54
- :position_lat => 51.5512 - mins * 0.0008,
55
- :position_long => 11.647 + mins * 0.002,
56
- :distance => 200.0 * mins,
57
- :altitude => (100 + mins * 0.5).to_i,
58
- :speed => 3.1,
59
- :vertical_oscillation => 9 + mins * 0.02,
60
- :stance_time => 235.0 * mins * 0.01,
61
- :stance_time_percent => 32.0,
62
- :heart_rate => 140 + mins,
63
- :cadence => 75,
64
- :activity_type => 'running',
65
- :fractional_cadence => (mins % 2) / 2.0
66
- })
29
+ # Round the timestamp to seconds. This is what the file format can store. A
30
+ # higher resolution would create errors during comparions.
31
+ let(:timestamp) { Time.at(Time.now.to_i) }
32
+ let(:user_data) do
33
+ {
34
+ :age => 33, :height => 1.78, :weight => 73.0,
35
+ :gender => 'male', :activity_class => 4.0,
36
+ :max_hr => 178
37
+ }
38
+ end
39
+ let(:user_profile) do
40
+ {
41
+ :friendly_name => 'Fast Runner',
42
+ :gender => 'male',
43
+ :age => 33,
44
+ :height => 1.78,
45
+ :weight => 73.0,
46
+ :resting_heart_rate => 43
47
+ }
48
+ end
49
+ def device_info_fenix3(ts)
50
+ {
51
+ :timestamp => ts,
52
+ :device_index => 0, :manufacturer => 'garmin',
53
+ :garmin_product => 'fenix3',
54
+ :serial_number => 123456789
55
+ }
56
+ end
57
+ def device_info_fenix3_gps(ts)
58
+ {
59
+ :timestamp => ts,
60
+ :device_index => 1, :manufacturer => 'garmin',
61
+ :garmin_product => 'fenix3_gps'
62
+ }
63
+ end
64
+ def device_info_hrm_run(ts, bs = 'ok')
65
+ {
66
+ :timestamp => ts,
67
+ :device_index => 2, :manufacturer => 'garmin',
68
+ :garmin_product => 'hrm_run',
69
+ :battery_status => bs
70
+ }
71
+ end
72
+ def device_info_sdm4(ts)
73
+ {
74
+ :timestamp => timestamp,
75
+ :device_index => 3, :manufacturer => 'garmin',
76
+ :garmin_product => 'sdm4',
77
+ :battery_status => 'ok'
78
+ }
79
+ end
80
+
81
+ context 'running activity' do
82
+ let(:activity) do
83
+ ts = timestamp
84
+ a = Fit4Ruby::Activity.new
85
+ a.total_timer_time = 30 * 60.0
86
+ a.new_user_data(user_data)
87
+ a.new_user_profile(user_profile)
88
+
89
+ a.new_event({ :event => 'timer', :event_type => 'start_time' })
90
+ a.new_device_info(device_info_fenix3(ts))
91
+ a.new_device_info(device_info_fenix3_gps(ts))
92
+ a.new_device_info(device_info_hrm_run(ts))
93
+ a.new_device_info(device_info_sdm4(ts))
94
+ a.new_data_sources({ :timestamp => ts, :distance => 1,
95
+ :speed => 1, :cadence => 3, :elevation => 1,
96
+ :heart_rate => 2 })
97
+ laps = 0
98
+ 0.upto(a.total_timer_time / 60) do |mins|
99
+ ts += 60
100
+ a.new_record({
101
+ :timestamp => ts,
102
+ :position_lat => 51.5512 - mins * 0.0008,
103
+ :position_long => 11.647 + mins * 0.002,
104
+ :distance => 200.0 * mins,
105
+ :altitude => (100 + mins * 0.5).to_i,
106
+ :speed => 3.1,
107
+ :vertical_oscillation => 9 + mins * 0.02,
108
+ :stance_time => 235.0 * mins * 0.01,
109
+ :stance_time_percent => 32.0,
110
+ :heart_rate => 140 + mins,
111
+ :cadence => 75,
112
+ :activity_type => 'running',
113
+ :fractional_cadence => (mins % 2) / 2.0
114
+ })
67
115
 
68
- if mins > 0 && mins % 5 == 0
69
- a.new_lap({ :timestamp => ts, :sport => 'running',
70
- :message_index => laps, :total_cycles => 195 })
71
- laps += 1
116
+ if mins > 0 && mins % 5 == 0
117
+ a.new_lap({ :timestamp => ts, :sport => 'running',
118
+ :message_index => laps, :total_cycles => 195 })
119
+ laps += 1
120
+ end
72
121
  end
73
- end
74
- a.new_session({ :timestamp => ts, :sport => 'running' })
75
- a.new_event({ :timestamp => ts, :event => 'recovery_time',
76
- :event_type => 'marker',
77
- :recovery_time => 2160 })
78
- a.new_event({ :timestamp => ts, :event => 'vo2max',
79
- :event_type => 'marker', :vo2max => 52 })
80
- a.new_event({ :timestamp => ts, :event => 'timer',
81
- :event_type => 'stop_all' })
82
- ts += 1
83
- a.new_device_info({ :timestamp => ts,
84
- :device_index => 0, :manufacturer => 'garmin',
85
- :garmin_product => 'fenix3',
86
- :serial_number => 123456789 })
87
- a.new_device_info({ :timestamp => ts,
88
- :device_index => 1, :manufacturer => 'garmin',
89
- :garmin_product => 'fenix3_gps'})
90
- a.new_device_info({ :timestamp => ts,
91
- :device_index => 2, :manufacturer => 'garmin',
92
- :garmin_product => 'hrm_run',
93
- :battery_status => 'low' })
94
- a.new_device_info({ :timestamp => ts,
95
- :device_index => 3, :manufacturer => 'garmin',
96
- :garmin_product => 'sdm4',
97
- :battery_status => 'ok' })
98
- ts += 120
99
- a.new_event({ :timestamp => ts, :event => 'recovery_hr',
100
- :event_type => 'marker', :recovery_hr => 132 })
101
-
102
- a.aggregate
103
- a
104
- end
122
+ a.new_session({ :timestamp => ts, :sport => 'running' })
123
+ a.new_event({ :timestamp => ts, :event => 'recovery_time',
124
+ :event_type => 'marker',
125
+ :recovery_time => 2160 })
126
+ a.new_event({ :timestamp => ts, :event => 'vo2max',
127
+ :event_type => 'marker', :vo2max => 52 })
128
+ a.new_event({ :timestamp => ts, :event => 'timer',
129
+ :event_type => 'stop_all' })
130
+ ts += 1
131
+ a.new_device_info(device_info_fenix3(ts))
132
+ a.new_device_info(device_info_fenix3_gps(ts))
133
+ a.new_device_info(device_info_hrm_run(ts, 'low'))
134
+ a.new_device_info(device_info_sdm4(ts))
135
+ ts += 120
136
+ a.new_event({ :timestamp => ts, :event => 'recovery_hr',
137
+ :event_type => 'marker', :recovery_hr => 132 })
105
138
 
106
- before do
107
- File.delete(fit_file) if File.exist?(fit_file)
108
- expect(File.exist?(fit_file)).to be false
109
- end
139
+ a.aggregate
140
+ a
141
+ end
110
142
 
111
- after { File.delete(fit_file) }
143
+ it 'should write an Activity FIT file and read it back' do
144
+ Fit4Ruby.write(fit_file, activity)
145
+ expect(File.exist?(fit_file)).to be true
112
146
 
113
- it 'should write an Activity FIT file and read it back' do
114
- Fit4Ruby.write(fit_file, activity)
115
- expect(File.exist?(fit_file)).to be true
147
+ b = Fit4Ruby.read(fit_file)
148
+ expect(b.laps.count).to eq 6
149
+ expect(b.lengths.count).to eq 0
150
+ expect(b.export).to eq(activity.export)
151
+ end
116
152
 
117
- b = Fit4Ruby.read(fit_file)
118
- expect(b.laps.count).to eq 6
119
- expect(b.lengths.count).to eq 0
120
- expect(b.inspect).to eq(activity.inspect)
121
153
  end
122
154
 
123
- context 'activity with Lengths' do
155
+ context 'swimming activity' do
124
156
  let(:activity) do
125
157
  ts = timestamp
126
158
  laps = 0
@@ -128,9 +160,7 @@ describe Fit4Ruby do
128
160
  a = Fit4Ruby::Activity.new
129
161
 
130
162
  a.total_timer_time = 30 * 60.0
131
- a.new_device_info({ :timestamp => ts,
132
- :device_index => 0, :manufacturer => 'garmin',
133
- :serial_number => 123456789 })
163
+ a.new_device_info(device_info_fenix3(ts))
134
164
 
135
165
  0.upto(a.total_timer_time / 60) do |mins|
136
166
  ts += 60
@@ -144,6 +174,7 @@ describe Fit4Ruby do
144
174
  lengths += 1
145
175
  end
146
176
  end
177
+ a.aggregate
147
178
  a
148
179
  end
149
180
 
@@ -156,9 +187,76 @@ describe Fit4Ruby do
156
187
  expect(b.lengths.count).to eq 6
157
188
  expect(b.laps.select { |l| l.sport == 'swimming' }.count).to eq 6
158
189
  expect(b.lengths.select { |l| l.total_strokes == 45 }.count).to eq 6
159
- expect(b.inspect).to eq(activity.inspect)
190
+ expect(b.export).to eq(activity.export)
191
+ end
192
+
193
+ end
194
+
195
+ context 'activity with developer fields' do
196
+ let(:activity) do
197
+ ts = timestamp
198
+ laps = 0
199
+ lengths = 0
200
+ a = Fit4Ruby::Activity.new
201
+
202
+ a.total_timer_time = 30 * 60.0
203
+ a.new_device_info(device_info_fenix3(ts))
204
+ a.new_developer_data_id({
205
+ application_id: [ 24, 251, 44, 240, 26, 75, 67, 13,
206
+ 173, 102, 152, 140, 132, 116, 33, 244 ],
207
+ application_version: 77
208
+ })
209
+ a.new_field_description({
210
+ developer_data_index: 0,
211
+ field_definition_number: 0,
212
+ fit_base_type_id: 132,
213
+ field_name: 'Power',
214
+ units: 'Watts',
215
+ native_mesg_num: 20,
216
+ native_field_num: 7
217
+ })
218
+ a.new_data_sources({ :timestamp => ts, :distance => 1,
219
+ :speed => 1, :cadence => 3, :elevation => 1,
220
+ :heart_rate => 2 })
221
+ laps = 0
222
+ 0.upto(a.total_timer_time / 60) do |mins|
223
+ ts += 60
224
+ a.new_record({
225
+ :timestamp => ts,
226
+ :position_lat => 51.5512 - mins * 0.0008,
227
+ :position_long => 11.647 + mins * 0.002,
228
+ :distance => 200.0 * mins,
229
+ :altitude => (100 + mins * 0.5).to_i,
230
+ :speed => 3.1,
231
+ :vertical_oscillation => 9 + mins * 0.02,
232
+ :stance_time => 235.0 * mins * 0.01,
233
+ :stance_time_percent => 32.0,
234
+ :heart_rate => 140 + mins,
235
+ :cadence => 75,
236
+ :activity_type => 'running',
237
+ :fractional_cadence => (mins % 2) / 2.0,
238
+ :Power_18FB2CF01A4B430DAD66988C847421F4 => 240
239
+ })
240
+
241
+ if mins > 0 && mins % 5 == 0
242
+ a.new_lap({ :timestamp => ts, :sport => 'running',
243
+ :message_index => laps, :total_cycles => 195 })
244
+ laps += 1
245
+ end
246
+ end
247
+ a.aggregate
248
+ a
160
249
  end
161
250
 
251
+ it 'should write an Activity FIT file and read it back' do
252
+ Fit4Ruby.write(fit_file, activity)
253
+ expect(File.exist?(fit_file)).to be true
254
+
255
+ # This currently does not work as the saving of developer fields is not
256
+ # yet implemented.
257
+ #b = Fit4Ruby.read(fit_file)
258
+ #expect(b.export).to eq(activity.export)
259
+ end
162
260
  end
163
261
 
164
262
  end