Class: RubyFit::MessageWriter
- Inherits:
-
Object
- Object
- RubyFit::MessageWriter
- Extended by:
- Helpers
- Defined in:
- lib/rubyfit/message_writer.rb
Constant Summary collapse
- FIT_PROTOCOL_VERSION =
major 1, minor 0
0x10- FIT_PROFILE_VERSION =
major 1, minor 52
1 * 100 + 52
- COURSE_POINT_TYPE =
{ invalid: 255, generic: 0, summit: 1, valley: 2, water: 3, food: 4, danger: 5, left: 6, right: 7, straight: 8, first_aid: 9, fourth_category: 10, third_category: 11, second_category: 12, first_category: 13, hors_category: 14, sprint: 15, left_fork: 16, right_fork: 17, middle_fork: 18, slight_left: 19, sharp_left: 20, slight_right: 21, sharp_right: 22, u_turn: 23, segment_start: 24, segment_end: 25 }.freeze
- MESSAGE_DEFINITIONS =
{ file_id: { id: 0, fields: { serial_number: { id: 3, type: RubyFit::Type.uint32z, required: true }, time_created: { id: 4, type: RubyFit::Type., required: true }, manufacturer: { id: 1, type: RubyFit::Type.uint16 }, # See FIT_MANUFACTURER_* product: { id: 2, type: RubyFit::Type.uint16 }, type: { id: 0, type: RubyFit::Type.enum, required: true }, # See FIT_FILE_* } }, course: { id: 31, fields: { name: { id: 5, type: RubyFit::Type.string(16), required: true }, } }, lap: { id: 19, fields: { timestamp: { id: 253, type: RubyFit::Type., required: true}, start_time: { id: 2, type: RubyFit::Type., required: true}, start_y: { id: 3, type: RubyFit::Type.semicircles }, start_x: { id: 4, type: RubyFit::Type.semicircles }, end_y: { id: 5, type: RubyFit::Type.semicircles }, end_x: { id: 6, type: RubyFit::Type.semicircles }, total_distance: { id: 9, type: RubyFit::Type.centimeters }, }, }, course_point: { id: 32, fields: { timestamp: { id: 1, type: RubyFit::Type., required: true }, y: { id: 2, type: RubyFit::Type.semicircles, required: true }, x: { id: 3, type: RubyFit::Type.semicircles, required: true }, distance: { id: 4, type: RubyFit::Type.centimeters }, name: { id: 6, type: RubyFit::Type.string(16) }, message_index: { id: 254, type: RubyFit::Type.uint16 }, type: { id: 5, type: RubyFit::Type.enum, values: COURSE_POINT_TYPE, required: true } }, }, record: { id: 20, fields: { timestamp: { id: 253, type: RubyFit::Type., required: true }, y: { id: 0, type: RubyFit::Type.semicircles, required: true }, x: { id: 1, type: RubyFit::Type.semicircles, required: true }, distance: { id: 5, type: RubyFit::Type.centimeters }, elevation: { id: 2, type: RubyFit::Type.altitude }, } } }
Constants included from Helpers
Helpers::DEGREES_TO_SEMICIRCLES, Helpers::GARMIN_TIME_OFFSET
Class Method Summary collapse
- .crc(crc_value) ⇒ Object
- .data_message(type, local_num, values) ⇒ Object
- .data_message_size(type) ⇒ Object
- .definition_message(type, local_num) ⇒ Object
- .definition_message_size(type) ⇒ Object
- .file_header(data_byte_count = 0) ⇒ Object
-
.header_byte(local_number, definition) ⇒ Object
Internal.
- .pack_bytes {|bytes| ... } ⇒ Object
Methods included from Helpers
bytes2hex, bytes2num, bytes2str, deg2semicircles, fit2unix_timestamp, make_message_header, num2bytes, semicircles2deg, str2bytes, unix2fit_timestamp
Class Method Details
.crc(crc_value) ⇒ Object
159 160 161 162 163 |
# File 'lib/rubyfit/message_writer.rb', line 159 def self.crc(crc_value) pack_bytes do |bytes| bytes.push(*num2bytes(crc_value, 2, false)) # Little endian end end |
.data_message(type, local_num, values) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/rubyfit/message_writer.rb', line 111 def self.(type, local_num, values) pack_bytes do |bytes| = MESSAGE_DEFINITIONS[type] bytes << header_byte(local_num, false) [:fields].each do |field, info| field_type = info[:type] value = values[field] if info[:required] && value.nil? raise ArgumentError.new("Missing required field '#{field}' in #{type} data message values") end if info[:values] value = info[:values][value] if value.nil? raise ArgumentError.new("Invalid value for '#{field}' in #{type} data message values") end end value_bytes = value ? field_type.val2bytes(value) : field_type.default_bytes bytes.push(*value_bytes) end end end |
.data_message_size(type) ⇒ Object
141 142 143 144 145 |
# File 'lib/rubyfit/message_writer.rb', line 141 def self.(type) = MESSAGE_DEFINITIONS[type] raise ArgumentError.new("Unknown message type '#{type}'") unless 1 + [:fields].values.map{|info| info[:type].byte_count}.reduce(&:+) end |
.definition_message(type, local_num) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rubyfit/message_writer.rb', line 93 def self.(type, local_num) pack_bytes do |bytes| = MESSAGE_DEFINITIONS[type] bytes << header_byte(local_num, true) bytes << 0x00 # Reserved uint8 bytes << 0x01 # Big endian bytes.push(*num2bytes([:id], 2)) # Global message ID bytes << [:fields].size # Field count [:fields].each do |field, info| type = info[:type] bytes << info[:id] bytes << type.byte_count bytes << type.fit_id end end end |
.definition_message_size(type) ⇒ Object
135 136 137 138 139 |
# File 'lib/rubyfit/message_writer.rb', line 135 def self.(type) = MESSAGE_DEFINITIONS[type] raise ArgumentError.new("Unknown message type '#{type}'") unless 6 + [:fields].count * 3 end |
.file_header(data_byte_count = 0) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/rubyfit/message_writer.rb', line 147 def self.file_header(data_byte_count = 0) pack_bytes do |bytes| bytes << 14 # Header size bytes << FIT_PROTOCOL_VERSION # Protocol version bytes.push(*num2bytes(FIT_PROFILE_VERSION, 2).reverse) # Profile version (little endian) bytes.push(*num2bytes(data_byte_count, 4).reverse) # Data size (little endian) bytes.push(*str2bytes(".FIT", 5).take(4)) # Data Type ASCII, no terminator crc = 0 #RubyFit::CRC.update_crc(0, bytes2str(bytes)) bytes.push(*num2bytes(crc, 2).reverse) # Header CRC (little endian) end end |
.header_byte(local_number, definition) ⇒ Object
Internal
167 168 169 |
# File 'lib/rubyfit/message_writer.rb', line 167 def self.header_byte(local_number, definition) local_number & 0xF | (definition ? 0x40 : 0x00) end |
.pack_bytes {|bytes| ... } ⇒ Object
171 172 173 174 175 |
# File 'lib/rubyfit/message_writer.rb', line 171 def self.pack_bytes bytes = [] yield bytes bytes.pack("C*") end |