fit4ruby 3.5.0 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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