fit4ruby 2.0.0 → 3.0.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/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
|