rubyfit 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rubyfit/message_constants.rb +83 -0
- data/lib/rubyfit/message_writer.rb +13 -31
- data/lib/rubyfit/type.rb +7 -0
- data/lib/rubyfit/version.rb +1 -1
- data/lib/rubyfit/writer.rb +58 -43
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00b20b537878f333895f88bcd88bfa2aed26118a
|
4
|
+
data.tar.gz: 5638078b60c7fdbe1dd984e94225a4645959eb3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5643d322008304a699877b16b8eac3dfdf8a08ce0a29bef8bf1eab7795ce6e64b4f99b7c2dd0720636d83e8e6d4e88ee36388e9a2182f7b80365134a7f53764e
|
7
|
+
data.tar.gz: 887e0f5f1d80504287437b935b16dc82c989e3b6a6709e0c54ecaff4a96c6f5e0e51c743c78e73be7e0f749fca7be646cf332cb257660814a668880be3c2febf
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RubyFit::MessageConstants
|
2
|
+
COURSE_POINT_TYPE = {
|
3
|
+
invalid: 255,
|
4
|
+
generic: 0,
|
5
|
+
summit: 1,
|
6
|
+
valley: 2,
|
7
|
+
water: 3,
|
8
|
+
food: 4,
|
9
|
+
danger: 5,
|
10
|
+
left: 6,
|
11
|
+
right: 7,
|
12
|
+
straight: 8,
|
13
|
+
first_aid: 9,
|
14
|
+
fourth_category: 10,
|
15
|
+
third_category: 11,
|
16
|
+
second_category: 12,
|
17
|
+
first_category: 13,
|
18
|
+
hors_category: 14,
|
19
|
+
sprint: 15,
|
20
|
+
left_fork: 16,
|
21
|
+
right_fork: 17,
|
22
|
+
middle_fork: 18,
|
23
|
+
slight_left: 19,
|
24
|
+
sharp_left: 20,
|
25
|
+
slight_right: 21,
|
26
|
+
sharp_right: 22,
|
27
|
+
u_turn: 23,
|
28
|
+
segment_start: 24,
|
29
|
+
segment_end: 25
|
30
|
+
}.freeze
|
31
|
+
|
32
|
+
EVENT_TYPE = {
|
33
|
+
start: 0,
|
34
|
+
stop: 1,
|
35
|
+
consecutive_depreciated: 2,
|
36
|
+
marker: 3,
|
37
|
+
stop_all: 4,
|
38
|
+
begin_depreciated: 5,
|
39
|
+
end_depreciated: 6,
|
40
|
+
end_all_depreciated: 7,
|
41
|
+
stop_disable: 8,
|
42
|
+
stop_disable_all: 9,
|
43
|
+
}.freeze
|
44
|
+
|
45
|
+
EVENT = {
|
46
|
+
timer: 0, # Group 0. Start / stop_all
|
47
|
+
workout: 3, # start / stop
|
48
|
+
workout_step: 4, # Start at beginning of workout. Stop at end of each step.
|
49
|
+
power_down: 5, # stop_all group 0
|
50
|
+
power_up: 6, # stop_all group 0
|
51
|
+
off_course: 7, # start / stop group 0
|
52
|
+
session: 8, # Stop at end of each session.
|
53
|
+
lap: 9, # Stop at end of each lap.
|
54
|
+
course_point: 10, # marker
|
55
|
+
battery: 11, # marker
|
56
|
+
virtual_partner_pace: 12, # Group 1. Start at beginning of activity if VP enabled, when VP pace is changed during activity or VP enabled mid activity. stop_disable when VP disabled.
|
57
|
+
hr_high_alert: 13, # Group 0. Start / stop when in alert condition.
|
58
|
+
hr_low_alert: 14, # Group 0. Start / stop when in alert condition.
|
59
|
+
speed_high_alert: 15, # Group 0. Start / stop when in alert condition.
|
60
|
+
speed_low_alert: 16, # Group 0. Start / stop when in alert condition.
|
61
|
+
cad_high_alert: 17, # Group 0. Start / stop when in alert condition.
|
62
|
+
cad_low_alert: 18, # Group 0. Start / stop when in alert condition.
|
63
|
+
power_high_alert: 19, # Group 0. Start / stop when in alert condition.
|
64
|
+
power_low_alert: 20, # Group 0. Start / stop when in alert condition.
|
65
|
+
recovery_hr: 21, # marker
|
66
|
+
battery_low: 22, # marker
|
67
|
+
time_duration_alert: 23, # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.
|
68
|
+
distance_duration_alert: 24, # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.
|
69
|
+
calorie_duration_alert: 25, # Group 1. Start if enabled mid activity (not required at start of activity). Stop when duration is reached. stop_disable if disabled.
|
70
|
+
activity: 26, # Group 1.. Stop at end of activity.
|
71
|
+
fitness_equipment: 27, # marker
|
72
|
+
length: 28, # Stop at end of each length.
|
73
|
+
user_marker: 32, # marker
|
74
|
+
sport_point: 33, # marker
|
75
|
+
calibration: 36, # start/stop/marker
|
76
|
+
front_gear_change: 42, # marker
|
77
|
+
rear_gear_change: 43, # marker
|
78
|
+
rider_position_change: 44, # marker
|
79
|
+
elev_high_alert: 45, # Group 0. Start / stop when in alert condition.
|
80
|
+
elev_low_alert: 46, # Group 0. Start / stop when in alert condition.
|
81
|
+
comm_timeout: 47, # marker
|
82
|
+
}.freeze
|
83
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "rubyfit/type"
|
2
2
|
require "rubyfit/helpers"
|
3
|
+
require "rubyfit/message_constants"
|
3
4
|
|
4
5
|
class RubyFit::MessageWriter
|
5
6
|
extend RubyFit::Helpers
|
@@ -7,36 +8,6 @@ class RubyFit::MessageWriter
|
|
7
8
|
FIT_PROTOCOL_VERSION = 0x10 # major 1, minor 0
|
8
9
|
FIT_PROFILE_VERSION = 1 * 100 + 52 # major 1, minor 52
|
9
10
|
|
10
|
-
COURSE_POINT_TYPE = {
|
11
|
-
invalid: 255,
|
12
|
-
generic: 0,
|
13
|
-
summit: 1,
|
14
|
-
valley: 2,
|
15
|
-
water: 3,
|
16
|
-
food: 4,
|
17
|
-
danger: 5,
|
18
|
-
left: 6,
|
19
|
-
right: 7,
|
20
|
-
straight: 8,
|
21
|
-
first_aid: 9,
|
22
|
-
fourth_category: 10,
|
23
|
-
third_category: 11,
|
24
|
-
second_category: 12,
|
25
|
-
first_category: 13,
|
26
|
-
hors_category: 14,
|
27
|
-
sprint: 15,
|
28
|
-
left_fork: 16,
|
29
|
-
right_fork: 17,
|
30
|
-
middle_fork: 18,
|
31
|
-
slight_left: 19,
|
32
|
-
sharp_left: 20,
|
33
|
-
slight_right: 21,
|
34
|
-
sharp_right: 22,
|
35
|
-
u_turn: 23,
|
36
|
-
segment_start: 24,
|
37
|
-
segment_end: 25
|
38
|
-
}.freeze
|
39
|
-
|
40
11
|
MESSAGE_DEFINITIONS = {
|
41
12
|
file_id: {
|
42
13
|
id: 0,
|
@@ -59,6 +30,8 @@ class RubyFit::MessageWriter
|
|
59
30
|
fields: {
|
60
31
|
timestamp: { id: 253, type: RubyFit::Type.timestamp, required: true},
|
61
32
|
start_time: { id: 2, type: RubyFit::Type.timestamp, required: true},
|
33
|
+
total_elapsed_time: { id: 7, type: RubyFit::Type.duration, required: true },
|
34
|
+
total_timer_time: { id: 8, type: RubyFit::Type.duration, required: true },
|
62
35
|
start_y: { id: 3, type: RubyFit::Type.semicircles },
|
63
36
|
start_x: { id: 4, type: RubyFit::Type.semicircles },
|
64
37
|
end_y: { id: 5, type: RubyFit::Type.semicircles },
|
@@ -75,7 +48,7 @@ class RubyFit::MessageWriter
|
|
75
48
|
distance: { id: 4, type: RubyFit::Type.centimeters },
|
76
49
|
name: { id: 6, type: RubyFit::Type.string(16) },
|
77
50
|
message_index: { id: 254, type: RubyFit::Type.uint16 },
|
78
|
-
type: { id: 5, type: RubyFit::Type.enum, values: COURSE_POINT_TYPE, required: true }
|
51
|
+
type: { id: 5, type: RubyFit::Type.enum, values: RubyFit::MessageConstants::COURSE_POINT_TYPE, required: true }
|
79
52
|
},
|
80
53
|
},
|
81
54
|
record: {
|
@@ -87,6 +60,15 @@ class RubyFit::MessageWriter
|
|
87
60
|
distance: { id: 5, type: RubyFit::Type.centimeters },
|
88
61
|
elevation: { id: 2, type: RubyFit::Type.altitude },
|
89
62
|
}
|
63
|
+
},
|
64
|
+
event: {
|
65
|
+
id: 21,
|
66
|
+
fields: {
|
67
|
+
timestamp: { id: 253, type: RubyFit::Type.timestamp, required: true },
|
68
|
+
event: { id: 0, type: RubyFit::Type.enum, values: RubyFit::MessageConstants::EVENT, required: true },
|
69
|
+
event_type: { id: 1, type: RubyFit::Type.enum, values: RubyFit::MessageConstants::EVENT_TYPE, required: true },
|
70
|
+
event_group: { id: 4, type: RubyFit::Type.uint8 },
|
71
|
+
}
|
90
72
|
}
|
91
73
|
}
|
92
74
|
|
data/lib/rubyfit/type.rb
CHANGED
data/lib/rubyfit/version.rb
CHANGED
data/lib/rubyfit/writer.rb
CHANGED
@@ -1,57 +1,44 @@
|
|
1
1
|
require "rubyfit/message_writer"
|
2
2
|
|
3
3
|
class RubyFit::Writer
|
4
|
+
PRODUCT_ID = 65534 # Garmin Connect
|
5
|
+
|
4
6
|
def write(stream, opts = {})
|
5
7
|
raise "Can't start write mode from #{@state}" if @state
|
6
8
|
@state = :write
|
7
|
-
@local_nums =
|
9
|
+
@local_nums = {}
|
10
|
+
@last_local_num = -1
|
8
11
|
|
9
12
|
@stream = stream
|
10
13
|
|
11
|
-
%i(start_time
|
14
|
+
%i(start_time duration course_point_count track_point_count name
|
12
15
|
total_distance time_created start_x start_y end_x end_y).each do |key|
|
13
16
|
raise ArgumentError.new("Missing required option #{key}") unless opts[key]
|
14
17
|
end
|
15
18
|
|
16
19
|
start_time = opts[:start_time].to_i
|
17
|
-
|
20
|
+
duration = opts[:duration].to_i
|
18
21
|
|
19
22
|
@data_crc = 0
|
20
23
|
|
21
|
-
|
22
|
-
definition_sizes = %i(file_id course lap course_point record)
|
23
|
-
.map{|type| RubyFit::MessageWriter.definition_message_size(type) }
|
24
|
-
.reduce(&:+)
|
25
|
-
|
26
|
-
data_sizes = {
|
27
|
-
file_id: 1,
|
28
|
-
course: 1,
|
29
|
-
lap: 1,
|
30
|
-
course_point: opts[:course_point_count],
|
31
|
-
record: opts[:track_point_count]
|
32
|
-
}
|
33
|
-
.map{|type, count| RubyFit::MessageWriter.data_message_size(type) * count }
|
34
|
-
.reduce(&:+)
|
35
|
-
|
36
|
-
data_size = definition_sizes + data_sizes
|
24
|
+
data_size = calculate_data_size(opts[:course_point_count], opts[:track_point_count])
|
37
25
|
write_data(RubyFit::MessageWriter.file_header(data_size))
|
38
26
|
|
39
|
-
|
40
|
-
write_data_message(:file_id, {
|
27
|
+
write_message(:file_id, {
|
41
28
|
time_created: opts[:time_created],
|
42
29
|
type: 6, # Course file
|
43
30
|
manufacturer: 1, # Garmin
|
44
|
-
product:
|
31
|
+
product: PRODUCT_ID,
|
45
32
|
serial_number: 0,
|
46
33
|
})
|
47
34
|
|
48
|
-
|
49
|
-
write_data_message(:course, { name: opts[:name] })
|
35
|
+
write_message(:course, { name: opts[:name] })
|
50
36
|
|
51
|
-
|
52
|
-
write_data_message(:lap, {
|
37
|
+
write_message(:lap, {
|
53
38
|
start_time: start_time,
|
54
|
-
timestamp:
|
39
|
+
timestamp: start_time,
|
40
|
+
total_elapsed_time: duration,
|
41
|
+
total_timer_time: duration,
|
55
42
|
start_x: opts[:start_x],
|
56
43
|
start_y: opts[:start_y],
|
57
44
|
end_x: opts[:end_x],
|
@@ -59,8 +46,22 @@ class RubyFit::Writer
|
|
59
46
|
total_distance: opts[:total_distance]
|
60
47
|
})
|
61
48
|
|
49
|
+
write_message(:event, {
|
50
|
+
timestamp: start_time,
|
51
|
+
event: :timer,
|
52
|
+
event_type: :start,
|
53
|
+
event_group: 0
|
54
|
+
})
|
55
|
+
|
62
56
|
yield
|
63
57
|
|
58
|
+
write_message(:event, {
|
59
|
+
timestamp: start_time + duration,
|
60
|
+
event: :timer,
|
61
|
+
event_type: :stop_disable_all,
|
62
|
+
event_group: 0
|
63
|
+
})
|
64
|
+
|
64
65
|
write_data(RubyFit::MessageWriter.crc(@data_crc))
|
65
66
|
@state = nil
|
66
67
|
end
|
@@ -68,7 +69,6 @@ class RubyFit::Writer
|
|
68
69
|
def course_points
|
69
70
|
raise "Can only start course points mode inside 'write' block" if @state != :write
|
70
71
|
@state = :course_points
|
71
|
-
write_definition_message(:course_point)
|
72
72
|
yield
|
73
73
|
@state = :write
|
74
74
|
end
|
@@ -76,29 +76,32 @@ class RubyFit::Writer
|
|
76
76
|
def track_points
|
77
77
|
raise "Can only write track points inside 'write' block" if @state != :write
|
78
78
|
@state = :track_points
|
79
|
-
write_definition_message(:record)
|
80
79
|
yield
|
81
80
|
@state = :write
|
82
81
|
end
|
83
82
|
|
84
83
|
def course_point(values)
|
85
84
|
raise "Can only write course points inside 'course_points' block" if @state != :course_points
|
86
|
-
|
85
|
+
write_message(:course_point, values)
|
87
86
|
end
|
88
87
|
|
89
88
|
def track_point(values)
|
90
89
|
raise "Can only write track points inside 'track_points' block" if @state != :track_points
|
91
|
-
|
90
|
+
write_message(:record, values)
|
92
91
|
end
|
93
92
|
|
94
93
|
protected
|
95
|
-
|
96
|
-
def write_definition_message(type)
|
97
|
-
write_data(RubyFit::MessageWriter.definition_message(type, local_num(type)))
|
98
|
-
end
|
99
94
|
|
100
|
-
def
|
101
|
-
|
95
|
+
def write_message(type, values)
|
96
|
+
local_num = @local_nums[type]
|
97
|
+
unless local_num
|
98
|
+
@last_local_num += 1
|
99
|
+
local_num = @last_local_num
|
100
|
+
@local_nums[type] = local_num
|
101
|
+
write_data(RubyFit::MessageWriter.definition_message(type, local_num))
|
102
|
+
end
|
103
|
+
|
104
|
+
write_data(RubyFit::MessageWriter.data_message(type, local_num, values))
|
102
105
|
end
|
103
106
|
|
104
107
|
def write_data(data)
|
@@ -107,12 +110,24 @@ class RubyFit::Writer
|
|
107
110
|
@data_crc = RubyFit::CRC.update_crc(@data_crc, data)
|
108
111
|
end
|
109
112
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
113
|
+
def calculate_data_size(course_point_count, track_point_count)
|
114
|
+
record_counts = {
|
115
|
+
file_id: 1,
|
116
|
+
course: 1,
|
117
|
+
lap: 1,
|
118
|
+
event: 2,
|
119
|
+
course_point: course_point_count,
|
120
|
+
record: track_point_count,
|
121
|
+
}
|
122
|
+
|
123
|
+
data_sizes = record_counts.map do |type, count|
|
124
|
+
def_size = RubyFit::MessageWriter.definition_message_size(type)
|
125
|
+
data_size = RubyFit::MessageWriter.data_message_size(type) * count
|
126
|
+
result = def_size + data_size
|
127
|
+
puts "#{type}: #{result}"
|
128
|
+
result
|
115
129
|
end
|
116
|
-
|
130
|
+
|
131
|
+
data_sizes.reduce(&:+)
|
117
132
|
end
|
118
133
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyfit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cullen King
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- ext/rubyfit/rubyfit.c
|
92
92
|
- lib/rubyfit.rb
|
93
93
|
- lib/rubyfit/helpers.rb
|
94
|
+
- lib/rubyfit/message_constants.rb
|
94
95
|
- lib/rubyfit/message_writer.rb
|
95
96
|
- lib/rubyfit/type.rb
|
96
97
|
- lib/rubyfit/version.rb
|