rubyfit 0.0.8 → 0.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 250aefed2638033617a97b1789e967c90a26940a
4
- data.tar.gz: 46b607c278b112a5dffa6519d54f0bb2c585b0fa
3
+ metadata.gz: 00b20b537878f333895f88bcd88bfa2aed26118a
4
+ data.tar.gz: 5638078b60c7fdbe1dd984e94225a4645959eb3e
5
5
  SHA512:
6
- metadata.gz: d7fbc3064d7e5f8af5947228731c0c2f3213ea196cf4d9f0b2045968216bd41864e04d17c8a646694c5e3ac3541b73fe95861b2574ffa8d84453b9765263e9ca
7
- data.tar.gz: 848eaca18d3bb03a830405671fd1c43e51020bfd51f4a6a66378c225b31e8b29f9d13bf82919c9473bf6fc77bbe03f76cecd443935b19d3ab337ab89b75ec307
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
 
@@ -151,5 +151,12 @@ class RubyFit::Type
151
151
  fit2rb: ->(val, type) { val - 500 }
152
152
  })
153
153
  end
154
+
155
+ def duration
156
+ uint32({
157
+ rb2fit: ->(val, type) { (val * 1000).truncate },
158
+ fit2rb: ->(val, type) { val / 1000.0 }
159
+ })
160
+ end
154
161
  end
155
162
  end
@@ -1,3 +1,3 @@
1
1
  module Rubyfit
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -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 end_time course_point_count track_point_count name
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
- end_time = opts[:end_time].to_i
20
+ duration = opts[:duration].to_i
18
21
 
19
22
  @data_crc = 0
20
23
 
21
- # Calculate data size to put in header
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
- write_definition_message(:file_id)
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: 0,
31
+ product: PRODUCT_ID,
45
32
  serial_number: 0,
46
33
  })
47
34
 
48
- write_definition_message(:course)
49
- write_data_message(:course, { name: opts[:name] })
35
+ write_message(:course, { name: opts[:name] })
50
36
 
51
- write_definition_message(:lap)
52
- write_data_message(:lap, {
37
+ write_message(:lap, {
53
38
  start_time: start_time,
54
- timestamp: end_time,
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
- write_data_message(:course_point, values)
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
- write_data_message(:record, values)
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 write_data_message(type, values)
101
- write_data(RubyFit::MessageWriter.data_message(type, local_num(type), values))
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 local_num(type)
111
- result = @local_nums.index(type)
112
- unless result
113
- result = @local_nums.size
114
- @local_nums << type
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
- result
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.8
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-15 00:00:00.000000000 Z
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