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 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