fit4ruby 0.0.1
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 +7 -0
- data/COPYING +280 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +21 -0
- data/README.md +16 -0
- data/Rakefile +19 -0
- data/fit4ruby.gemspec +30 -0
- data/lib/fit4ruby.rb +26 -0
- data/lib/fit4ruby/Activity.rb +119 -0
- data/lib/fit4ruby/Converters.rb +58 -0
- data/lib/fit4ruby/FitDataRecord.rb +79 -0
- data/lib/fit4ruby/FitDefinition.rb +54 -0
- data/lib/fit4ruby/FitDefinitionField.rb +137 -0
- data/lib/fit4ruby/FitFile.rb +154 -0
- data/lib/fit4ruby/FitFileId.rb +31 -0
- data/lib/fit4ruby/FitFilter.rb +26 -0
- data/lib/fit4ruby/FitHeader.rb +55 -0
- data/lib/fit4ruby/FitMessageIdMapper.rb +53 -0
- data/lib/fit4ruby/FitMessageRecord.rb +77 -0
- data/lib/fit4ruby/FitRecord.rb +80 -0
- data/lib/fit4ruby/FitRecordHeader.rb +39 -0
- data/lib/fit4ruby/GlobalFitDictList.rb +68 -0
- data/lib/fit4ruby/GlobalFitDictionaries.rb +302 -0
- data/lib/fit4ruby/GlobalFitMessage.rb +189 -0
- data/lib/fit4ruby/GlobalFitMessages.rb +235 -0
- data/lib/fit4ruby/Lap.rb +44 -0
- data/lib/fit4ruby/Log.rb +45 -0
- data/lib/fit4ruby/Record.rb +56 -0
- data/lib/fit4ruby/Session.rb +110 -0
- data/lib/fit4ruby/version.rb +3 -0
- data/tasks/changelog.rake +169 -0
- data/tasks/gem.rake +52 -0
- data/tasks/rdoc.rake +14 -0
- data/tasks/test.rake +7 -0
- data/test/FitFile_spec.rb +31 -0
- metadata +137 -0
@@ -0,0 +1,189 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = GlobalFitMessage.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014 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/GlobalFitDictList'
|
14
|
+
require 'fit4ruby/Converters'
|
15
|
+
|
16
|
+
module Fit4Ruby
|
17
|
+
|
18
|
+
class GlobalFitMessage
|
19
|
+
|
20
|
+
attr_reader :name, :number, :fields
|
21
|
+
|
22
|
+
class Field
|
23
|
+
|
24
|
+
include Converters
|
25
|
+
|
26
|
+
attr_reader :type, :name, :opts
|
27
|
+
|
28
|
+
def initialize(type, name, opts = {})
|
29
|
+
@type = type
|
30
|
+
@name = name
|
31
|
+
@opts = opts
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_machine(value)
|
35
|
+
return nil if value.nil?
|
36
|
+
|
37
|
+
if @opts.include?(:dict) &&
|
38
|
+
(dict = GlobalFitDictionaries[@opts[:dict]])
|
39
|
+
return [ dict.name(value) || "Undocumented value #{value}", nil ]
|
40
|
+
end
|
41
|
+
|
42
|
+
case @opts[:type]
|
43
|
+
when 'coordinate'
|
44
|
+
value *= 180.0 / 2147483648
|
45
|
+
when 'date_time'
|
46
|
+
value = fit_time_to_time(value)
|
47
|
+
end
|
48
|
+
value /= @opts[:scale].to_f if @opts[:scale]
|
49
|
+
value -= @opts[:offset] if @opts[:offset]
|
50
|
+
value
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_human(value)
|
54
|
+
return nil if value.nil?
|
55
|
+
|
56
|
+
if @opts.include?(:dict) &&
|
57
|
+
(dict = GlobalFitDictionaries[@opts[:dict]])
|
58
|
+
return [ dict.name(value) || "Undocumented value #{value}", nil ]
|
59
|
+
end
|
60
|
+
|
61
|
+
value /= @opts[:scale].to_f if @opts[:scale]
|
62
|
+
value -= @opts[:offset] if @opts[:offset]
|
63
|
+
|
64
|
+
case @opts[:type]
|
65
|
+
when 'coordinate'
|
66
|
+
value *= 180.0 / 2147483648
|
67
|
+
when 'date_time'
|
68
|
+
value = fit_time_to_time(value).strftime("%Y-%m-%d %H:%M:%S")
|
69
|
+
when 'duration'
|
70
|
+
value = secsToDHMS(value)
|
71
|
+
end
|
72
|
+
[ value, @opts[:unit] ]
|
73
|
+
end
|
74
|
+
|
75
|
+
def native_to_fit(value)
|
76
|
+
return nil if value.nil?
|
77
|
+
|
78
|
+
if @opts.include?(:dict) && (dict = GlobalFitDictionaries[@opts[:dict]])
|
79
|
+
return dict.value_by_name(value)
|
80
|
+
end
|
81
|
+
|
82
|
+
value = (value * @opts[:scale].to_f).to_i if @opts[:scale]
|
83
|
+
value += @opts[:offset] if @opts[:offset]
|
84
|
+
|
85
|
+
case @opts[:type]
|
86
|
+
when 'coordinate'
|
87
|
+
value *= 2147483648.0 / 180.0
|
88
|
+
when 'date_time'
|
89
|
+
value = time_to_fit_time(value)
|
90
|
+
end
|
91
|
+
|
92
|
+
value
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s(value)
|
96
|
+
return "[no value]" if value.nil?
|
97
|
+
|
98
|
+
human_readable = to_human(value)
|
99
|
+
"#{human_readable[0]}" +
|
100
|
+
"#{ human_readable[1] ? " #{human_readable[1]}" : ''}"
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize(name, number)
|
106
|
+
@name = name
|
107
|
+
@number = number
|
108
|
+
@fields = {}
|
109
|
+
end
|
110
|
+
|
111
|
+
def field(number, type, name, opts = {})
|
112
|
+
if @fields.include?(number)
|
113
|
+
raise "Field #{number} has already been defined"
|
114
|
+
end
|
115
|
+
@fields[number] = Field.new(type, name, opts)
|
116
|
+
end
|
117
|
+
|
118
|
+
def write(io, local_message_type)
|
119
|
+
header = FitRecordHeader.new
|
120
|
+
header.normal = 0
|
121
|
+
header.message_type = 1
|
122
|
+
header.local_message_type = local_message_type
|
123
|
+
header.write(io)
|
124
|
+
|
125
|
+
definition = FitDefinition.new
|
126
|
+
definition.global_message_number = @number
|
127
|
+
definition.setup(self)
|
128
|
+
definition.write(io)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
class GlobalFitMessageList
|
134
|
+
|
135
|
+
def initialize(&block)
|
136
|
+
@current_message = nil
|
137
|
+
@messages = {}
|
138
|
+
instance_eval(&block) if block_given?
|
139
|
+
end
|
140
|
+
|
141
|
+
def message(number, name)
|
142
|
+
if @messages.include?(number)
|
143
|
+
raise "Message #{number} has already been defined"
|
144
|
+
end
|
145
|
+
@messages[number] = @current_message = GlobalFitMessage.new(name, number)
|
146
|
+
end
|
147
|
+
|
148
|
+
def each
|
149
|
+
@messages.each_value do |message|
|
150
|
+
yield(message)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def write(io)
|
155
|
+
# The FIT file supports more than 16 global message types. But only 16
|
156
|
+
# can be declared as local message types at any point of time. If there
|
157
|
+
# are more then 16 messages, the current subset must be declared before
|
158
|
+
# it's being used in the data records of the file.
|
159
|
+
# Since we currently have 16 or less message types, we just write them
|
160
|
+
# all upfront before the data records.
|
161
|
+
if @messages.length > 16
|
162
|
+
raise 'Cannot support more than 16 message types!'
|
163
|
+
end
|
164
|
+
|
165
|
+
local_message_type = 0
|
166
|
+
@messages.each do |number, message|
|
167
|
+
message.write(io, local_message_type)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def find_by_name(name)
|
172
|
+
@messages.each_value{ |m| return m if m.name == name }
|
173
|
+
end
|
174
|
+
|
175
|
+
def field(number, type, name, opts = {})
|
176
|
+
unless @current_message
|
177
|
+
raise "You must define a message first"
|
178
|
+
end
|
179
|
+
@current_message.field(number, type, name, opts)
|
180
|
+
end
|
181
|
+
|
182
|
+
def [](number)
|
183
|
+
@messages[number]
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = GlobalFitMessages.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014 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/GlobalFitMessage'
|
14
|
+
|
15
|
+
module Fit4Ruby
|
16
|
+
|
17
|
+
GlobalFitMessages = GlobalFitMessageList.new do
|
18
|
+
message 0, 'file_id'
|
19
|
+
field 0, 'enum', 'type', :dict => 'file'
|
20
|
+
field 1, 'uint16', 'manufacturer', :dict => 'manufacturer'
|
21
|
+
field 2, 'uint16', 'product', :dict => 'product'
|
22
|
+
field 3, 'uint32z', 'serial_number'
|
23
|
+
field 4, 'uint32', 'time_created', :type => 'date_time'
|
24
|
+
field 5, 'uint16', 'number'
|
25
|
+
|
26
|
+
message 18, 'session'
|
27
|
+
field 0, 'enum', 'event', :dict => 'event'
|
28
|
+
field 1, 'enum', 'event_type', :dict => 'event_type'
|
29
|
+
field 2, 'uint32', 'start_time', :type => 'date_time'
|
30
|
+
field 3, 'sint32', 'start_position_lat', :type => 'coordinate'
|
31
|
+
field 4, 'sint32', 'start_position_long', :type => 'coordinate'
|
32
|
+
field 5, 'enum', 'sport', :dict => 'sport'
|
33
|
+
field 6, 'enum', 'sub_sport', :dict => 'sub_sport'
|
34
|
+
field 7, 'uint32', 'total_elapsed_time', :type => 'duration', :scale => 1000
|
35
|
+
field 8, 'uint32', 'total_timer_time', :type => 'duration', :scale => 1000
|
36
|
+
field 9, 'uint32', 'total_distance', :scale => 100, :unit => 'm'
|
37
|
+
field 10, 'uint32', 'total_strides', :unit => 'strides'
|
38
|
+
field 11, 'uint16', 'total_calories', :unit => 'kcal'
|
39
|
+
field 13, 'uint16', 'total_fat_calories', :unit => 'kcal'
|
40
|
+
field 14, 'uint16', 'avg_speed', :scale => 1000, :unit => 'm/s'
|
41
|
+
field 15, 'uint16', 'max_speed', :scale => 1000, :unit => 'm/s'
|
42
|
+
field 16, 'uint8', 'avg_heart_rate', :unit => 'bpm'
|
43
|
+
field 17, 'uint8', 'max_heart_rate', :unit => 'bpm'
|
44
|
+
field 18, 'uint8', 'avg_running_cadence', :unit => 'strides/min'
|
45
|
+
field 19, 'uint8', 'max_running_cadence', :unit => 'strides/min'
|
46
|
+
field 22, 'uint16', 'total_ascent', :unit => 'm'
|
47
|
+
field 23, 'uint16', 'total_descent', :unit => 'm'
|
48
|
+
field 24, 'uint8', 'total_training_effect', :scale => 10
|
49
|
+
field 25, 'uint16', 'first_lap_index'
|
50
|
+
field 26, 'uint16', 'num_laps'
|
51
|
+
field 27, 'uint8', 'event_group'
|
52
|
+
field 28, 'enum', 'trigger', :dict => 'session_trigger'
|
53
|
+
field 29, 'sint32', 'nec_lat', :type => 'coordinate'
|
54
|
+
field 30, 'sint32', 'nec_long', :type => 'coordinate'
|
55
|
+
field 31, 'sint32', 'swc_lat', :type => 'coordinate'
|
56
|
+
field 32, 'sint32', 'swc_long', :type => 'coordinate'
|
57
|
+
field 81, 'enum', 'undocumented_field_81'
|
58
|
+
field 89, 'uint16', 'avg_vertical_oscillation', :scale => 10, :unit => 'mm'
|
59
|
+
field 90, 'uint16', 'avg_stance_time_percent', :scale => 100, :unit => 'percent'
|
60
|
+
field 91, 'uint16', 'avg_stance_time', :scale => 10, :unit => 'ms'
|
61
|
+
field 92, 'uint8', 'avg_fraction_cadence', :scale => 128
|
62
|
+
field 93, 'uint8', 'max_fractional_cadence', :scale => 128
|
63
|
+
field 94, 'uint8', 'total_fractional_cycles', :scale => 128
|
64
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
65
|
+
field 254, 'uint16', 'message_index'
|
66
|
+
|
67
|
+
message 19, 'lap'
|
68
|
+
field 0, 'enum', 'event', :dict => 'event'
|
69
|
+
field 1, 'enum', 'event_type', :dict => 'event_type'
|
70
|
+
field 2, 'uint32', 'start_time', :type => 'date_time'
|
71
|
+
field 3, 'sint32', 'start_position_lat', :type => 'coordinate'
|
72
|
+
field 4, 'sint32', 'start_position_long', :type => 'coordinate'
|
73
|
+
field 5, 'sint32', 'end_position_lat', :type => 'coordinate'
|
74
|
+
field 6, 'sint32', 'end_position_long', :type => 'coordinate'
|
75
|
+
field 7, 'uint32', 'total_elapsed_time', :type => 'duration', :scale => 1000
|
76
|
+
field 8, 'uint32', 'total_timer_time', :type => 'duration', :scale => 1000
|
77
|
+
field 9, 'uint32', 'total_distance', :scale => 100, :unit => 'm'
|
78
|
+
field 10, 'uint32', 'total_strides', :unit => 'strides'
|
79
|
+
field 11, 'uint16', 'total_calories', :unit => 'kcal'
|
80
|
+
field 12, 'uint16', 'total_fat_calories', :unit => 'kcal'
|
81
|
+
field 13, 'uint16', 'avg_speed', :scale => 1000, :unit => 'm/s'
|
82
|
+
field 14, 'uint16', 'max_speed', :scale => 1000, :unit => 'm/s'
|
83
|
+
field 15, 'uint8', 'avg_heart_rate', :unit => 'bpm'
|
84
|
+
field 16, 'uint8', 'max_heart_rate', :unit => 'bpm'
|
85
|
+
field 17, 'uint8', 'avg_running_cadence', :unit => 'strides'
|
86
|
+
field 18, 'uint8', 'max_running_cadence', :unit => 'strides'
|
87
|
+
field 21, 'uint16', 'total_ascent', :unit => 'm'
|
88
|
+
field 22, 'uint16', 'total_descent', :unit => 'm'
|
89
|
+
field 23, 'enum', 'intensity', :dict => 'intensity'
|
90
|
+
field 24, 'enum', 'lap_trigger', :dict => 'lap_trigger'
|
91
|
+
field 25, 'enum', 'sport', :dict => 'sport'
|
92
|
+
field 26, 'uint8', 'event_group'
|
93
|
+
field 27, 'sint32', 'nec_lat', :type => 'coordinate'
|
94
|
+
field 28, 'sint32', 'nec_long', :type => 'coordinate'
|
95
|
+
field 29, 'sint32', 'swc_lat', :type => 'coordinate'
|
96
|
+
field 30, 'sint32', 'swc_long', :type => 'coordinate'
|
97
|
+
field 39, 'enum', 'sub_sport', :dict => 'sub_sport'
|
98
|
+
field 71, 'uint16', 'wkt_step_index'
|
99
|
+
field 72, 'enum', 'undocumented_field_72'
|
100
|
+
field 77, 'uint16', 'avg_vertical_oscillation', :scale => 10, :unit => 'mm'
|
101
|
+
field 78, 'uint16', 'avg_stance_time_percent', :scale => 100, :unit => 'percent'
|
102
|
+
field 79, 'uint16', 'avg_stance_time', :scale => 10, :unit => 'ms'
|
103
|
+
field 80, 'uint8', 'avg_fractional_cadence', :scale => 128
|
104
|
+
field 81, 'uint8', 'max_fractional_cadence', :scale => 128
|
105
|
+
field 82, 'uint8', 'total_fractional_cycles', :scale => 128
|
106
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
107
|
+
field 254, 'uint16', 'message_index'
|
108
|
+
|
109
|
+
message 20, 'record'
|
110
|
+
field 0, 'sint32', 'position_lat', :type => 'coordinate'
|
111
|
+
field 1, 'sint32', 'position_long', :type => 'coordinate'
|
112
|
+
field 2, 'uint16', 'altitude', :scale => 5, :offset => 500, :unit => 'm'
|
113
|
+
field 3, 'uint8', 'heart_rate', :unit => 'bpm'
|
114
|
+
field 4, 'uint8', 'cadence', :unit => 'rpm'
|
115
|
+
field 5, 'uint32', 'distance', :scale => 100, :unit => 'm'
|
116
|
+
field 6, 'uint16', 'speed', :scale => 1000, :unit => 'm/s'
|
117
|
+
field 39, 'uint16', 'vertical_oscillation', :scale => 10, :unit => 'mm'
|
118
|
+
field 40, 'uint16', 'stance_time_percent', :scale => 100, :unit => 'percent'
|
119
|
+
field 41, 'uint16', 'stance_time', :scale => 10, :unit => 'ms'
|
120
|
+
field 42, 'enum', 'activity_type', :dict => 'activity_type'
|
121
|
+
field 53, 'uint8', 'fractional_cadence', :scale => 128 # Just a guess
|
122
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
123
|
+
|
124
|
+
message 21, 'event'
|
125
|
+
field 0, 'enum', 'event', :dict => 'event'
|
126
|
+
field 1, 'enum', 'event_type', :dict => 'event_type'
|
127
|
+
field 2, 'uint16', 'data16'
|
128
|
+
field 3, 'uint32', 'data'
|
129
|
+
field 4, 'uint8', 'event_group'
|
130
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
131
|
+
|
132
|
+
# Possibly the signal quality of the best 6 satellites; Not documented in
|
133
|
+
# FIT SDK
|
134
|
+
message 22, 'gps_signals'
|
135
|
+
field 0, 'uint8', 'Satellite 1'
|
136
|
+
field 1, 'uint8', 'Satellite 2'
|
137
|
+
field 2, 'uint8', 'Satellite 3'
|
138
|
+
field 3, 'uint8', 'Satellite 4'
|
139
|
+
field 4, 'uint8', 'Satellite 5'
|
140
|
+
field 5, 'enum', 'lock_status'
|
141
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
142
|
+
|
143
|
+
message 23, 'device_info'
|
144
|
+
field 0, 'uint8', 'device_index'
|
145
|
+
field 1, 'uint8', 'device_type', :dict => 'device_type'
|
146
|
+
field 2, 'uint16', 'manufacturer', :dict => 'manufacturer'
|
147
|
+
field 3, 'uint32z', 'serial_number'
|
148
|
+
field 4, 'uint16', 'product', :dict => 'product'
|
149
|
+
field 5, 'uint16', 'software_version', :scale => 100
|
150
|
+
field 6, 'uint8', 'hardware_version'
|
151
|
+
field 7, 'uint32', 'cum_operating_time', :type => 'duration'
|
152
|
+
field 8, 'uint32', 'undocumented_field_8'
|
153
|
+
field 9, 'uint8', 'undocumented_field_9'
|
154
|
+
field 10, 'uint16', 'battery_voltage', :scale => 256, :unit => 'V'
|
155
|
+
field 11, 'uint8', 'battery_status', :dict => 'battery_status'
|
156
|
+
field 15, 'uint32', 'rx_packets_ok' # just a guess
|
157
|
+
field 16, 'uint32', 'rx_packets_err' # just a guess
|
158
|
+
field 20, 'uint8z', 'undocumented_field_20'
|
159
|
+
field 21, 'uint16z', 'undocumented_field_21'
|
160
|
+
field 22, 'enum', 'undocumented_field_22'
|
161
|
+
field 23, 'uint8', 'undocumented_field_23'
|
162
|
+
field 25, 'enum', 'undocumented_field_25'
|
163
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
164
|
+
|
165
|
+
message 34, 'activity'
|
166
|
+
field 0, 'uint32', 'total_timer_time', :type => 'duration', :scale => 1000
|
167
|
+
field 1, 'uint16', 'num_sessions'
|
168
|
+
field 2, 'enum', 'type', :dict => 'activity_type'
|
169
|
+
field 3, 'enum', 'event', :dict => 'event'
|
170
|
+
field 4, 'enum', 'event_type', :dict => 'event_type'
|
171
|
+
field 5, 'uint32', 'local_timestamp', :type => 'date_time'
|
172
|
+
field 6, 'uint8', 'event_group'
|
173
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
174
|
+
|
175
|
+
message 49, 'file_creator'
|
176
|
+
field 0, 'uint16', 'software_version'
|
177
|
+
field 1, 'uint8', 'hardware_version'
|
178
|
+
|
179
|
+
# Not part of the official ANT SDK doc
|
180
|
+
message 79, 'user_profile'
|
181
|
+
field 0, 'uint16', 'undocumented_field_0' # seems to strongly correlate with vo2max
|
182
|
+
field 1, 'uint8', 'age', :unit => 'years'
|
183
|
+
field 2, 'uint8', 'height', :scale => 100, :unit => 'm'
|
184
|
+
field 3, 'uint16', 'weight', :scale => 10, :unit => 'kg'
|
185
|
+
field 4, 'enum', 'gender', :dict => 'gender'
|
186
|
+
field 5, 'enum', 'activity_class', :scale => 10
|
187
|
+
field 6, 'uint8', 'max_hr', :unit => 'bpm'
|
188
|
+
field 7, 'sint8', 'undocumented_field_7' # seems to be always 1
|
189
|
+
field 8, 'uint16', 'recovery_time', :scale => 60, :unit => 'hours'
|
190
|
+
field 9, 'uint16', 'undocumented_field_9' # maybe activity measurement
|
191
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
192
|
+
|
193
|
+
# Not part of the official ANT SDK doc
|
194
|
+
message 113, 'personal_records'
|
195
|
+
field 0, 'uint16', 'longest_distance'
|
196
|
+
field 1, 'enum', 'undocumented_field_1' # Seems to be always 1
|
197
|
+
field 2, 'uint32', 'distance', :scale => 100, :unit => 'm'
|
198
|
+
# If longest_distance is 1, field 3 is the distance, not a duration!
|
199
|
+
field 3, 'uint32', 'duration', :scale => 1000, :type => 'duration'
|
200
|
+
field 4, 'uint32', 'start_time', :type => 'date_time'
|
201
|
+
field 5, 'enum', 'new_record'
|
202
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
203
|
+
|
204
|
+
# Not part of the official ANT SDK doc
|
205
|
+
# The values in this message seem to be related to the activity history.
|
206
|
+
# If no HRM is used, most of them are 0. Fields 4, 7, 9 and 10 always have
|
207
|
+
# non-zero values.
|
208
|
+
message 140, 'undocumented_140'
|
209
|
+
field 0, 'uint8', 'max_heart_rate', :unit => 'bpm'
|
210
|
+
field 1, 'uint8', 'undocumented_field_1'
|
211
|
+
field 2, 'sint32', 'undocumented_field_2'
|
212
|
+
field 3, 'sint32', 'undocumented_field_3'
|
213
|
+
field 4, 'uint8', 'total_training_effect', :scale => 10
|
214
|
+
field 5, 'sint32', 'undocumented_field_5'
|
215
|
+
field 6, 'sint32', 'undocumented_field_6'
|
216
|
+
field 7, 'sint32', 'undocumented_field_7'
|
217
|
+
field 8, 'uint8', 'undocumented_field_8'
|
218
|
+
field 9, 'uint16', 'recovery_time', :scale => 60, :unit => 'hours'
|
219
|
+
field 10, 'uint16', 'undocumented_field_10' # always seems to be 340
|
220
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
221
|
+
|
222
|
+
# Not part of the official ANT SDK doc
|
223
|
+
message 141, 'gps_ephemeris'
|
224
|
+
field 0, 'enum', 'valid' # 0 if no data cached, 1 else
|
225
|
+
field 1, 'uint32', 'interval_start', :type => 'date_time'
|
226
|
+
field 2, 'uint32', 'interval_end', :type => 'date_time'
|
227
|
+
field 3, 'uint32', 'undocumented_field_3'
|
228
|
+
field 4, 'sint32', 'undocumented_field_4'
|
229
|
+
field 5, 'sint32', 'undocumented_field_5'
|
230
|
+
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
data/lib/fit4ruby/Lap.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = Lap.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2014 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
|
+
module Fit4Ruby
|
14
|
+
|
15
|
+
class Lap
|
16
|
+
|
17
|
+
def set(field, value)
|
18
|
+
case field
|
19
|
+
when 'start_time'
|
20
|
+
@start_time = value
|
21
|
+
when 'total_timer_time'
|
22
|
+
@duration = value
|
23
|
+
when 'avg_speed'
|
24
|
+
@avg_speed = value
|
25
|
+
when 'avg_heart_rate'
|
26
|
+
@avg_heart_rate = value
|
27
|
+
when 'max_heart_rate'
|
28
|
+
@max_heart_rate = value
|
29
|
+
when 'avg_vertical_oscillation'
|
30
|
+
@avg_vertical_oscillation = value
|
31
|
+
when 'avg_stance_time'
|
32
|
+
@avg_stance_time = value
|
33
|
+
when 'avg_running_cadence'
|
34
|
+
@avg_running_cadence = 2 * value
|
35
|
+
when 'avg_fraction_cadence'
|
36
|
+
@avg_running_cadence += 2 * value
|
37
|
+
else
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|