fit4ruby 3.7.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/fit4ruby.gemspec +2 -2
- data/lib/fit4ruby/Activity.rb +118 -55
- data/lib/fit4ruby/BDFieldNameTranslator.rb +36 -0
- data/lib/fit4ruby/FDR_DevField_Extension.rb +81 -0
- data/lib/fit4ruby/FieldDescription.rb +22 -10
- data/lib/fit4ruby/FileId.rb +2 -1
- data/lib/fit4ruby/FitDataRecord.rb +84 -31
- data/lib/fit4ruby/FitDefinition.rb +11 -4
- data/lib/fit4ruby/FitDefinitionField.rb +4 -4
- data/lib/fit4ruby/FitDefinitionFieldBase.rb +15 -6
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +1 -1
- data/lib/fit4ruby/FitFile.rb +2 -0
- data/lib/fit4ruby/FitMessageRecord.rb +23 -18
- data/lib/fit4ruby/FitRecord.rb +2 -1
- data/lib/fit4ruby/FitTypeDefs.rb +2 -2
- data/lib/fit4ruby/GlobalFitDictionaries.rb +197 -2
- data/lib/fit4ruby/GlobalFitMessage.rb +79 -14
- data/lib/fit4ruby/GlobalFitMessages.rb +52 -6
- data/lib/fit4ruby/Lap.rb +10 -1
- data/lib/fit4ruby/Record.rb +11 -2
- data/lib/fit4ruby/Workout.rb +31 -0
- data/lib/fit4ruby/WorkoutStep.rb +32 -0
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +198 -100
- metadata +16 -13
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
139
|
+
a.aggregate
|
140
|
+
a
|
141
|
+
end
|
110
142
|
|
111
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
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
|
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(
|
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.
|
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
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fit4ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.4.8
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: 2.4.8
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: yard
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 13.0.3
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 13.0.3
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- fit4ruby.gemspec
|
113
113
|
- lib/fit4ruby.rb
|
114
114
|
- lib/fit4ruby/Activity.rb
|
115
|
+
- lib/fit4ruby/BDFieldNameTranslator.rb
|
115
116
|
- lib/fit4ruby/CRC16.rb
|
116
117
|
- lib/fit4ruby/Converters.rb
|
117
118
|
- lib/fit4ruby/DataSources.rb
|
@@ -120,6 +121,7 @@ files:
|
|
120
121
|
- lib/fit4ruby/DumpedField.rb
|
121
122
|
- lib/fit4ruby/EPO_Data.rb
|
122
123
|
- lib/fit4ruby/Event.rb
|
124
|
+
- lib/fit4ruby/FDR_DevField_Extension.rb
|
123
125
|
- lib/fit4ruby/FieldDescription.rb
|
124
126
|
- lib/fit4ruby/FileCreator.rb
|
125
127
|
- lib/fit4ruby/FileId.rb
|
@@ -162,6 +164,8 @@ files:
|
|
162
164
|
- lib/fit4ruby/TrainingStatus.rb
|
163
165
|
- lib/fit4ruby/UserData.rb
|
164
166
|
- lib/fit4ruby/UserProfile.rb
|
167
|
+
- lib/fit4ruby/Workout.rb
|
168
|
+
- lib/fit4ruby/WorkoutStep.rb
|
165
169
|
- lib/fit4ruby/version.rb
|
166
170
|
- spec/FileNameCoder_spec.rb
|
167
171
|
- spec/FitFile_spec.rb
|
@@ -174,7 +178,7 @@ homepage: https://github.com/scrapper/fit4ruby
|
|
174
178
|
licenses:
|
175
179
|
- GNU GPL version 2
|
176
180
|
metadata: {}
|
177
|
-
post_install_message:
|
181
|
+
post_install_message:
|
178
182
|
rdoc_options: []
|
179
183
|
require_paths:
|
180
184
|
- lib
|
@@ -189,9 +193,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
193
|
- !ruby/object:Gem::Version
|
190
194
|
version: '0'
|
191
195
|
requirements: []
|
192
|
-
|
193
|
-
|
194
|
-
signing_key:
|
196
|
+
rubygems_version: 3.2.32
|
197
|
+
signing_key:
|
195
198
|
specification_version: 4
|
196
199
|
summary: Library to read and write GARMIN FIT files.
|
197
200
|
test_files:
|