fit4ruby 2.0.0 → 3.0.0
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 +16 -4
- data/lib/fit4ruby/DeveloperDataId.rb +0 -3
- data/lib/fit4ruby/FieldDescription.rb +28 -2
- data/lib/fit4ruby/FitDataRecord.rb +2 -1
- data/lib/fit4ruby/FitDefinition.rb +7 -1
- data/lib/fit4ruby/FitDefinitionField.rb +3 -2
- data/lib/fit4ruby/FitDefinitionFieldBase.rb +11 -30
- data/lib/fit4ruby/FitDeveloperDataFieldDefinition.rb +39 -7
- data/lib/fit4ruby/FitFile.rb +1 -1
- data/lib/fit4ruby/FitFileEntity.rb +4 -2
- data/lib/fit4ruby/FitMessageRecord.rb +21 -21
- data/lib/fit4ruby/FitRecord.rb +8 -4
- data/lib/fit4ruby/FitTypeDefs.rb +37 -0
- data/lib/fit4ruby/GlobalFitMessages.rb +11 -8
- data/lib/fit4ruby/Monitoring_B.rb +3 -2
- data/lib/fit4ruby/PhysiologicalMetrics.rb +1 -1
- data/lib/fit4ruby/UserData.rb +32 -0
- data/lib/fit4ruby/UserProfile.rb +1 -1
- data/lib/fit4ruby/version.rb +1 -1
- data/spec/FitFile_spec.rb +3 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4ee014802983dc12f9d4204e29e1c80d33be729
|
4
|
+
data.tar.gz: 7d52d887dea393412752a72974d189452ffea3e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d306e3ff6d58837943461a2508c6a81d05043b49eb186e352f273e11b341ffe6b0db92e500d764e327c37f38c5f3a5ec466a8bb8172599dd1df563a3b9a0075
|
7
|
+
data.tar.gz: cb7692535f35056b613c8f9e3a334d9690400ec2f614c8e5676af0919cb8132b1a280caa7efcd3c6265044008def7deed8a6e706e4718aad1be57a96b12700f3
|
data/lib/fit4ruby/Activity.rb
CHANGED
@@ -19,6 +19,7 @@ require 'fit4ruby/FileCreator'
|
|
19
19
|
require 'fit4ruby/DeviceInfo'
|
20
20
|
require 'fit4ruby/SensorSettings'
|
21
21
|
require 'fit4ruby/DataSources'
|
22
|
+
require 'fit4ruby/UserData'
|
22
23
|
require 'fit4ruby/UserProfile'
|
23
24
|
require 'fit4ruby/PhysiologicalMetrics'
|
24
25
|
require 'fit4ruby/Session'
|
@@ -38,7 +39,7 @@ module Fit4Ruby
|
|
38
39
|
|
39
40
|
attr_accessor :file_id, :field_descriptions, :developer_data_ids, :epo_data,
|
40
41
|
:file_creator, :device_infos, :sensor_settings, :data_sources,
|
41
|
-
:user_profiles, :physiological_metrics,
|
42
|
+
:user_data, :user_profiles, :physiological_metrics,
|
42
43
|
:sessions, :laps, :records, :hrv,
|
43
44
|
:heart_rate_zones, :events, :personal_records
|
44
45
|
|
@@ -58,6 +59,7 @@ module Fit4Ruby
|
|
58
59
|
@device_infos = []
|
59
60
|
@sensor_settings = []
|
60
61
|
@data_sources = []
|
62
|
+
@user_data = []
|
61
63
|
@user_profiles = []
|
62
64
|
@physiological_metrics = []
|
63
65
|
@events = []
|
@@ -318,7 +320,7 @@ module Fit4Ruby
|
|
318
320
|
# @param field_values [Hash] A Hash that provides initial values for
|
319
321
|
# certain fields of the FitDataRecord.
|
320
322
|
# @return [DeveloperDataId]
|
321
|
-
def
|
323
|
+
def new_developer_data_id(field_values = {})
|
322
324
|
new_fit_data_record('developer_data_id', field_values)
|
323
325
|
end
|
324
326
|
|
@@ -347,12 +349,20 @@ module Fit4Ruby
|
|
347
349
|
new_fit_data_record('data_sources', field_values)
|
348
350
|
end
|
349
351
|
|
352
|
+
# Add a new UserData to the Activity.
|
353
|
+
# @param field_values [Hash] A Hash that provides initial values for
|
354
|
+
# certain fields of the FitDataRecord.
|
355
|
+
# @return [UserData]
|
356
|
+
def new_user_data(field_values = {})
|
357
|
+
new_fit_data_record('user_data', field_values)
|
358
|
+
end
|
359
|
+
|
350
360
|
# Add a new UserProfile to the Activity.
|
351
361
|
# @param field_values [Hash] A Hash that provides initial values for
|
352
362
|
# certain fields of the FitDataRecord.
|
353
363
|
# @return [UserProfile]
|
354
364
|
def new_user_profile(field_values = {})
|
355
|
-
new_fit_data_record('
|
365
|
+
new_fit_data_record('user_profile', field_values)
|
356
366
|
end
|
357
367
|
|
358
368
|
# Add a new PhysiologicalMetrics to the Activity.
|
@@ -461,7 +471,9 @@ module Fit4Ruby
|
|
461
471
|
@sensor_settings << (record = SensorSettings.new(field_values))
|
462
472
|
when 'data_sources'
|
463
473
|
@data_sources << (record = DataSources.new(field_values))
|
464
|
-
when '
|
474
|
+
when 'user_data'
|
475
|
+
@user_data << (record = UserData.new(field_values))
|
476
|
+
when 'user_profile'
|
465
477
|
@user_profiles << (record = UserProfile.new(field_values))
|
466
478
|
when 'physiological_metrics'
|
467
479
|
@physiological_metrics <<
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FieldDescription.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2017 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2017, 2018 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,8 @@
|
|
11
11
|
#
|
12
12
|
|
13
13
|
require 'fit4ruby/FitDataRecord'
|
14
|
+
require 'fit4ruby/FitDefinitionFieldBase'
|
15
|
+
require 'fit4ruby/FitTypeDefs'
|
14
16
|
|
15
17
|
module Fit4Ruby
|
16
18
|
|
@@ -25,7 +27,31 @@ module Fit4Ruby
|
|
25
27
|
set_field_values(field_values)
|
26
28
|
end
|
27
29
|
|
28
|
-
def create_global_definition
|
30
|
+
def create_global_definition(fit_entity)
|
31
|
+
messages = fit_entity.developer_fit_messages
|
32
|
+
unless (gfm = GlobalFitMessages[@native_mesg_num])
|
33
|
+
Log.error "Developer field description references unknown global " +
|
34
|
+
"message number #{@native_mesg_num}"
|
35
|
+
end
|
36
|
+
|
37
|
+
if @developer_data_index >=
|
38
|
+
fit_entity.top_level_record.developer_data_ids.size
|
39
|
+
Log.error "Developer data index #{@developer_data_index} is too large"
|
40
|
+
end
|
41
|
+
|
42
|
+
msg = messages[@native_mesg_num] ||
|
43
|
+
messages.message(@native_mesg_num, gfm.name)
|
44
|
+
unless (@fit_base_type_id & 0x7F) < FIT_TYPE_DEFS.size
|
45
|
+
Log.error "fit_base_type_id #{@fit_base_type_id} is too large"
|
46
|
+
end
|
47
|
+
options = {}
|
48
|
+
options[:scale] = @scale if @scale
|
49
|
+
options[:offset] = @offset if @offset
|
50
|
+
options[:array] = @array if @array
|
51
|
+
options[:unit] = @units
|
52
|
+
msg.field(@field_definition_number,
|
53
|
+
FIT_TYPE_DEFS[@fit_base_type_id & 0x7F][1],
|
54
|
+
"_#{@developer_data_index}_#{@field_name}", options)
|
29
55
|
end
|
30
56
|
|
31
57
|
end
|
@@ -19,7 +19,8 @@ module Fit4Ruby
|
|
19
19
|
|
20
20
|
include Converters
|
21
21
|
|
22
|
-
RecordOrder = [ '
|
22
|
+
RecordOrder = [ 'user_data', 'user_profile',
|
23
|
+
'device_info', 'data_sources', 'event',
|
23
24
|
'record', 'lap', 'session', 'heart_rate_zones',
|
24
25
|
'personal_records' ]
|
25
26
|
|
@@ -54,10 +54,12 @@ module Fit4Ruby
|
|
54
54
|
Log.fatal "Illegal architecture value #{architecture.snapshot}"
|
55
55
|
end
|
56
56
|
data_fields.each { |f| f.check }
|
57
|
+
developer_fields.each { |f| f.check }
|
57
58
|
end
|
58
59
|
|
59
|
-
def FitDefinition::read(io, entity, developer_data_flag)
|
60
|
+
def FitDefinition::read(io, entity, developer_data_flag, fit_entity)
|
60
61
|
@@has_developer_data = developer_data_flag != 0
|
62
|
+
@@fit_entity = fit_entity
|
61
63
|
super(io)
|
62
64
|
end
|
63
65
|
|
@@ -71,6 +73,10 @@ module Fit4Ruby
|
|
71
73
|
@@has_developer_data
|
72
74
|
end
|
73
75
|
|
76
|
+
def fit_entity
|
77
|
+
@@fit_entity
|
78
|
+
end
|
79
|
+
|
74
80
|
def setup(fit_message_definition)
|
75
81
|
fit_message_definition.fields_by_number.each do |number, f|
|
76
82
|
fdf = FitDefinitionField.new
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitDefinitionField.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2017, 2018 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
|
@@ -15,6 +15,7 @@ require 'time'
|
|
15
15
|
require 'fit4ruby/FitDefinitionFieldBase'
|
16
16
|
require 'fit4ruby/Log'
|
17
17
|
require 'fit4ruby/GlobalFitMessage'
|
18
|
+
require 'fit4ruby/FitTypeDefs'
|
18
19
|
|
19
20
|
module Fit4Ruby
|
20
21
|
|
@@ -45,7 +46,7 @@ module Fit4Ruby
|
|
45
46
|
"choice_#{field_number}"
|
46
47
|
@type = field.respond_to?('type') ? field.type : nil
|
47
48
|
|
48
|
-
if @type && (td =
|
49
|
+
if @type && (td = FIT_TYPE_DEFS[checked_base_type_number]) &&
|
49
50
|
td[0] != @type
|
50
51
|
Log.warn "#{@global_message_number}:#{@name} must be of type " +
|
51
52
|
"#{@type}, not #{td[0]}"
|
@@ -10,52 +10,33 @@
|
|
10
10
|
# published by the Free Software Foundation.
|
11
11
|
#
|
12
12
|
|
13
|
+
require 'fit4ruby/FitTypeDefs'
|
14
|
+
|
13
15
|
module Fit4Ruby
|
14
16
|
|
15
17
|
module FitDefinitionFieldBase
|
16
18
|
|
17
|
-
@@TypeDefs = [
|
18
|
-
# FIT Type, BinData type, undefined value, bytes
|
19
|
-
[ 'enum', 'uint8', 0xFF, 1 ],
|
20
|
-
[ 'sint8', 'int8', 0x7F, 1 ],
|
21
|
-
[ 'uint8', 'uint8', 0xFF, 1 ],
|
22
|
-
[ 'sint16', 'int16', 0x7FFF, 2 ],
|
23
|
-
[ 'uint16', 'uint16', 0xFFFF, 2 ],
|
24
|
-
[ 'sint32', 'int32', 0x7FFFFFFF, 4 ],
|
25
|
-
[ 'uint32', 'uint32', 0xFFFFFFFF, 4 ],
|
26
|
-
[ 'string', 'string', '', 0 ],
|
27
|
-
[ 'float32', 'float', 0xFFFFFFFF, 4 ],
|
28
|
-
[ 'float63', 'double', 0xFFFFFFFF, 4 ],
|
29
|
-
[ 'uint8z', 'uint8', 0, 1 ],
|
30
|
-
[ 'uint16z', 'uint16', 0, 2 ],
|
31
|
-
[ 'uint32z', 'uint32', 0, 4 ],
|
32
|
-
[ 'byte', 'uint8', 0xFF, 1 ],
|
33
|
-
[ 'sint64', 'int64', 0x7FFFFFFFFFFFFFFF, 8 ],
|
34
|
-
[ 'uint64', 'uint64', 0xFFFFFFFFFFFFFFFF, 8 ],
|
35
|
-
[ 'uint64z', 'uint64', 0, 8 ]
|
36
|
-
]
|
37
|
-
|
38
19
|
def FitDefinitionFieldBase::fit_type_to_bin_data(fit_type)
|
39
|
-
entry =
|
20
|
+
entry = FIT_TYPE_DEFS.find { |e| e[0] == fit_type }
|
40
21
|
raise "Unknown fit type #{fit_type}" unless entry
|
41
22
|
entry[1]
|
42
23
|
end
|
43
24
|
|
44
25
|
def FitDefinitionFieldBase::undefined_value(fit_type)
|
45
|
-
entry =
|
26
|
+
entry = FIT_TYPE_DEFS.find { |e| e[0] == fit_type }
|
46
27
|
raise "Unknown fit type #{fit_type}" unless entry
|
47
28
|
entry[2]
|
48
29
|
end
|
49
30
|
|
50
31
|
def set_type(fit_type)
|
51
|
-
idx =
|
32
|
+
idx = FIT_TYPE_DEFS.index { |x| x[0] == fit_type }
|
52
33
|
raise "Unknown type #{fit_type}" unless idx
|
53
34
|
self.base_type_number = idx
|
54
|
-
self.byte_count =
|
35
|
+
self.byte_count = FIT_TYPE_DEFS[idx][3]
|
55
36
|
end
|
56
37
|
|
57
38
|
def type(fit_type = false)
|
58
|
-
|
39
|
+
FIT_TYPE_DEFS[checked_base_type_number][fit_type ? 0 : 1]
|
59
40
|
end
|
60
41
|
|
61
42
|
def is_array?
|
@@ -76,17 +57,17 @@ module Fit4Ruby
|
|
76
57
|
end
|
77
58
|
|
78
59
|
def base_type_bytes
|
79
|
-
|
60
|
+
FIT_TYPE_DEFS[checked_base_type_number][3]
|
80
61
|
end
|
81
62
|
|
82
63
|
def undefined_value
|
83
|
-
|
64
|
+
FIT_TYPE_DEFS[checked_base_type_number][2]
|
84
65
|
end
|
85
66
|
|
86
67
|
private
|
87
68
|
|
88
69
|
def checked_base_type_number
|
89
|
-
if
|
70
|
+
if FIT_TYPE_DEFS.length <= base_type_number.snapshot
|
90
71
|
Log.error "Unknown FIT Base type #{base_type_number.snapshot} in " +
|
91
72
|
"Global FIT Message #{name}"
|
92
73
|
return 0
|
@@ -95,7 +76,7 @@ module Fit4Ruby
|
|
95
76
|
end
|
96
77
|
|
97
78
|
def check_fit_base_type
|
98
|
-
if
|
79
|
+
if FIT_TYPE_DEFS.length <= base_type_number.snapshot
|
99
80
|
end
|
100
81
|
end
|
101
82
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitDeveloperDataFieldDefinition.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2017 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2017, 2018 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,6 +12,7 @@
|
|
12
12
|
|
13
13
|
require 'bindata'
|
14
14
|
require 'fit4ruby/FitDefinitionFieldBase'
|
15
|
+
require 'fit4ruby/FitTypeDefs'
|
15
16
|
|
16
17
|
module Fit4Ruby
|
17
18
|
|
@@ -28,13 +29,44 @@ module Fit4Ruby
|
|
28
29
|
"#{field_number.snapshot}"
|
29
30
|
end
|
30
31
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
def type
|
33
|
+
FIT_TYPE_DEFS[checked_base_type_number][1]
|
34
|
+
end
|
35
|
+
|
36
|
+
def base_type_bytes
|
37
|
+
FIT_TYPE_DEFS[checked_base_type_number][3]
|
38
|
+
end
|
39
|
+
|
40
|
+
def byte_count
|
41
|
+
size_in_bytes
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def find_field_definition
|
47
|
+
tlr = parent.parent.fit_entity.top_level_record
|
48
|
+
field = tlr.field_descriptions.find do |fd|
|
49
|
+
fd.field_definition_number == field_number.snapshot &&
|
50
|
+
fd.developer_data_index == developer_data_index.snapshot
|
37
51
|
end
|
52
|
+
unless field
|
53
|
+
Log.error "Unknown developer field #{field_number.snapshot} " +
|
54
|
+
"for developer #{developer_data_index.snapshot}"
|
55
|
+
end
|
56
|
+
|
57
|
+
field
|
58
|
+
end
|
59
|
+
|
60
|
+
def checked_base_type_number
|
61
|
+
field = find_field_definition
|
62
|
+
base_type_number = field.fit_base_type_id & 0x7F
|
63
|
+
if FIT_TYPE_DEFS.length <= base_type_number
|
64
|
+
Log.error "Unknown FIT Base type #{base_type_number} in " +
|
65
|
+
"Global FIT Message #{name}"
|
66
|
+
return 0
|
67
|
+
end
|
68
|
+
|
69
|
+
base_type_number
|
38
70
|
end
|
39
71
|
|
40
72
|
end
|
data/lib/fit4ruby/FitFile.rb
CHANGED
@@ -55,7 +55,7 @@ module Fit4Ruby
|
|
55
55
|
# incremented each time the corresponding record type is found.
|
56
56
|
record_counters = Hash.new { 0 }
|
57
57
|
while io.pos < offset + header.end_pos
|
58
|
-
record = FitRecord.new(definitions)
|
58
|
+
record = FitRecord.new(definitions, entity)
|
59
59
|
record.read(io, entity, filter, record_counters)
|
60
60
|
records << record if filter
|
61
61
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FitMessageRecord.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
5
|
#
|
6
|
-
# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2015, 2016, 2017, 2018 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,6 +12,7 @@
|
|
12
12
|
|
13
13
|
require 'fit4ruby/Activity'
|
14
14
|
require 'fit4ruby/Monitoring_B'
|
15
|
+
require 'fit4ruby/GlobalFitMessage'
|
15
16
|
|
16
17
|
module Fit4Ruby
|
17
18
|
|
@@ -25,11 +26,12 @@ module Fit4Ruby
|
|
25
26
|
# objec we need to use to store it for later consumption.
|
26
27
|
class FitFileEntity
|
27
28
|
|
28
|
-
attr_reader :top_level_record
|
29
|
+
attr_reader :top_level_record, :developer_fit_messages
|
29
30
|
|
30
31
|
# Create a FitFileEntity.
|
31
32
|
def initialize
|
32
33
|
@top_level_record = nil
|
34
|
+
@developer_fit_messages = GlobalFitMessageList.new
|
33
35
|
end
|
34
36
|
|
35
37
|
# Set what kind of FIT file we are dealing with.
|
@@ -41,9 +41,16 @@ module Fit4Ruby
|
|
41
41
|
@message_record = produce(definition)
|
42
42
|
end
|
43
43
|
|
44
|
-
def read(io, entity, filter = nil, fields_dump = nil)
|
44
|
+
def read(io, entity, filter = nil, fields_dump = nil, fit_entity)
|
45
45
|
@message_record.read(io)
|
46
46
|
|
47
|
+
# Check if we have a developer defined message for this global message
|
48
|
+
# number.
|
49
|
+
if fit_entity.top_level_record
|
50
|
+
developer_fields = fit_entity.top_level_record.field_descriptions
|
51
|
+
@dfm = developer_fields[@global_message_number]
|
52
|
+
end
|
53
|
+
|
47
54
|
if @name == 'file_id'
|
48
55
|
unless (entity_type = @message_record['type'].snapshot)
|
49
56
|
Log.fatal "Corrupted FIT file: file_id record has no type definition"
|
@@ -63,6 +70,7 @@ module Fit4Ruby
|
|
63
70
|
f1alt ? 1 : -1
|
64
71
|
end
|
65
72
|
|
73
|
+
#(sorted_fields + @definition.developer_fields).each do |field|
|
66
74
|
sorted_fields.each do |field|
|
67
75
|
value = @message_record[field.name].snapshot
|
68
76
|
# Strings are null byte terminated. There may be more bytes in the
|
@@ -89,16 +97,10 @@ module Fit4Ruby
|
|
89
97
|
(field_def ? field_def : field).to_s(value))
|
90
98
|
end
|
91
99
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
# "Developer ID: #{field.developer_data_index.snapshot}"
|
97
|
-
#end
|
98
|
-
|
99
|
-
#if @name == 'field_description'
|
100
|
-
# obj.create_global_definition
|
101
|
-
#end
|
100
|
+
|
101
|
+
if @name == 'field_description'
|
102
|
+
obj.create_global_definition(fit_entity)
|
103
|
+
end
|
102
104
|
end
|
103
105
|
|
104
106
|
private
|
@@ -141,26 +143,24 @@ module Fit4Ruby
|
|
141
143
|
|
142
144
|
def produce(definition)
|
143
145
|
fields = []
|
144
|
-
definition.data_fields.
|
146
|
+
(definition.data_fields.to_a +
|
147
|
+
definition.developer_fields.to_a).each do |field|
|
145
148
|
field_def = [ field.type, field.name ]
|
149
|
+
|
150
|
+
# Some field types need special handling.
|
146
151
|
if field.type == 'string'
|
147
|
-
#
|
148
|
-
# of the String.
|
152
|
+
# We need to also include the length of the String.
|
149
153
|
field_def << { :read_length => field.total_bytes }
|
150
154
|
elsif field.is_array?
|
155
|
+
# For Arrays we have to break them into separte fields.
|
151
156
|
field_def = [ :array, field.name,
|
152
157
|
{ :type => field.type.intern,
|
153
|
-
:initial_length =>
|
154
|
-
|
158
|
+
:initial_length =>
|
159
|
+
field.total_bytes / field.base_type_bytes } ]
|
155
160
|
end
|
156
161
|
fields << field_def
|
157
162
|
end
|
158
163
|
|
159
|
-
definition.developer_fields.each do |field|
|
160
|
-
field_def = [ field.bindata_type, field.name ]
|
161
|
-
fields << field_def
|
162
|
-
end
|
163
|
-
|
164
164
|
BinData::Struct.new(:endian => definition.endian, :fields => fields)
|
165
165
|
end
|
166
166
|
|
data/lib/fit4ruby/FitRecord.rb
CHANGED
@@ -28,8 +28,12 @@ module Fit4Ruby
|
|
28
28
|
|
29
29
|
attr_reader :number
|
30
30
|
|
31
|
-
def initialize(definitions)
|
31
|
+
def initialize(definitions, fit_entity)
|
32
32
|
@definitions = definitions
|
33
|
+
# It's a bit ugly that we have to pass the generated FitFileEntity to
|
34
|
+
# the parser classes. But we need to have access to the developer field
|
35
|
+
# definitions to parse them properly.
|
36
|
+
@fit_entity = fit_entity
|
33
37
|
@name = @number = @fields = nil
|
34
38
|
end
|
35
39
|
|
@@ -44,8 +48,8 @@ module Fit4Ruby
|
|
44
48
|
local_message_type = header.local_message_type.snapshot
|
45
49
|
if header.normal? && header.message_type.snapshot == 1
|
46
50
|
# process definition message
|
47
|
-
definition = FitDefinition.read(
|
48
|
-
|
51
|
+
definition = FitDefinition.read(
|
52
|
+
io, entity, header.developer_data_flag.snapshot, @fit_entity)
|
49
53
|
@definitions[local_message_type] = FitMessageRecord.new(definition)
|
50
54
|
else
|
51
55
|
# process data message
|
@@ -68,7 +72,7 @@ module Fit4Ruby
|
|
68
72
|
@fields = []
|
69
73
|
end
|
70
74
|
end
|
71
|
-
definition.read(io, entity, filter, @fields)
|
75
|
+
definition.read(io, entity, filter, @fields, @fit_entity)
|
72
76
|
end
|
73
77
|
|
74
78
|
self
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = FitTypeDefs.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2017, 2018 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
|
+
FIT_TYPE_DEFS = [
|
16
|
+
# FIT Type, BinData type, undefined value, bytes
|
17
|
+
[ 'enum', 'uint8', 0xFF, 1 ],
|
18
|
+
[ 'sint8', 'int8', 0x7F, 1 ],
|
19
|
+
[ 'uint8', 'uint8', 0xFF, 1 ],
|
20
|
+
[ 'sint16', 'int16', 0x7FFF, 2 ],
|
21
|
+
[ 'uint16', 'uint16', 0xFFFF, 2 ],
|
22
|
+
[ 'sint32', 'int32', 0x7FFFFFFF, 4 ],
|
23
|
+
[ 'uint32', 'uint32', 0xFFFFFFFF, 4 ],
|
24
|
+
[ 'string', 'string', '', 0 ],
|
25
|
+
[ 'float32', 'float', 0xFFFFFFFF, 4 ],
|
26
|
+
[ 'float63', 'double', 0xFFFFFFFF, 4 ],
|
27
|
+
[ 'uint8z', 'uint8', 0, 1 ],
|
28
|
+
[ 'uint16z', 'uint16', 0, 2 ],
|
29
|
+
[ 'uint32z', 'uint32', 0, 4 ],
|
30
|
+
[ 'byte', 'uint8', 0xFF, 1 ],
|
31
|
+
[ 'sint64', 'int64', 0x7FFFFFFFFFFFFFFF, 8 ],
|
32
|
+
[ 'uint64', 'uint64', 0xFFFFFFFFFFFFFFFF, 8 ],
|
33
|
+
[ 'uint64z', 'uint64', 0, 8 ]
|
34
|
+
]
|
35
|
+
|
36
|
+
end
|
37
|
+
|
@@ -114,7 +114,7 @@ module Fit4Ruby
|
|
114
114
|
field 12, 'enum', 'hr_setting', :dict => 'display_heart'
|
115
115
|
field 13, 'enum', 'speed_setting', :dict => 'display_measure'
|
116
116
|
field 14, 'enum', 'dist_setting', :dict => 'display_measure'
|
117
|
-
field 17, 'enum', 'activity_class'
|
117
|
+
field 17, 'enum', 'activity_class', :scale => 10
|
118
118
|
field 18, 'enum', 'position_setting', :dict => 'display_position'
|
119
119
|
field 21, 'enum', 'temperature_setting', :dict => 'display_measure'
|
120
120
|
field 24, 'uint8', 'birth_year'
|
@@ -251,8 +251,8 @@ module Fit4Ruby
|
|
251
251
|
field 35, 'uint16', 'training_stress_score', :scale => 10, :unit => 'tss'
|
252
252
|
field 36, 'uint16', 'intensity_factor', :scale => 1000, :unit => 'if'
|
253
253
|
field 37, 'uint16', 'left_right_balance', :dict => 'left_right_balance_100'
|
254
|
-
field 38, 'sint32', '
|
255
|
-
field 39, 'sint32', '
|
254
|
+
field 38, 'sint32', 'lap1_lat', :type => 'coordinate' # guessed
|
255
|
+
field 39, 'sint32', 'lap1_long', :type => 'coordinate' # guessed
|
256
256
|
field 41, 'uint32', 'avg_stroke_count', :scale => 10, :unit => 'strokes/lap'
|
257
257
|
field 42, 'uint16', 'avg_stroke_distance', :scale => 100, :unit => 'm'
|
258
258
|
field 43, 'enum', 'swim_stroke', :dict => 'swim_stroke'
|
@@ -433,6 +433,8 @@ module Fit4Ruby
|
|
433
433
|
field 46, 'uint8', 'right_pedal_smoothness', :scale => 2, :unit => '%'
|
434
434
|
field 47, 'uint8', 'combined_pedal_smoothness', :scale => 2, :unit => '%'
|
435
435
|
field 53, 'uint8', 'fractional_cadence', :scale => 128
|
436
|
+
field 54, 'uint16', 'total_hemoglobin_conc', :scale => 100, :unit => 'g/dL'
|
437
|
+
field 57, 'uint16', 'saturated_hemoglobin_percent', :scale => 10, :unit => '%'
|
436
438
|
field 61, 'uint16', 'undefined_value_61'
|
437
439
|
field 63, 'uint16', 'undefined_value_63'
|
438
440
|
field 64, 'uint16', 'undefined_value_64'
|
@@ -629,7 +631,7 @@ module Fit4Ruby
|
|
629
631
|
field 0, 'uint16', 'time', :array => true, :scale => 1000, :unit => 's'
|
630
632
|
|
631
633
|
# Not part of the official ANT SDK doc
|
632
|
-
message 79, '
|
634
|
+
message 79, 'user_data'
|
633
635
|
field 0, 'uint16', 'metmax', :scale => 1000, :unit => 'MET' # VO2max / 3.5
|
634
636
|
field 1, 'uint8', 'age', :unit => 'years'
|
635
637
|
field 2, 'uint8', 'height', :scale => 100, :unit => 'm'
|
@@ -807,6 +809,7 @@ module Fit4Ruby
|
|
807
809
|
field 57, 'uint16', 'undocumented_field_57'
|
808
810
|
field 58, 'enum', 'undocumented_field_58'
|
809
811
|
field 59, 'uint8', 'undocumented_field_59'
|
812
|
+
field 62, 'uint8', 'undocumented_field_62'
|
810
813
|
field 254, 'uint16', 'message_index'
|
811
814
|
|
812
815
|
message 206, 'field_description'
|
@@ -844,12 +847,12 @@ module Fit4Ruby
|
|
844
847
|
field 1, 'uint16', 'lap_index'
|
845
848
|
field 2, 'uint32', 'time_in_hr_zone', :array => true, :scale => 1000, :unit => 's'
|
846
849
|
field 5, 'uint32', 'undocumented_field_5'
|
847
|
-
field 6, 'uint8', 'heart_rate_zones', :array => true
|
850
|
+
field 6, 'uint8', 'heart_rate_zones', :array => true, :unit => 'bpm'
|
848
851
|
field 9, 'uint16', 'undocumented_field_9'
|
849
852
|
field 10, 'enum', 'undocumented_field_10'
|
850
|
-
field 11, 'uint8', 'max_heart_rate'
|
851
|
-
field 12, 'uint8', 'resting_heart_rate'
|
852
|
-
field 13, 'uint8', '
|
853
|
+
field 11, 'uint8', 'max_heart_rate', :unit => 'bpm'
|
854
|
+
field 12, 'uint8', 'resting_heart_rate', :unit => 'bpm'
|
855
|
+
field 13, 'uint8', 'lactate_threshold_heart_rate', :unit => 'bpm'
|
853
856
|
field 14, 'enum', 'undocumented_field_14'
|
854
857
|
field 15, 'uint16', 'undocumented_field_15'
|
855
858
|
field 253, 'uint32', 'timestamp', :type => 'date_time'
|
@@ -25,8 +25,8 @@ module Fit4Ruby
|
|
25
25
|
# record structures used in the FIT file.
|
26
26
|
class Monitoring_B < FitDataRecord
|
27
27
|
|
28
|
-
attr_accessor :file_id, :
|
29
|
-
|
28
|
+
attr_accessor :file_id, :field_descriptions, :device_infos, :software,
|
29
|
+
:monitoring_infos, :monitorings
|
30
30
|
|
31
31
|
# Create a new Monitoring_B object.
|
32
32
|
# @param field_values [Hash] A Hash that provides initial values for
|
@@ -36,6 +36,7 @@ module Fit4Ruby
|
|
36
36
|
@num_sessions = 0
|
37
37
|
|
38
38
|
@file_id = FileId.new
|
39
|
+
@field_descriptions = []
|
39
40
|
@device_infos = []
|
40
41
|
@softwares = nil
|
41
42
|
@monitoring_infos = []
|
@@ -14,7 +14,7 @@ require 'fit4ruby/FitDataRecord'
|
|
14
14
|
|
15
15
|
module Fit4Ruby
|
16
16
|
|
17
|
-
# This class corresponds to the
|
17
|
+
# This class corresponds to the physiological_metrics FIT message.
|
18
18
|
class PhysiologicalMetrics < FitDataRecord
|
19
19
|
|
20
20
|
# Create a new PhysiologicalMetrics object.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
#
|
4
|
+
# = UserData.rb -- Fit4Ruby - FIT file processing library for Ruby
|
5
|
+
#
|
6
|
+
# Copyright (c) 2018 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/FitDataRecord'
|
14
|
+
|
15
|
+
module Fit4Ruby
|
16
|
+
|
17
|
+
# This class corresponds to the old_user_profile FIT message.
|
18
|
+
class UserData < FitDataRecord
|
19
|
+
|
20
|
+
# Create a new UserData object.
|
21
|
+
# @param field_values [Hash] Hash that provides initial values for certain
|
22
|
+
# fields.
|
23
|
+
def initialize(field_values = {})
|
24
|
+
super('user_data')
|
25
|
+
set_field_values(field_values)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
data/lib/fit4ruby/UserProfile.rb
CHANGED
data/lib/fit4ruby/version.rb
CHANGED
data/spec/FitFile_spec.rb
CHANGED
@@ -20,9 +20,9 @@ describe Fit4Ruby do
|
|
20
20
|
ts = Time.now
|
21
21
|
a = Fit4Ruby::Activity.new
|
22
22
|
a.total_timer_time = 30 * 60.0
|
23
|
-
a.
|
24
|
-
|
25
|
-
|
23
|
+
a.new_user_data({ :age => 33, :height => 1.78, :weight => 73.0,
|
24
|
+
:gender => 'male', :activity_class => 4.0,
|
25
|
+
:max_hr => 178 })
|
26
26
|
|
27
27
|
a.new_event({ :event => 'timer', :event_type => 'start_time' })
|
28
28
|
a.new_device_info({ :timestamp => ts,
|
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:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
@@ -108,6 +108,7 @@ files:
|
|
108
108
|
- lib/fit4ruby/FitMessageRecord.rb
|
109
109
|
- lib/fit4ruby/FitRecord.rb
|
110
110
|
- lib/fit4ruby/FitRecordHeader.rb
|
111
|
+
- lib/fit4ruby/FitTypeDefs.rb
|
111
112
|
- lib/fit4ruby/GeoMath.rb
|
112
113
|
- lib/fit4ruby/GlobalFitDictList.rb
|
113
114
|
- lib/fit4ruby/GlobalFitDictionaries.rb
|
@@ -127,6 +128,7 @@ files:
|
|
127
128
|
- lib/fit4ruby/SensorSettings.rb
|
128
129
|
- lib/fit4ruby/Session.rb
|
129
130
|
- lib/fit4ruby/Software.rb
|
131
|
+
- lib/fit4ruby/UserData.rb
|
130
132
|
- lib/fit4ruby/UserProfile.rb
|
131
133
|
- lib/fit4ruby/version.rb
|
132
134
|
- spec/FileNameCoder_spec.rb
|