fit4ruby 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fit4ruby/Activity.rb +50 -1
- data/lib/fit4ruby/Converters.rb +2 -2
- data/lib/fit4ruby/GlobalFitDictionaries.rb +14 -0
- data/lib/fit4ruby/GlobalFitMessages.rb +29 -9
- data/lib/fit4ruby/Monitoring_B.rb +31 -0
- data/lib/fit4ruby/Session.rb +1 -0
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +3 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 012c8c74873a9ce1d703e72c75e14019d480db0f
|
4
|
+
data.tar.gz: 32137198f2a8a87dc473c7bdc0c3bdc978a9e31c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5c6653686b550a201b71ad021af82d79cc03b092fceda5441fd286c0a3e34ff2c7f2291b35aa5f8ed3c740060953a47b63ef1c2c895a8571cf09a0464566640
|
7
|
+
data.tar.gz: bb3b5778604e1f342163fd751c3e3beccb09c3aa8ddcebb5deb7274c1623e6d194408b54486f34837d80645aa471e5c2132236551d5bf4c8ff2fc1f3864f3a07
|
data/lib/fit4ruby/Activity.rb
CHANGED
@@ -36,6 +36,7 @@ module Fit4Ruby
|
|
36
36
|
# certain fields of the FitDataRecord.
|
37
37
|
def initialize(field_values = {})
|
38
38
|
super('activity')
|
39
|
+
@meta_field_units['total_gps_distance'] = 'm'
|
39
40
|
@num_sessions = 0
|
40
41
|
|
41
42
|
@file_id = FileId.new
|
@@ -59,7 +60,7 @@ module Fit4Ruby
|
|
59
60
|
# Perform some basic logical checks on the object and all references sub
|
60
61
|
# objects. Any errors will be reported via the Log object.
|
61
62
|
def check
|
62
|
-
unless @timestamp && @timestamp >= Time.parse('1990-01-
|
63
|
+
unless @timestamp && @timestamp >= Time.parse('1990-01-01T00:00:00+00:00')
|
63
64
|
Log.error "Activity has no valid timestamp"
|
64
65
|
end
|
65
66
|
unless @total_timer_time
|
@@ -71,6 +72,12 @@ module Fit4Ruby
|
|
71
72
|
"FIT file."
|
72
73
|
end
|
73
74
|
@sessions.each { |s| s.check(self) }
|
75
|
+
# Laps must have a consecutively growing message index.
|
76
|
+
@laps.each.with_index do |lap, index|
|
77
|
+
unless lap.message_index == index
|
78
|
+
Log.error "Lap #{index} has wrong message_index #{lap.message_index}"
|
79
|
+
end
|
80
|
+
end
|
74
81
|
end
|
75
82
|
|
76
83
|
# Convenience method that aggregates all the distances from the included
|
@@ -81,6 +88,48 @@ module Fit4Ruby
|
|
81
88
|
d
|
82
89
|
end
|
83
90
|
|
91
|
+
# Total distance convered by this activity purely computed by the GPS
|
92
|
+
# coordinates. This may differ from the distance computed by the device as
|
93
|
+
# it can be based on a purely calibrated footpod.
|
94
|
+
def total_gps_distance
|
95
|
+
timer_stops = []
|
96
|
+
# Generate a list of all timestamps where the timer was stopped.
|
97
|
+
@events.each do |e|
|
98
|
+
if e.event == 'timer' && e.event_type == 'stop_all'
|
99
|
+
timer_stops << e.timestamp
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# The first record of a FIT file can already have a distance associated
|
104
|
+
# with it. The GPS location of the first record is not where the start
|
105
|
+
# button was pressed. This introduces a slight inaccurcy when computing
|
106
|
+
# the total distance purely on the GPS coordinates found in the records.
|
107
|
+
d = 0.0
|
108
|
+
last_lat = last_long = nil
|
109
|
+
|
110
|
+
# Iterate over all the records and accumlate the distances between the
|
111
|
+
# neiboring coordinates.
|
112
|
+
@records.each do |r|
|
113
|
+
if (lat = r.position_lat) && (long = r.position_long)
|
114
|
+
if last_lat && last_long
|
115
|
+
d += Fit4Ruby::GeoMath.distance(last_lat, last_long,
|
116
|
+
lat, long)
|
117
|
+
end
|
118
|
+
if timer_stops[0] == r.timestamp
|
119
|
+
# If a stop event was found for this record timestamp we clear the
|
120
|
+
# last_* values so that the distance covered while being stopped
|
121
|
+
# is not added to the total.
|
122
|
+
last_lat = last_long = nil
|
123
|
+
timer_stops.shift
|
124
|
+
else
|
125
|
+
last_lat = lat
|
126
|
+
last_long = long
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
d
|
131
|
+
end
|
132
|
+
|
84
133
|
# Call this method to update the aggregated data fields stored in Lap and
|
85
134
|
# Session objects.
|
86
135
|
def aggregate
|
data/lib/fit4ruby/Converters.rb
CHANGED
@@ -68,11 +68,11 @@ module Fit4Ruby
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def time_to_fit_time(t)
|
71
|
-
(t - Time.parse('1989-12-
|
71
|
+
(t - Time.parse('1989-12-31T00:00:00+00:00')).to_i
|
72
72
|
end
|
73
73
|
|
74
74
|
def fit_time_to_time(ft)
|
75
|
-
Time.parse('1989-12-
|
75
|
+
Time.parse('1989-12-31T00:00:00+00:00') + ft.to_i
|
76
76
|
end
|
77
77
|
|
78
78
|
end
|
@@ -67,6 +67,9 @@ module Fit4Ruby
|
|
67
67
|
entry 5, 'critical'
|
68
68
|
|
69
69
|
dict 'device_type'
|
70
|
+
entry 0, 'position' # Just a guess
|
71
|
+
entry 3, 'acceleration' # Just a guess
|
72
|
+
entry 4, 'barometric_pressure' # Just a guess
|
70
73
|
entry 1, 'antfs'
|
71
74
|
entry 11, 'bike_power'
|
72
75
|
entry 12, 'environment_sensor_legacy'
|
@@ -159,8 +162,15 @@ module Fit4Ruby
|
|
159
162
|
dict 'garmin_product'
|
160
163
|
entry 8, 'hrm_run_single_byte_product_id'
|
161
164
|
entry 1551, 'fenix'
|
165
|
+
# The Fenix3 is rumored to have a Mediatek MT3333 GPS chipset. Not sure if
|
166
|
+
# that would be a beter name.
|
167
|
+
entry 1620, 'fenix3_gps' # Just a guess
|
162
168
|
entry 1623, 'fr620'
|
163
169
|
entry 1632, 'fr220'
|
170
|
+
# The FR620 is rumored to have a MediaTek MT3339 GPS chipset while the
|
171
|
+
# FR920XT is rumored to have a MT3333. Not sure why they have the same ID
|
172
|
+
# in the FIT file for the GPS device.
|
173
|
+
entry 1689, 'fr620_fr920xt_gps' # Just a guess
|
164
174
|
entry 1752, 'hrm_run'
|
165
175
|
entry 1765, 'fr920xt'
|
166
176
|
entry 1928, 'fr620_japan'
|
@@ -208,6 +218,10 @@ module Fit4Ruby
|
|
208
218
|
entry 0x3FFF, 'mask'
|
209
219
|
entry 0x8000, 'right'
|
210
220
|
|
221
|
+
dict 'length_type'
|
222
|
+
entry 0, 'idle'
|
223
|
+
entry 1, 'active'
|
224
|
+
|
211
225
|
dict 'manufacturer'
|
212
226
|
entry 1, 'garmin'
|
213
227
|
entry 2, 'garmin_fr405_antfs'
|
@@ -26,6 +26,7 @@ module Fit4Ruby
|
|
26
26
|
field 4, 'uint32', 'time_created', :type => 'date_time'
|
27
27
|
field 5, 'uint16', 'number'
|
28
28
|
field 6, 'uint16', 'undocumented_field_6'
|
29
|
+
field 7, 'uint32', 'undocumented_field_7'
|
29
30
|
|
30
31
|
message 12, 'sport'
|
31
32
|
field 0, 'enum', 'sport', :dict => 'sport'
|
@@ -253,13 +254,14 @@ module Fit4Ruby
|
|
253
254
|
field 4, 'uint8', 'event_group'
|
254
255
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
255
256
|
|
256
|
-
# Possibly
|
257
|
-
|
258
|
-
|
259
|
-
field
|
260
|
-
field
|
261
|
-
field
|
262
|
-
field
|
257
|
+
# Possibly which device is used as metering source.
|
258
|
+
# Not documented in FIT SDK, so these are all guesses right now.
|
259
|
+
message 22, 'metering_devices'
|
260
|
+
field 0, 'uint8', 'speed'
|
261
|
+
field 1, 'uint8', 'distance'
|
262
|
+
field 2, 'uint8', 'cadence'
|
263
|
+
field 3, 'uint8', 'altitude'
|
264
|
+
field 4, 'uint8', 'heart_rate'
|
263
265
|
field 5, 'enum', 'undocumented_field_5' # 0 or 3 seen
|
264
266
|
field 6, 'uint8', 'undocumented_field_6' # First found in FR920XT
|
265
267
|
field 14, 'uint8', 'undocumented_field_14' # First found in FR920XT
|
@@ -336,7 +338,7 @@ module Fit4Ruby
|
|
336
338
|
field 0, 'enum', 'device_index'
|
337
339
|
field 1, 'uint16', 'calories', :unit => 'kcal'
|
338
340
|
field 2, 'uint32', 'distance', :scale => 100, :unit => 'm'
|
339
|
-
field 5, 'enum', 'activity_type'
|
341
|
+
field 5, 'enum', 'activity_type', :dict => 'activity_type'
|
340
342
|
alt_field 3, 'activity_type' do
|
341
343
|
field :default, 'uint32', 'cycles', :scale => 2, :unit => 'cycles'
|
342
344
|
field [ 'walking', 'running' ], 'uint32', 'steps', :unit => 'steps'
|
@@ -351,7 +353,7 @@ module Fit4Ruby
|
|
351
353
|
field 11, 'uint16', 'local_timestamp'
|
352
354
|
field 19, 'uint16', 'active_calories', :unit => 'kcal'
|
353
355
|
field 24, 'byte', 'current_activity_type_intensity', :type => 'activity_intensity'
|
354
|
-
field 26, 'uint16', '
|
356
|
+
field 26, 'uint16', 'timestamp_16', :unit => 's'
|
355
357
|
field 29, 'uint16', 'duration_min', :unit => 'min'
|
356
358
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
357
359
|
|
@@ -383,6 +385,24 @@ module Fit4Ruby
|
|
383
385
|
field 9, 'uint16', 'undocumented_field_9' # maybe activity measurement
|
384
386
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
385
387
|
|
388
|
+
message 101, 'length'
|
389
|
+
field 0, 'enum', 'event', :dict => 'event'
|
390
|
+
field 1, 'enum', 'event_type', :dict => 'event_type'
|
391
|
+
field 2, 'uint32', 'date_time', :type => 'date_time'
|
392
|
+
field 3, 'uint32', 'total_elapsed_time', :scale => 1000, :unit => 's'
|
393
|
+
field 4, 'uint32', 'total_timer_time', :scale => 1000, :unit => 's'
|
394
|
+
field 5, 'uint16', 'total_strokes', :unit => 'strokes'
|
395
|
+
field 6, 'uint16', 'avg_speed', :scale => 1000, :unit => 'm/s'
|
396
|
+
field 7, 'enum', 'swim_stroke', :dict => 'swim_stroke'
|
397
|
+
field 9, 'uint8', 'avg_swimming_cadence', :unit => 'strokes/min'
|
398
|
+
field 10, 'uint8', 'event_group'
|
399
|
+
field 11, 'uint16', 'total_calories', :unit => 'kcal'
|
400
|
+
field 12, 'enum', 'length_type', :dict => 'length_type'
|
401
|
+
field 18, 'uint16', 'player_score'
|
402
|
+
field 19, 'uint16', 'opponent_score'
|
403
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
404
|
+
field 254, 'uint16', 'message_index'
|
405
|
+
|
386
406
|
message 103, 'monitoring_info'
|
387
407
|
field 0, 'uint32', 'local_time', :type => 'date_time'
|
388
408
|
field 1, 'enum', 'activity_type', :array => true, :dict => 'activity_type'
|
@@ -45,6 +45,37 @@ module Fit4Ruby
|
|
45
45
|
# Perform some basic logical checks on the object and all references sub
|
46
46
|
# objects. Any errors will be reported via the Log object.
|
47
47
|
def check
|
48
|
+
last_timestamp = ts_16_offset = nil
|
49
|
+
|
50
|
+
# The timestamp_16 is a 2 byte time stamp value that is used instead of
|
51
|
+
# the 4 byte timestamp field for monitoring records that have
|
52
|
+
# current_activity_type_intensity values with an activity type of 6. The
|
53
|
+
# value seems to be in seconds, but the 0 value reference does not seem
|
54
|
+
# to be included in the file. However, it can be approximated using the
|
55
|
+
# surrounding timestamp values.
|
56
|
+
@monitorings.each do |record|
|
57
|
+
if ts_16_offset
|
58
|
+
# We have already found the offset. Adjust all timestamps according
|
59
|
+
# to 'offset + timestamp_16'
|
60
|
+
if record.timestamp_16
|
61
|
+
record.timestamp = ts_16_offset + record.timestamp_16
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# We are still looking for the offset.
|
65
|
+
if record.timestamp_16 && last_timestamp
|
66
|
+
# We have a previous timestamp and found the first record with a
|
67
|
+
# timestamp_16 value set. We assume that the timestamp of this
|
68
|
+
# record is one minute after the previously found timestamp.
|
69
|
+
# That's just a guess. Who knows what the Garmin engineers were
|
70
|
+
# thinking here?
|
71
|
+
ts_16_offset = last_timestamp + 60 - record.timestamp_16
|
72
|
+
record.timestamp = ts_16_offset + record.timestamp_16
|
73
|
+
else
|
74
|
+
# Just save the timestamp of the current record.
|
75
|
+
last_timestamp = record.timestamp
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
48
79
|
end
|
49
80
|
|
50
81
|
# Create a new FitDataRecord.
|
data/lib/fit4ruby/Session.rb
CHANGED
data/lib/fit4ruby/version.rb
CHANGED
data/spec/FitFile_spec.rb
CHANGED
@@ -26,6 +26,7 @@ describe Fit4Ruby do
|
|
26
26
|
a.new_device_info({ :device_index => 1, :manufacturer => 'development',
|
27
27
|
:battery_status => 'ok' })
|
28
28
|
ts = Time.now
|
29
|
+
laps = 0
|
29
30
|
0.upto(a.total_timer_time / 60) do |mins|
|
30
31
|
ts += 60
|
31
32
|
a.new_record({
|
@@ -46,7 +47,8 @@ describe Fit4Ruby do
|
|
46
47
|
|
47
48
|
if mins > 0 && mins % 5 == 0
|
48
49
|
a.new_lap({ :timestamp => ts, :sport => 'running',
|
49
|
-
:total_cycles => 195 })
|
50
|
+
:message_index => laps, :total_cycles => 195 })
|
51
|
+
laps += 1
|
50
52
|
end
|
51
53
|
end
|
52
54
|
a.new_session({ :timestamp => ts, :sport => 'running' })
|
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: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|