nmea_plus 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/nmea_plus.rb +2 -0
- data/lib/nmea_plus/message/ais/base_ais.rb +7 -0
- data/lib/nmea_plus/message/ais/vdm.rb +17 -4
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg.rb +72 -13
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg1.rb +12 -0
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg8.rb +2 -0
- data/lib/nmea_plus/message/base.rb +10 -10
- data/lib/nmea_plus/message/nmea/base_nmea.rb +19 -4
- data/lib/nmea_plus/message/nmea/bwr.rb +4 -0
- data/lib/nmea_plus/message/nmea/dtm.rb +4 -0
- data/lib/nmea_plus/message/nmea/gga.rb +4 -0
- data/lib/nmea_plus/message/nmea/gll.rb +5 -0
- data/lib/nmea_plus/message/nmea/gns.rb +4 -0
- data/lib/nmea_plus/message/nmea/gxa.rb +5 -0
- data/lib/nmea_plus/message/nmea/hdg.rb +4 -0
- data/lib/nmea_plus/message/nmea/rma.rb +6 -0
- data/lib/nmea_plus/message/nmea/rmb.rb +4 -0
- data/lib/nmea_plus/message/nmea/rmc.rb +8 -0
- data/lib/nmea_plus/message/nmea/rte.rb +3 -0
- data/lib/nmea_plus/message/nmea/sfi.rb +2 -0
- data/lib/nmea_plus/message/nmea/trf.rb +6 -0
- data/lib/nmea_plus/message/nmea/vtg.rb +9 -0
- data/lib/nmea_plus/message/nmea/wpl.rb +4 -0
- data/lib/nmea_plus/message/nmea/zda.rb +3 -1
- data/lib/nmea_plus/nmea_message_factory.rb +2 -2
- data/lib/nmea_plus/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a207c93360fededdabcaff54e1728e9ab275b344
|
4
|
+
data.tar.gz: 1085b632c37d05ef034c64804283d376417f55d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8a9716472c3c20a86cf6daaadecc78aa06301d8b3f37b1e9141ec2d05c5135f2dd5f5bc70e5e2f09339e59a0e2fe30c8773805ea18e3aa59887dd5b54f109cf
|
7
|
+
data.tar.gz: 005a20dcb935adb5fd9d0762ed40b94a9c6950ea7dc2b1c8b914fe7631bbb005cc305a825f74b931c25bcb2d97908d87e657393f38c585e0e0973549ad6c1c7c
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/nmea_plus.svg)](https://rubygems.org/gems/nmea_plus)
|
4
4
|
[![Build Status](https://travis-ci.org/ifreecarve/nmea_plus.svg)](https://travis-ci.org/ifreecarve/nmea_plus)
|
5
|
+
[![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://rubydoc.org/gems/nmea_plus/frames)
|
5
6
|
|
6
7
|
[NMEA Plus](https://github.com/ifreecarve/nmea_plus) is a Ruby gem for parsing and decoding "GPS" messages: NMEA, AIS, and any other similar formats of short messaging typically used by marine equipment. It provides convenient access (by name) to the fields of each message type, and a stream reader designed for use with Ruby Blocks.
|
7
8
|
|
data/lib/nmea_plus.rb
CHANGED
@@ -4,6 +4,8 @@ require 'nmea_plus/generated_parser/parser'
|
|
4
4
|
require 'nmea_plus/generated_parser/tokenizer'
|
5
5
|
|
6
6
|
# NMEAPlus contains classes for parsing and decoding NMEA and AIS messages.
|
7
|
+
# You probably want to check out {NMEAPlus::Message::NMEA::NMEAMessage}
|
8
|
+
# and {NMEAPlus::Message::AIS::AISMessage}.
|
7
9
|
# @author Ian Katz
|
8
10
|
module NMEAPlus
|
9
11
|
|
@@ -3,13 +3,20 @@ require_relative "../base"
|
|
3
3
|
|
4
4
|
module NMEAPlus
|
5
5
|
module Message
|
6
|
+
# A container for all {AISMessage} types.
|
6
7
|
module AIS
|
7
8
|
|
8
9
|
class AISMessage < NMEAPlus::Message::Base
|
10
|
+
# NMEA (AIS) message types are 5 characters, the first 2 of which are the talker ID
|
11
|
+
# @!parse attr_accessor :talker
|
12
|
+
# @return [String] The two-character "talker ID" of the message
|
9
13
|
def talker
|
10
14
|
data_type[0..1]
|
11
15
|
end
|
12
16
|
|
17
|
+
# NMEA (AIS) message types are 5 characters (or so), the last of which are the message type
|
18
|
+
# @!parse attr_accessor :message_type
|
19
|
+
# @return [String] The two-character "talker ID" of the message
|
13
20
|
def message_type
|
14
21
|
data_type[2..-1]
|
15
22
|
end
|
@@ -21,7 +21,6 @@ require_relative "vdm_payload/vdm_msg1"
|
|
21
21
|
require_relative "vdm_payload/vdm_msg5"
|
22
22
|
require_relative "vdm_payload/vdm_msg8"
|
23
23
|
|
24
|
-
|
25
24
|
module NMEAPlus
|
26
25
|
module Message
|
27
26
|
module AIS
|
@@ -33,8 +32,10 @@ module NMEAPlus
|
|
33
32
|
field_reader :raw_ais_payload, 5, :_string
|
34
33
|
field_reader :ais_payload_fill_bits, 6, :_integer
|
35
34
|
|
35
|
+
# factory method: find the appropriate message type class and instantiate it
|
36
|
+
# @!parse attr_reader :ais
|
37
|
+
# @return [VDMPayload::VDMMsg]
|
36
38
|
def ais
|
37
|
-
# factory method: find the appropriate message type class and instantiate it
|
38
39
|
p = full_dearmored_ais_payload
|
39
40
|
ret = _payload_container(p[0, 6].to_i(2))
|
40
41
|
ret.payload_bitstring = p
|
@@ -42,7 +43,9 @@ module NMEAPlus
|
|
42
43
|
ret
|
43
44
|
end
|
44
45
|
|
45
|
-
# the full encoded payload as it was received
|
46
|
+
# the full encoded payload as it was received -- spanning multiple messages
|
47
|
+
# @!parse attr_reader :full_armored_ais_payload
|
48
|
+
# @return [String]
|
46
49
|
def full_armored_ais_payload
|
47
50
|
# get the full message and fill bits for the last one
|
48
51
|
ptr = self
|
@@ -56,6 +59,8 @@ module NMEAPlus
|
|
56
59
|
end
|
57
60
|
|
58
61
|
# a binary string ("0010101110110") representing the dearmored payload
|
62
|
+
# @!parse attr_reader :full_dearmored_ais_payload
|
63
|
+
# @return [String]
|
59
64
|
def full_dearmored_ais_payload
|
60
65
|
data = full_armored_ais_payload
|
61
66
|
out = ""
|
@@ -65,8 +70,10 @@ module NMEAPlus
|
|
65
70
|
out
|
66
71
|
end
|
67
72
|
|
73
|
+
# Get the fill bits for the last message in the sequence -- the only one that matters
|
74
|
+
# @!parse attr_reader :last_ais_fill_bits
|
75
|
+
# @return [Integer]
|
68
76
|
def last_ais_fill_bits
|
69
|
-
# get the fill bits for the last message in the sequence
|
70
77
|
ptr = self
|
71
78
|
fill_bits = nil
|
72
79
|
loop do
|
@@ -78,6 +85,9 @@ module NMEAPlus
|
|
78
85
|
end
|
79
86
|
|
80
87
|
# perform the 6-bit to 8-bit conversion defined in the spec
|
88
|
+
# @param c [String] a character
|
89
|
+
# @param len [Integer] The number of bits to consider
|
90
|
+
# @return [String] a binary encoded string
|
81
91
|
def _dearmor6b(c, len = 6)
|
82
92
|
val = c.ord
|
83
93
|
if val >= 96
|
@@ -88,6 +98,9 @@ module NMEAPlus
|
|
88
98
|
ret.to_s(2).rjust(6, "0")[0..(len - 1)]
|
89
99
|
end
|
90
100
|
|
101
|
+
# Find an appropriate payload container for the payload type, based on its stated message ID
|
102
|
+
# @param message_type_id [String]
|
103
|
+
# @return [NMEAPlus::Message::AIS::VDMPayload::VDMMsg] The parsed payload
|
91
104
|
def _payload_container(message_type_id)
|
92
105
|
class_identifier = "NMEAPlus::Message::AIS::VDMPayload::VDMMsg#{message_type_id}"
|
93
106
|
Object::const_get(class_identifier).new
|
@@ -1,69 +1,111 @@
|
|
1
1
|
class Class
|
2
|
-
# make our own shortcut syntax for payload attributes
|
3
|
-
def payload_reader(name, start_bit, length, formatter, formatter_arg = nil)
|
4
|
-
if formatter_arg.nil?
|
5
|
-
self.class_eval("def #{name};#{formatter}(#{start_bit}, #{length});end")
|
6
|
-
else
|
7
|
-
self.class_eval("def #{name};#{formatter}(#{start_bit}, #{length}, #{formatter_arg});end")
|
8
|
-
end
|
9
|
-
end
|
10
2
|
end
|
11
3
|
|
12
4
|
module NMEAPlus
|
13
5
|
module Message
|
14
6
|
module AIS
|
7
|
+
# There are many VDM payload types, and this is their container. See {VDMMsg}.
|
15
8
|
module VDMPayload
|
9
|
+
# The base class for the AIS payload (of {NMEAPlus::Message::AIS::VDM}) which can be of many types.
|
16
10
|
class VDMMsg
|
11
|
+
# @return [String] The raw "armored payload" in the original message
|
17
12
|
attr_accessor :payload_bitstring
|
13
|
+
|
14
|
+
# @return [Integer] The number of padding characters required to bring the payload to a 6 bit boundary
|
18
15
|
attr_accessor :fill_bits
|
19
16
|
|
17
|
+
# make our own shortcut syntax for payload attributes
|
18
|
+
# @param name [String] What the accessor will be called
|
19
|
+
# @param start_bit [Integer] The index of first bit of this field in the payload
|
20
|
+
# @param length [Integer] The number of bits in this field
|
21
|
+
# @param formatter [Symbol] The symbol for the formatting function to apply to the field (optional)
|
22
|
+
# @param formatter_arg Any argument necessary for the formatting function
|
23
|
+
# @macro [attach] payload_reader
|
24
|
+
# @!attribute [r] $1
|
25
|
+
# @return The field defined by $3 bits starting at bit $2 of the payload, formatted with the function {#$4}($5)
|
26
|
+
def self.payload_reader(name, start_bit, length, formatter, formatter_arg = nil)
|
27
|
+
if formatter_arg.nil?
|
28
|
+
self.class_eval("def #{name};#{formatter}(#{start_bit}, #{length});end")
|
29
|
+
else
|
30
|
+
self.class_eval("def #{name};#{formatter}(#{start_bit}, #{length}, #{formatter_arg});end")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
20
34
|
payload_reader :message_type, 0, 6, :_u
|
21
35
|
payload_reader :repeat_indicator, 6, 2, :_u
|
22
36
|
payload_reader :source_mmsi, 8, 30, :_u
|
23
37
|
|
24
|
-
#
|
38
|
+
# Convert 6-bit ascii to a character, according to http://catb.org/gpsd/AIVDM.html#_ais_payload_data_types
|
39
|
+
# @param ord [Integer] The 6-bit ascii code
|
40
|
+
# @return [String] the character for that code
|
25
41
|
def _6b_ascii(ord)
|
26
42
|
'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !"#$%&\'()*+,-./0123456789:;<=>?'[ord]
|
27
43
|
end
|
28
44
|
|
29
|
-
#
|
45
|
+
# Access part of the payload. If there aren't bytes, there, return nil
|
30
46
|
# else execute a block
|
47
|
+
# @param start [Integer] The index of the first bit in the payload field
|
48
|
+
# @param length [Integer] The number of bits in the payload field
|
49
|
+
# @return Nil or whatever is yielded by the block
|
50
|
+
# @yield [String] A binary coded string ("010010101" etc)
|
31
51
|
def _access(start, length)
|
32
52
|
part = @payload_bitstring[start, length]
|
33
53
|
return nil if part.nil? || part.empty?
|
34
54
|
yield part
|
35
55
|
end
|
36
56
|
|
37
|
-
#
|
57
|
+
# pull out 6b chunks from the payload, then convert those to their more familar characters
|
58
|
+
# @param start [Integer] The index of the first bit in the payload field
|
59
|
+
# @param length [Integer] The number of bits in the payload field
|
60
|
+
# @return [String]
|
38
61
|
def _6b_string(start, length)
|
39
|
-
# pull out 6b chunks from the string, use their value as a lookup into the ascii array
|
40
62
|
_bit_slices(start, length, 6).to_a.map(&:join).map { |x| _6b_ascii(x.to_i(2)) }.join
|
41
63
|
end
|
42
64
|
|
65
|
+
# pull out 8b chunks from the payload, then convert those to their more familar characters
|
66
|
+
# @param start [Integer] The index of the first bit in the payload field
|
67
|
+
# @param length [Integer] The number of bits in the payload field
|
68
|
+
# @return [String]
|
43
69
|
def _8b_data_string(start, length)
|
44
70
|
_bit_slices(start, length, 8).to_a.map(&:join).map { |x| x.to_i(2).chr }.join
|
45
71
|
end
|
46
72
|
|
73
|
+
# Slice a part of the payload into binary chunks of a given size
|
74
|
+
# @param start [Integer] The index of the first bit in the payload field
|
75
|
+
# @param length [Integer] The number of bits in the payload field
|
76
|
+
# @return [Array<String>] Strings representing binary ("01010101" etc) for each slice
|
47
77
|
def _bit_slices(start, length, chunk_size)
|
48
78
|
_access(start, length) { |bits| bits.chars.each_slice(chunk_size) }
|
49
79
|
end
|
50
80
|
|
51
|
-
# convert a string but trim off the 0s ('@')
|
81
|
+
# convert a 6b string but trim off the 0s ('@')
|
82
|
+
# @param start [Integer] The index of the first bit in the payload field
|
83
|
+
# @param length [Integer] The number of bits in the payload field
|
84
|
+
# @return [String]
|
52
85
|
def _6b_string_nullterminated(start, length)
|
53
86
|
_6b_string(start, length).split("@", 2)[0]
|
54
87
|
end
|
55
88
|
|
56
89
|
# directly convert a string to a binary number as you'd read it
|
90
|
+
# @param start [Integer] The index of the first bit in the payload field
|
91
|
+
# @param length [Integer] The number of bits in the payload field
|
92
|
+
# @return [Integer] an unsigned integer value
|
57
93
|
def _6b_unsigned_integer(start, length)
|
58
94
|
_access(start, length) { |bits| bits.to_i(2) }
|
59
95
|
end
|
60
96
|
|
61
97
|
# perform a twos complement operation on part of the payload
|
98
|
+
# @param start [Integer] The index of the first bit in the payload field
|
99
|
+
# @param length [Integer] The number of bits in the payload field
|
100
|
+
# @return [Integer] an integer value
|
62
101
|
def _6b_twoscomplement(start, length)
|
63
102
|
# two's complement: flip bits, then add 1
|
64
103
|
_access(start, length) { |bits| bits.tr("01", "10").to_i(2) + 1 }
|
65
104
|
end
|
66
105
|
|
106
|
+
# @param start [Integer] The index of the first bit in the payload field
|
107
|
+
# @param length [Integer] The number of bits in the payload field
|
108
|
+
# @return [Integer] an integer value
|
67
109
|
def _6b_integer(start, length)
|
68
110
|
# MSB is 1 for negative
|
69
111
|
twoc = _6b_twoscomplement(start, length)
|
@@ -71,19 +113,35 @@ module NMEAPlus
|
|
71
113
|
end
|
72
114
|
|
73
115
|
# scale an integer by dividing it by 10^decimal_places
|
116
|
+
# @param start [Integer] The index of the first bit in the payload field
|
117
|
+
# @param length [Integer] The number of bits in the payload field
|
118
|
+
# @param decimal_places [Integer] The power of ten to use in scaling the result
|
119
|
+
# @return [Integer] an integer value
|
74
120
|
def _6b_integer_scaled(start, length, decimal_places)
|
75
121
|
_6b_integer(start, length).to_f / (10 ** decimal_places)
|
76
122
|
end
|
77
123
|
|
78
124
|
# scale an unsigned integer by dividing it by 10^decimal_places
|
125
|
+
# @param start [Integer] The index of the first bit in the payload field
|
126
|
+
# @param length [Integer] The number of bits in the payload field
|
127
|
+
# @param decimal_places [Integer] The power of ten to use in scaling the result
|
128
|
+
# @return [Integer] an integer value
|
79
129
|
def _6b_unsigned_integer_scaled(start, length, decimal_places)
|
80
130
|
_6b_unsigned_integer(start, length).to_f / (10.0 ** decimal_places)
|
81
131
|
end
|
82
132
|
|
133
|
+
# Get the value of a bit in the payload
|
134
|
+
# @param start [Integer] The index of the first bit in the payload field
|
135
|
+
# @param _ [Integer] Doesn't matter. Here so signatures match; we hard-code 1 because it's 1 bit.
|
136
|
+
# @return [bool]
|
83
137
|
def _6b_boolean(start, _)
|
84
138
|
_access(start, 1) { |bits| bits.to_i == 1 }
|
85
139
|
end
|
86
140
|
|
141
|
+
# Return a string representing binary
|
142
|
+
# @param start [Integer] The index of the first bit in the payload field
|
143
|
+
# @param length [Integer] The number of bits in the payload field
|
144
|
+
# @return [String] e.g. "0101010101011000"
|
87
145
|
def _2b_data_string(start, length)
|
88
146
|
_access(start, length)
|
89
147
|
end
|
@@ -100,6 +158,7 @@ module NMEAPlus
|
|
100
158
|
|
101
159
|
end
|
102
160
|
|
161
|
+
# We haven't defined all the AIS payload types, so this is a catch-all
|
103
162
|
class VDMMsgUndefined < VDMMsg; end
|
104
163
|
|
105
164
|
end
|
@@ -4,10 +4,13 @@ module NMEAPlus
|
|
4
4
|
module Message
|
5
5
|
module AIS
|
6
6
|
module VDMPayload
|
7
|
+
# CNB - The Common Navigation Block, transmitted by AIS messages 1, 2, and 3.
|
7
8
|
class VDMMsgCNB < NMEAPlus::Message::AIS::VDMPayload::VDMMsg
|
8
9
|
|
9
10
|
payload_reader :navigational_status, 38, 4, :_u
|
10
11
|
|
12
|
+
# @!parse attr_reader :navigational_status_description
|
13
|
+
# @return [String] the human-readable description of navigational status
|
11
14
|
def navigational_status_description
|
12
15
|
case navigational_status
|
13
16
|
when 0 then return "Under way using engine"
|
@@ -25,6 +28,9 @@ module NMEAPlus
|
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
# The rate of turn in degrees per minute
|
32
|
+
# @!parse attr_reader :rate_of_turn
|
33
|
+
# @return [Float]
|
28
34
|
def rate_of_turn
|
29
35
|
ret = _i(42, 8)
|
30
36
|
return nil if ret == -128
|
@@ -34,16 +40,22 @@ module NMEAPlus
|
|
34
40
|
payload_reader :speed_over_ground, 50, 10, :_U, 1
|
35
41
|
payload_reader :position_10m_accuracy?, 60, 1, :_b
|
36
42
|
|
43
|
+
# @!parse attr_reader :longitude
|
44
|
+
# @return [Float]
|
37
45
|
def longitude
|
38
46
|
_I(61, 28, 4) / 60
|
39
47
|
end
|
40
48
|
|
49
|
+
# @!parse attr_reader :latitude
|
50
|
+
# @return [Float]
|
41
51
|
def latitude
|
42
52
|
_U(89, 27, 4) / 60
|
43
53
|
end
|
44
54
|
|
45
55
|
payload_reader :course_over_ground, 116, 12, :_U, 1
|
46
56
|
|
57
|
+
# @!parse attr_reader :true_heading
|
58
|
+
# @return [Float]
|
47
59
|
def true_heading
|
48
60
|
ret = _u(128, 9)
|
49
61
|
return nil if ret == 511 # means "not available"
|
@@ -12,8 +12,8 @@ module NMEAPlus
|
|
12
12
|
# @param name [String] What the accessor will be called
|
13
13
|
# @param field_num [Integer] The index of the field in the payload
|
14
14
|
# @param formatter [Symbol] The symbol for the formatting function to apply to the field (optional)
|
15
|
-
#
|
16
|
-
#
|
15
|
+
# @macro [attach] field_reader
|
16
|
+
# @!attribute [r] $1
|
17
17
|
# @return field $2 of the payload, formatted with the function {#$3}
|
18
18
|
def self.field_reader(name, field_num, formatter = nil)
|
19
19
|
if formatter.nil?
|
@@ -149,7 +149,7 @@ module NMEAPlus
|
|
149
149
|
end
|
150
150
|
|
151
151
|
# integer or nil
|
152
|
-
# @param field [String] the field
|
152
|
+
# @param field [String] the value in the field to be checked
|
153
153
|
# @return [Integer] The value in the field or nil
|
154
154
|
def _integer(field)
|
155
155
|
return nil if field.nil? || field.empty?
|
@@ -157,7 +157,7 @@ module NMEAPlus
|
|
157
157
|
end
|
158
158
|
|
159
159
|
# float or nil
|
160
|
-
# @param field [String] the field
|
160
|
+
# @param field [String] the value in the field to be checked
|
161
161
|
# @return [Float] The value in the field or nil
|
162
162
|
def _float(field)
|
163
163
|
return nil if field.nil? || field.empty?
|
@@ -165,7 +165,7 @@ module NMEAPlus
|
|
165
165
|
end
|
166
166
|
|
167
167
|
# string or nil
|
168
|
-
# @param field [String] the field
|
168
|
+
# @param field [String] the value in the field to be checked
|
169
169
|
# @return [String] The value in the field or nil
|
170
170
|
def _string(field)
|
171
171
|
return nil if field.nil? || field.empty?
|
@@ -173,7 +173,7 @@ module NMEAPlus
|
|
173
173
|
end
|
174
174
|
|
175
175
|
# hex to int or nil
|
176
|
-
# @param field [String] the field
|
176
|
+
# @param field [String] the value in the field to be checked
|
177
177
|
# @return [Integer] The value in the field or nil
|
178
178
|
def _hex_to_integer(field)
|
179
179
|
return nil if field.nil? || field.empty?
|
@@ -181,7 +181,7 @@ module NMEAPlus
|
|
181
181
|
end
|
182
182
|
|
183
183
|
# utc time or nil (HHMMSS or HHMMSS.SS)
|
184
|
-
# @param field [String] the field
|
184
|
+
# @param field [String] the value in the field to be checked
|
185
185
|
# @return [Time] The value in the field or nil
|
186
186
|
def _utctime_hms(field)
|
187
187
|
return nil if field.nil? || field.empty?
|
@@ -196,7 +196,7 @@ module NMEAPlus
|
|
196
196
|
end
|
197
197
|
|
198
198
|
# time interval or nil (HHMMSS or HHMMSS.SS)
|
199
|
-
# @param field [String] the field
|
199
|
+
# @param field [String] the value in the field to be checked
|
200
200
|
# @return [Time] The value in the field or nil
|
201
201
|
def _interval_hms(field)
|
202
202
|
return nil if field.nil? || field.empty?
|
@@ -209,8 +209,8 @@ module NMEAPlus
|
|
209
209
|
end
|
210
210
|
end
|
211
211
|
|
212
|
-
# @param d_field [String] the date field
|
213
|
-
# @param t_field [String] the time field
|
212
|
+
# @param d_field [String] the date value in the field to be checked
|
213
|
+
# @param t_field [String] the time value in the field to be checked
|
214
214
|
# @return [Time] The value in the fields, or nil if either is not provided
|
215
215
|
def _utc_date_time(d_field, t_field)
|
216
216
|
return nil if t_field.nil? || t_field.empty?
|
@@ -3,27 +3,42 @@ require_relative "../base"
|
|
3
3
|
|
4
4
|
module NMEAPlus
|
5
5
|
module Message
|
6
|
+
# A container for all {NMEAMessage} typs.
|
6
7
|
module NMEA
|
7
8
|
|
9
|
+
# The base class for NMEA messages includes a few more NMEA-specific parsing functions
|
8
10
|
class NMEAMessage < NMEAPlus::Message::Base
|
11
|
+
|
12
|
+
# NMEA message types are 5 characters, the first 2 of which are the talker ID
|
13
|
+
# @!parse attr_accessor :talker
|
14
|
+
# @return [String] The two-character "talker ID" of the message
|
9
15
|
def talker
|
10
16
|
data_type[0..1]
|
11
17
|
end
|
12
18
|
|
19
|
+
# NMEA message types are 5 characters (or so), the last of which are the message type
|
20
|
+
# @!parse attr_accessor :message_type
|
21
|
+
# @return [String] The two-character "talker ID" of the message
|
13
22
|
def message_type
|
14
23
|
data_type[2..-1]
|
15
24
|
end
|
16
25
|
|
17
|
-
|
18
|
-
|
26
|
+
# Convert a string true/false (encoded as A=true, V=false) to boolean
|
27
|
+
# @param field [String] the value in the field to be checked
|
28
|
+
# @return [bool] The value in the field or nil
|
29
|
+
def _av_boolean(field)
|
30
|
+
case field
|
19
31
|
when 'A' then return true
|
20
32
|
when 'V' then return false
|
21
33
|
end
|
22
34
|
nil
|
23
35
|
end
|
24
36
|
|
25
|
-
|
26
|
-
|
37
|
+
# Convert a string true/false (encoded as 1=true, 0=false) to boolean
|
38
|
+
# @param field [String] the value in the field to be checked
|
39
|
+
# @return [bool] The value in the field or nil
|
40
|
+
def _10_boolean(field)
|
41
|
+
case field
|
27
42
|
when '1' then return true
|
28
43
|
when '0' then return false
|
29
44
|
end
|
@@ -6,10 +6,14 @@ module NMEAPlus
|
|
6
6
|
class BWR < NMEAPlus::Message::NMEA::NMEAMessage
|
7
7
|
field_reader :utc_time, 1, :_utctime_hms
|
8
8
|
|
9
|
+
# @!parse attr_reader :waypoint_latitude
|
10
|
+
# @return [Float]
|
9
11
|
def waypoint_latitude
|
10
12
|
_degrees_minutes_to_decimal(@fields[2], @fields[3])
|
11
13
|
end
|
12
14
|
|
15
|
+
# @!parse attr_reader :waypoint_longitude
|
16
|
+
# @return [Float]
|
13
17
|
def waypoint_longitude
|
14
18
|
_degrees_minutes_to_decimal(@fields[4], @fields[5])
|
15
19
|
end
|
@@ -7,10 +7,14 @@ module NMEAPlus
|
|
7
7
|
field_reader :code, 1, :_string
|
8
8
|
field_reader :subcode, 2, :_string
|
9
9
|
|
10
|
+
# @!parse attr_reader :latitude_offset
|
11
|
+
# @return [Float]
|
10
12
|
def latitude_offset
|
11
13
|
_nsew_signed_float(@fields[3], @fields[4])
|
12
14
|
end
|
13
15
|
|
16
|
+
# @!parse attr_reader :longitude_offset
|
17
|
+
# @return [Float]
|
14
18
|
def longitude_offset
|
15
19
|
_nsew_signed_float(@fields[5], @fields[6])
|
16
20
|
end
|
@@ -8,10 +8,14 @@ module NMEAPlus
|
|
8
8
|
class GGA < NMEAPlus::Message::NMEA::NMEAMessage
|
9
9
|
field_reader :fix_time, 1, :_utctime_hms
|
10
10
|
|
11
|
+
# @!parse attr_reader :latitude
|
12
|
+
# @return [Float]
|
11
13
|
def latitude
|
12
14
|
_degrees_minutes_to_decimal(@fields[2], @fields[3])
|
13
15
|
end
|
14
16
|
|
17
|
+
# @!parse attr_reader :longitude
|
18
|
+
# @return [Float]
|
15
19
|
def longitude
|
16
20
|
_degrees_minutes_to_decimal(@fields[4], @fields[5])
|
17
21
|
end
|
@@ -4,10 +4,15 @@ module NMEAPlus
|
|
4
4
|
module Message
|
5
5
|
module NMEA
|
6
6
|
class GLL < NMEAPlus::Message::NMEA::NMEAMessage
|
7
|
+
|
8
|
+
# @!parse attr_reader :latitude
|
9
|
+
# @return [Float]
|
7
10
|
def latitude
|
8
11
|
_degrees_minutes_to_decimal(@fields[1], @fields[2])
|
9
12
|
end
|
10
13
|
|
14
|
+
# @!parse attr_reader :longitude
|
15
|
+
# @return [Float]
|
11
16
|
def longitude
|
12
17
|
_degrees_minutes_to_decimal(@fields[3], @fields[4])
|
13
18
|
end
|
@@ -7,10 +7,14 @@ module NMEAPlus
|
|
7
7
|
class GNS < NMEAPlus::Message::NMEA::NMEAMessage
|
8
8
|
field_reader :fix_time, 1, :_utctime_hms
|
9
9
|
|
10
|
+
# @!parse attr_reader :latitude
|
11
|
+
# @return [Float]
|
10
12
|
def latitude
|
11
13
|
_degrees_minutes_to_decimal(@fields[2], @fields[3])
|
12
14
|
end
|
13
15
|
|
16
|
+
# @!parse attr_reader :longitude
|
17
|
+
# @return [Float]
|
14
18
|
def longitude
|
15
19
|
_degrees_minutes_to_decimal(@fields[4], @fields[5])
|
16
20
|
end
|
@@ -6,10 +6,15 @@ module NMEAPlus
|
|
6
6
|
class GXA < NMEAPlus::Message::NMEA::NMEAMessage
|
7
7
|
|
8
8
|
field_reader :fix_time, 1, :_utctime_hms
|
9
|
+
|
10
|
+
# @!parse attr_reader :latitude
|
11
|
+
# @return [Float]
|
9
12
|
def latitude
|
10
13
|
_degrees_minutes_to_decimal(@fields[2], @fields[3])
|
11
14
|
end
|
12
15
|
|
16
|
+
# @!parse attr_reader :longitude
|
17
|
+
# @return [Float]
|
13
18
|
def longitude
|
14
19
|
_degrees_minutes_to_decimal(@fields[4], @fields[5])
|
15
20
|
end
|
@@ -6,10 +6,14 @@ module NMEAPlus
|
|
6
6
|
module NMEA
|
7
7
|
class HDG < NMEAPlus::Message::NMEA::HDM
|
8
8
|
|
9
|
+
# @!parse attr_reader :magnetic_deviation_degrees
|
10
|
+
# @return [Float]
|
9
11
|
def magnetic_deviation_degrees
|
10
12
|
_nsew_signed_float(@fields[2], @fields[3])
|
11
13
|
end
|
12
14
|
|
15
|
+
# @!parse attr_reader :magnetic_variation_degrees
|
16
|
+
# @return [Float]
|
13
17
|
def magnetic_variation_degrees
|
14
18
|
_nsew_signed_float(@fields[4], @fields[5])
|
15
19
|
end
|
@@ -7,10 +7,14 @@ module NMEAPlus
|
|
7
7
|
|
8
8
|
field_reader :blink_warning, 1, :_av_boolean
|
9
9
|
|
10
|
+
# @!parse attr_reader :latitude
|
11
|
+
# @return [Float]
|
10
12
|
def latitude
|
11
13
|
_degrees_minutes_to_decimal(@fields[2], @fields[3])
|
12
14
|
end
|
13
15
|
|
16
|
+
# @!parse attr_reader :longitude
|
17
|
+
# @return [Float]
|
14
18
|
def longitude
|
15
19
|
_degrees_minutes_to_decimal(@fields[4], @fields[5])
|
16
20
|
end
|
@@ -20,6 +24,8 @@ module NMEAPlus
|
|
20
24
|
field_reader :speed_over_ground_knots, 8, :_float
|
21
25
|
field_reader :track_made_good_degrees_true, 9, :_float
|
22
26
|
|
27
|
+
# @!parse attr_reader :magnetic_variation_degrees
|
28
|
+
# @return [Float]
|
23
29
|
def magnetic_variation_degrees
|
24
30
|
_nsew_signed_float(@fields[10], @fields[11])
|
25
31
|
end
|
@@ -11,10 +11,14 @@ module NMEAPlus
|
|
11
11
|
field_reader :waypoint_to, 4, :_integer
|
12
12
|
field_reader :waypoint_from, 5, :_integer
|
13
13
|
|
14
|
+
# @!parse attr_reader :waypoint_latitude
|
15
|
+
# @return [Float]
|
14
16
|
def waypoint_latitude
|
15
17
|
_degrees_minutes_to_decimal(@fields[6], @fields[7])
|
16
18
|
end
|
17
19
|
|
20
|
+
# @!parse attr_reader :waypoint_longitude
|
21
|
+
# @return [Float]
|
18
22
|
def waypoint_longitude
|
19
23
|
_degrees_minutes_to_decimal(@fields[8], @fields[9])
|
20
24
|
end
|
@@ -5,16 +5,22 @@ module NMEAPlus
|
|
5
5
|
module NMEA
|
6
6
|
class RMC < NMEAPlus::Message::NMEA::NMEAMessage
|
7
7
|
|
8
|
+
# @!parse attr_reader :utc_time
|
9
|
+
# @return [Time]
|
8
10
|
def utc_time
|
9
11
|
_utc_date_time(@fields[9], @fields[1])
|
10
12
|
end
|
11
13
|
|
12
14
|
field_reader :active?, 2, :_av_boolean
|
13
15
|
|
16
|
+
# @!parse attr_reader :latitude
|
17
|
+
# @return [Float]
|
14
18
|
def latitude
|
15
19
|
_degrees_minutes_to_decimal(@fields[3], @fields[4])
|
16
20
|
end
|
17
21
|
|
22
|
+
# @!parse attr_reader :longitude
|
23
|
+
# @return [Float]
|
18
24
|
def longitude
|
19
25
|
_degrees_minutes_to_decimal(@fields[5], @fields[6])
|
20
26
|
end
|
@@ -22,6 +28,8 @@ module NMEAPlus
|
|
22
28
|
field_reader :speed_over_ground_knots, 7, :_float
|
23
29
|
field_reader :track_made_good_degrees_true, 8, :_float
|
24
30
|
|
31
|
+
# @!parse attr_reader :magnetic_variation_degrees
|
32
|
+
# @return [Float]
|
25
33
|
def magnetic_variation_degrees
|
26
34
|
_nsew_signed_float(@fields[10], @fields[11])
|
27
35
|
end
|
@@ -4,14 +4,20 @@ module NMEAPlus
|
|
4
4
|
module Message
|
5
5
|
module NMEA
|
6
6
|
class TRF < NMEAPlus::Message::NMEA::NMEAMessage
|
7
|
+
# @!parse attr_reader :utc_time
|
8
|
+
# @return [Time]
|
7
9
|
def utc_time
|
8
10
|
_utc_date_time(@fields[2], @fields[1])
|
9
11
|
end
|
10
12
|
|
13
|
+
# @!parse attr_reader :latitude
|
14
|
+
# @return [Float]
|
11
15
|
def latitude
|
12
16
|
_degrees_minutes_to_decimal(@fields[3], @fields[4])
|
13
17
|
end
|
14
18
|
|
19
|
+
# @!parse attr_reader :longitude
|
20
|
+
# @return [Float]
|
15
21
|
def longitude
|
16
22
|
_degrees_minutes_to_decimal(@fields[5], @fields[6])
|
17
23
|
end
|
@@ -5,30 +5,39 @@ module NMEAPlus
|
|
5
5
|
module NMEA
|
6
6
|
class VTG < NMEAPlus::Message::NMEA::NMEAMessage
|
7
7
|
# whether this is the new format. docs say check field #2 for value "2"
|
8
|
+
# @return [bool]
|
8
9
|
def new_format?
|
9
10
|
'T' == @fields[2]
|
10
11
|
end
|
11
12
|
|
12
13
|
field_reader :track_degrees_true, 1, :_float
|
13
14
|
|
15
|
+
# @!parse attr_reader :track_degrees_magnetic
|
16
|
+
# @return [Float]
|
14
17
|
def track_degrees_magnetic
|
15
18
|
f = new_format? ? 3 : 2
|
16
19
|
return nil if @fields[f].nil? || @fields[f].empty?
|
17
20
|
@fields[f].to_f
|
18
21
|
end
|
19
22
|
|
23
|
+
# @!parse attr_reader :speed_knots
|
24
|
+
# @return [Float]
|
20
25
|
def speed_knots
|
21
26
|
f = new_format? ? 5 : 3
|
22
27
|
return nil if @fields[f].nil? || @fields[f].empty?
|
23
28
|
@fields[f].to_f
|
24
29
|
end
|
25
30
|
|
31
|
+
# @!parse attr_reader :speed_kmh
|
32
|
+
# @return [Float]
|
26
33
|
def speed_kmh
|
27
34
|
f = new_format? ? 7 : 4
|
28
35
|
return nil if @fields[f].nil? || @fields[f].empty?
|
29
36
|
@fields[f].to_f
|
30
37
|
end
|
31
38
|
|
39
|
+
# @!parse attr_reader :faa_mode
|
40
|
+
# @return [String]
|
32
41
|
def faa_mode
|
33
42
|
f = new_format? ? 9 : 100
|
34
43
|
return nil if @fields[f].nil? || @fields[f].empty?
|
@@ -4,10 +4,14 @@ module NMEAPlus
|
|
4
4
|
module Message
|
5
5
|
module NMEA
|
6
6
|
class WPL < NMEAPlus::Message::NMEA::NMEAMessage
|
7
|
+
# @!parse attr_reader :latitude
|
8
|
+
# @return [Float]
|
7
9
|
def latitude
|
8
10
|
_degrees_minutes_to_decimal(@fields[1], @fields[2])
|
9
11
|
end
|
10
12
|
|
13
|
+
# @!parse attr_reader :longitude
|
14
|
+
# @return [Float]
|
11
15
|
def longitude
|
12
16
|
_degrees_minutes_to_decimal(@fields[3], @fields[4])
|
13
17
|
end
|
@@ -4,8 +4,10 @@ module NMEAPlus
|
|
4
4
|
module Message
|
5
5
|
module NMEA
|
6
6
|
class ZDA < NMEAPlus::Message::NMEA::NMEAMessage
|
7
|
-
def utc_time
|
8
7
|
|
8
|
+
# @!parse attr_reader :utc_time
|
9
|
+
# @return [Time]
|
10
|
+
def utc_time
|
9
11
|
re_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
|
10
12
|
hms = re_format.match(@fields[1])
|
11
13
|
begin
|
@@ -79,6 +79,8 @@ require_relative 'message/nmea/ztg'
|
|
79
79
|
# proprietary
|
80
80
|
require_relative 'message/nmea/pashr'
|
81
81
|
|
82
|
+
module NMEAPlus
|
83
|
+
|
82
84
|
=begin boilerplate for message definitions
|
83
85
|
require_relative 'base_nmea'
|
84
86
|
|
@@ -93,8 +95,6 @@ module NMEAPlus
|
|
93
95
|
end
|
94
96
|
=end
|
95
97
|
|
96
|
-
module NMEAPlus
|
97
|
-
|
98
98
|
# Defines a factory for NMEA messages, which will all use {NMEAPlus::Message::NMEA::NMEAMessage} as their base
|
99
99
|
class NMEAMessageFactory < MessageFactory
|
100
100
|
|
data/lib/nmea_plus/version.rb
CHANGED