nmea_plus 1.0.8 → 1.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 +4 -4
- data/README.md +10 -9
- data/lib/nmea_plus/ais_message_factory.rb +3 -1
- data/lib/nmea_plus/generated_parser/tokenizer.rb +1 -1
- data/lib/nmea_plus/message/ais/base_ais.rb +9 -2
- data/lib/nmea_plus/message/ais/vdm.rb +8 -2
- data/lib/nmea_plus/message/ais/vdm_payload/payload.rb +59 -23
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg.rb +444 -76
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg1.rb +6 -5
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg12.rb +5 -2
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg14.rb +1 -1
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg18.rb +5 -3
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg20.rb +2 -1
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg21.rb +2 -1
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg24.rb +2 -1
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg27.rb +2 -1
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg4.rb +15 -2
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg5.rb +3 -2
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6.rb +55 -0
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1022f61.rb +122 -0
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d235f10.rb +54 -0
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg7.rb +36 -0
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg8.rb +2 -9
- data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg9.rb +5 -5
- data/lib/nmea_plus/message/base.rb +27 -14
- data/lib/nmea_plus/message/nmea/base_nmea.rb +13 -7
- data/lib/nmea_plus/message/nmea/bwr.rb +2 -2
- data/lib/nmea_plus/message/nmea/dtm.rb +2 -2
- data/lib/nmea_plus/message/nmea/gga.rb +2 -2
- data/lib/nmea_plus/message/nmea/gll.rb +2 -2
- data/lib/nmea_plus/message/nmea/gns.rb +2 -2
- data/lib/nmea_plus/message/nmea/gxa.rb +2 -2
- data/lib/nmea_plus/message/nmea/hdg.rb +2 -2
- data/lib/nmea_plus/message/nmea/rma.rb +3 -3
- data/lib/nmea_plus/message/nmea/rmb.rb +2 -2
- data/lib/nmea_plus/message/nmea/rmc.rb +3 -3
- data/lib/nmea_plus/message/nmea/trf.rb +2 -2
- data/lib/nmea_plus/message/nmea/wpl.rb +2 -2
- data/lib/nmea_plus/nmea_message_factory.rb +3 -1
- data/lib/nmea_plus/version.rb +1 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b9332e5d45ba59ff6572c20801c15205fcfc674
|
4
|
+
data.tar.gz: ddc8d5117a0b4c4774eb5ffe552b07a1ce2873ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4163c6ee8e9d1ba684cd30f18a94e4d8b42b11c5401a23c57ff0d82b27ce18b9b0ce2a21090e95f9fe96316bda9034f4224ae1b0d12176e75b90309f4369e09b
|
7
|
+
data.tar.gz: 538f7e47902a954c116d1c7d630c51b32a821b5d2cdc1b95e54ad9148ddb3e4b6ef2546b550bda734680e6f0da806d0bf3a87edc947d67ebdc47f1b2ce2d15d5
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# NMEA Ruby
|
1
|
+
# NMEA (GPS) and AIS Parser / Decoder for Ruby (nmea_plus)
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/nmea_plus)
|
4
4
|
[](https://travis-ci.org/ifreecarve/nmea_plus)
|
5
|
-
[](http://www.rubydoc.info/gems/nmea_plus/1.0.
|
5
|
+
[](http://www.rubydoc.info/gems/nmea_plus/1.0.9)
|
6
6
|
|
7
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.
|
8
8
|
|
@@ -84,9 +84,7 @@ end
|
|
84
84
|
|
85
85
|
```
|
86
86
|
|
87
|
-
##
|
88
|
-
|
89
|
-
### NMEA
|
87
|
+
## NMEA (GPS) Parsing
|
90
88
|
|
91
89
|
This gem was coded to accept the standard NMEA messages defined in the unoffical spec found here:
|
92
90
|
http://www.catb.org/gpsd/NMEA.txt
|
@@ -97,16 +95,19 @@ Because the message types are standard, if no override is found for a particular
|
|
97
95
|
|
98
96
|
Support for proprietary NMEA messages is also possible. PASHR is included as proof-of-concept.
|
99
97
|
|
100
|
-
|
98
|
+
|
99
|
+
## AIS Decoding
|
101
100
|
|
102
101
|
AIS message type definitions were implemented from the unofficial spec found here:
|
103
102
|
http://catb.org/gpsd/AIVDM.html
|
104
103
|
|
105
|
-
Currently, the following
|
104
|
+
The AIS payload can be found in the AIVDM message's payload field. Currently, the following AIS message types are supported:
|
106
105
|
|
107
|
-
> 1, 2, 3, 4, 5, 8, 9, 12, 14, 18, 19, 20, 21, 24, 27
|
108
|
-
> Type 8 subtypes for DAC/FID: 1/31, 366/56, 366/57
|
106
|
+
> 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 18, 19, 20, 21, 24, 27
|
109
107
|
|
108
|
+
> Type 6 subtypes for DAC/FID: 235/10, 1022/61
|
109
|
+
|
110
|
+
> Type 8 subtypes for DAC/FID: 1/31, 366/56, 366/57
|
110
111
|
|
111
112
|
|
112
113
|
## Disclaimer
|
@@ -5,7 +5,9 @@ require_relative 'message/ais/vdm'
|
|
5
5
|
|
6
6
|
module NMEAPlus
|
7
7
|
|
8
|
-
# Defines a factory for AIS messages, which will all use {NMEAPlus::Message::AIS::AISMessage} as their base
|
8
|
+
# Defines a factory for AIS messages, which will all use {NMEAPlus::Message::AIS::AISMessage} as their base.
|
9
|
+
# The factory extracts the NMEA data type (prefixed by a 2-character "talker ID"), and looks for a class with
|
10
|
+
# that name within the NMEA message namespace.
|
9
11
|
class AISMessageFactory < MessageFactory
|
10
12
|
# @return [String] The name of the parent module: AIS
|
11
13
|
def self.parent_module
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
module NMEAPlus
|
9
|
-
class Decoder < Parser #
|
9
|
+
class Decoder < Parser # The source file is in .rex format -- indentation and most yard documentation is impossible. The class does a very basic parse of an input line, calling {NMEAPlus::MessageFactory.create} on the result. In parser.y, this is currently defined to be a {NMEAPlus::NMEAMessageFactory} if the line begins with `$` and {NMEAPlus::AISMessageFactory} if the line begins with `!`
|
10
10
|
require 'strscan'
|
11
11
|
|
12
12
|
class ScanError < StandardError ; end
|
@@ -3,18 +3,25 @@ require_relative "../base"
|
|
3
3
|
|
4
4
|
module NMEAPlus
|
5
5
|
module Message
|
6
|
+
|
6
7
|
# A container for all {AISMessage} types.
|
8
|
+
# Most definitions were sourced from http://catb.org/gpsd/AIVDM.html
|
9
|
+
# @see NMEAPlus::Message::AIS::AISMessage Base class for all AIS messages
|
10
|
+
# @see NMEAPlus::Message::AIS::VDMPayload::VDMMsg Base class for all AIS binary payloads
|
7
11
|
module AIS
|
8
12
|
|
13
|
+
# The base NMEA message type for AIS. This is currently a thin wrapper, as {VDM} is the only defined message type.
|
9
14
|
class AISMessage < NMEAPlus::Message::Base
|
10
|
-
#
|
15
|
+
# The first two characters of the NMEA message type
|
11
16
|
# @!parse attr_accessor :talker
|
12
17
|
# @return [String] The two-character "talker ID" of the message
|
13
18
|
def talker
|
14
19
|
data_type[0..1]
|
15
20
|
end
|
16
21
|
|
17
|
-
#
|
22
|
+
# The generic type of the NMEA message.
|
23
|
+
# NMEA message types are 5 characters (or so): the first 2 are the talker ID, and the
|
24
|
+
# remaining characters are the generic message type.
|
18
25
|
# @!parse attr_accessor :message_type
|
19
26
|
# @return [String] The two-character "talker ID" of the message
|
20
27
|
def message_type
|
@@ -18,8 +18,10 @@ end
|
|
18
18
|
=end
|
19
19
|
|
20
20
|
require_relative "vdm_payload/vdm_msg1" # also incldues 2 and 3
|
21
|
-
require_relative "vdm_payload/vdm_msg4"
|
21
|
+
require_relative "vdm_payload/vdm_msg4" # also includes 11
|
22
22
|
require_relative "vdm_payload/vdm_msg5"
|
23
|
+
require_relative "vdm_payload/vdm_msg6"
|
24
|
+
require_relative "vdm_payload/vdm_msg7" # also includes 13
|
23
25
|
require_relative "vdm_payload/vdm_msg8"
|
24
26
|
require_relative "vdm_payload/vdm_msg9"
|
25
27
|
require_relative "vdm_payload/vdm_msg12"
|
@@ -33,6 +35,10 @@ require_relative "vdm_payload/vdm_msg27"
|
|
33
35
|
module NMEAPlus
|
34
36
|
module Message
|
35
37
|
module AIS
|
38
|
+
|
39
|
+
# VDM - Vessel Data Message
|
40
|
+
# This message type thinly wraps AIS payloads.
|
41
|
+
# @see NMEAPlus::Message::AIS::VDMPayload::VDMMsg
|
36
42
|
class VDM < NMEAPlus::Message::AIS::AISMessage
|
37
43
|
field_reader :total_messages, 1, :_integer
|
38
44
|
field_reader :message_number, 2, :_integer
|
@@ -41,7 +47,7 @@ module NMEAPlus
|
|
41
47
|
field_reader :raw_ais_payload, 5, :_string
|
42
48
|
field_reader :ais_payload_fill_bits, 6, :_integer
|
43
49
|
|
44
|
-
# factory method: find the appropriate message type
|
50
|
+
# factory method: find the appropriate class for this AIS message type and instantiate it
|
45
51
|
# @!parse attr_reader :ais
|
46
52
|
# @return [VDMPayload::VDMMsg]
|
47
53
|
def ais
|
@@ -3,7 +3,9 @@ module NMEAPlus
|
|
3
3
|
module Message
|
4
4
|
module AIS
|
5
5
|
module VDMPayload
|
6
|
-
# Basic tools for interpreting the armored payload encoding
|
6
|
+
# Basic tools for interpreting the armored (binary) payload encoding of AIS.
|
7
|
+
# This class provides convenience functions for accessing the fields as the appropriate data type,
|
8
|
+
# as well as logic for AIS bit-level formats
|
7
9
|
class Payload
|
8
10
|
|
9
11
|
def initialize; end
|
@@ -14,7 +16,9 @@ module NMEAPlus
|
|
14
16
|
# @return [Integer] The number of padding characters required to bring the payload to a 6 bit boundary
|
15
17
|
attr_accessor :fill_bits
|
16
18
|
|
17
|
-
#
|
19
|
+
# Enable a shortcut syntax for AIS payload attributes, in the style of `attr_accessor` metaprogramming.
|
20
|
+
# This is used to create a named field pointing to a specific bit range in the payload, applying
|
21
|
+
# a specific formatting function with up to 3 arguments as necessary
|
18
22
|
# @param name [String] What the accessor will be called
|
19
23
|
# @param start_bit [Integer] The index of first bit of this field in the payload
|
20
24
|
# @param length [Integer] The number of bits in this field
|
@@ -22,6 +26,7 @@ module NMEAPlus
|
|
22
26
|
# @param fmt_arg Any argument necessary for the formatting function
|
23
27
|
# @param fmt_arg2 Any other argument necessary for the formatting function
|
24
28
|
# @param fmt_arg3 Any other argument necessary for the formatting function
|
29
|
+
# @return [void]
|
25
30
|
# @macro [attach] payload_reader
|
26
31
|
# @!attribute [r] $1
|
27
32
|
# @return The field defined by the $3 bits starting at payload bit $2, formatted with the function {#$4}($5, $6, $7)
|
@@ -33,6 +38,13 @@ module NMEAPlus
|
|
33
38
|
self.class_eval("def #{name};#{formatter}(#{args.join(', ')});end")
|
34
39
|
end
|
35
40
|
|
41
|
+
# Return an object by its class name, or nil if it isn't defined
|
42
|
+
def _object_by_name(class_identifier)
|
43
|
+
Object::const_get(class_identifier).new
|
44
|
+
rescue ::NameError
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
36
48
|
# Convert 6-bit ascii to a character, according to http://catb.org/gpsd/AIVDM.html#_ais_payload_data_types
|
37
49
|
# @param ord [Integer] The 6-bit ascii code
|
38
50
|
# @return [String] the character for that code
|
@@ -40,8 +52,8 @@ module NMEAPlus
|
|
40
52
|
'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !"#$%&\'()*+,-./0123456789:;<=>?'[ord]
|
41
53
|
end
|
42
54
|
|
43
|
-
# Access part of the payload.
|
44
|
-
#
|
55
|
+
# Access part of the payload.
|
56
|
+
# If there aren't bytes, there, return nil. Else, execute a block
|
45
57
|
# @param start [Integer] The index of the first bit in the payload field
|
46
58
|
# @param length [Integer] The number of bits in the payload field
|
47
59
|
# @return Nil or whatever is yielded by the block
|
@@ -53,6 +65,7 @@ module NMEAPlus
|
|
53
65
|
end
|
54
66
|
|
55
67
|
# pull out 6b chunks from the payload, then convert those to their more familar characters
|
68
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
56
69
|
# @param start [Integer] The index of the first bit in the payload field
|
57
70
|
# @param length [Integer] The number of bits in the payload field
|
58
71
|
# @return [String]
|
@@ -60,7 +73,8 @@ module NMEAPlus
|
|
60
73
|
_bit_slices(start, length, 6).to_a.map(&:join).map { |x| _6b_ascii(x.to_i(2)) }.join
|
61
74
|
end
|
62
75
|
|
63
|
-
# pull out 8b chunks from the payload, then convert those to their more familar characters
|
76
|
+
# pull out 8b chunks from the payload, then convert those to their more familar characters.
|
77
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
64
78
|
# @param start [Integer] The index of the first bit in the payload field
|
65
79
|
# @param length [Integer] The number of bits in the payload field
|
66
80
|
# @return [String]
|
@@ -68,7 +82,8 @@ module NMEAPlus
|
|
68
82
|
_bit_slices(start, length, 8).to_a.map(&:join).map { |x| x.to_i(2).chr }.join
|
69
83
|
end
|
70
84
|
|
71
|
-
# Slice a part of the payload into binary chunks of a given size
|
85
|
+
# Slice a part of the payload into binary chunks of a given size.
|
86
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
72
87
|
# @param start [Integer] The index of the first bit in the payload field
|
73
88
|
# @param length [Integer] The number of bits in the payload field
|
74
89
|
# @return [Array<String>] Strings representing binary ("01010101" etc) for each slice
|
@@ -76,7 +91,8 @@ module NMEAPlus
|
|
76
91
|
_access(start, length) { |bits| bits.chars.each_slice(chunk_size) }
|
77
92
|
end
|
78
93
|
|
79
|
-
# convert a 6b string but trim off the 0s ('@')
|
94
|
+
# convert a 6b string but trim off the 0s ('@').
|
95
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
80
96
|
# @param start [Integer] The index of the first bit in the payload field
|
81
97
|
# @param length [Integer] The number of bits in the payload field
|
82
98
|
# @return [String]
|
@@ -84,7 +100,8 @@ module NMEAPlus
|
|
84
100
|
_6b_string(start, length).split("@", 2)[0]
|
85
101
|
end
|
86
102
|
|
87
|
-
# directly convert a string to a binary number as you'd read it
|
103
|
+
# directly convert a string to a binary number as you'd read it.
|
104
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
88
105
|
# @param start [Integer] The index of the first bit in the payload field
|
89
106
|
# @param length [Integer] The number of bits in the payload field
|
90
107
|
# @param equiv_nil [Integer] If applicable, the value for this field that would indicate nil
|
@@ -95,7 +112,8 @@ module NMEAPlus
|
|
95
112
|
ret
|
96
113
|
end
|
97
114
|
|
98
|
-
# perform a twos complement operation on part of the payload
|
115
|
+
# perform a twos complement operation on part of the payload.
|
116
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
99
117
|
# @param start [Integer] The index of the first bit in the payload field
|
100
118
|
# @param length [Integer] The number of bits in the payload field
|
101
119
|
# @param equiv_nil [Integer] If applicable, the value for this field that would indicate nil
|
@@ -113,7 +131,8 @@ module NMEAPlus
|
|
113
131
|
end
|
114
132
|
end
|
115
133
|
|
116
|
-
# scale an integer by dividing it by a denominator
|
134
|
+
# scale an integer by dividing it by a denominator.
|
135
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
117
136
|
# @param start [Integer] The index of the first bit in the payload field
|
118
137
|
# @param length [Integer] The number of bits in the payload field
|
119
138
|
# @param denominator [Integer] The divisor to use in scaling down the result
|
@@ -125,7 +144,8 @@ module NMEAPlus
|
|
125
144
|
ret.to_f / denominator
|
126
145
|
end
|
127
146
|
|
128
|
-
# scale an unsigned integer by dividing it by a denominator
|
147
|
+
# scale an unsigned integer by dividing it by a denominator.
|
148
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
129
149
|
# @param start [Integer] The index of the first bit in the payload field
|
130
150
|
# @param length [Integer] The number of bits in the payload field
|
131
151
|
# @param denominator [Integer] The divisor to use in scaling down the result
|
@@ -137,7 +157,8 @@ module NMEAPlus
|
|
137
157
|
ret.to_f / denominator
|
138
158
|
end
|
139
159
|
|
140
|
-
# scale an integer by dividing it by a denominator
|
160
|
+
# scale an integer by dividing it by a denominator.
|
161
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
141
162
|
# @param start [Integer] The index of the first bit in the payload field
|
142
163
|
# @param length [Integer] The number of bits in the payload field
|
143
164
|
# @param denominator [Integer] The divisor to use in scaling down the result
|
@@ -150,7 +171,8 @@ module NMEAPlus
|
|
150
171
|
ret + shift
|
151
172
|
end
|
152
173
|
|
153
|
-
# scale an unsigned integer by dividing it by a denominator
|
174
|
+
# scale an unsigned integer by dividing it by a denominator.
|
175
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
154
176
|
# @param start [Integer] The index of the first bit in the payload field
|
155
177
|
# @param length [Integer] The number of bits in the payload field
|
156
178
|
# @param denominator [Integer] The divisor to use in scaling down the result
|
@@ -163,7 +185,8 @@ module NMEAPlus
|
|
163
185
|
ret + shift
|
164
186
|
end
|
165
187
|
|
166
|
-
# Get the value of a bit in the payload
|
188
|
+
# Get the value of a bit in the payload.
|
189
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
167
190
|
# @param start [Integer] The index of the first bit in the payload field
|
168
191
|
# @param _ [Integer] Doesn't matter. Here so signatures match; we hard-code 1 because it's 1 bit.
|
169
192
|
# @return [bool]
|
@@ -171,7 +194,17 @@ module NMEAPlus
|
|
171
194
|
_access(start, 1) { |bits| bits.to_i == 1 }
|
172
195
|
end
|
173
196
|
|
174
|
-
#
|
197
|
+
# Get the flipped value of a bit in the payload.
|
198
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
199
|
+
# @param start [Integer] The index of the first bit in the payload field
|
200
|
+
# @param _ [Integer] Doesn't matter. Here so signatures match; we hard-code 1 because it's 1 bit.
|
201
|
+
# @return [bool]
|
202
|
+
def _6b_negated_boolean(start, _)
|
203
|
+
!_6b_boolean(start, 1)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Return a string representing binary digits.
|
207
|
+
# This function is meant to be passed as a formatter to {payload_reader}.
|
175
208
|
# @param start [Integer] The index of the first bit in the payload field
|
176
209
|
# @param length [Integer] The number of bits in the payload field
|
177
210
|
# @return [String] e.g. "0101010101011000"
|
@@ -180,14 +213,17 @@ module NMEAPlus
|
|
180
213
|
end
|
181
214
|
|
182
215
|
# use shorthand for data types as defined in http://catb.org/gpsd/AIVDM.html
|
183
|
-
alias_method :_u,
|
184
|
-
alias_method :_U,
|
185
|
-
alias_method :_i,
|
186
|
-
alias_method :_I,
|
187
|
-
alias_method :_b,
|
188
|
-
alias_method :
|
189
|
-
alias_method :
|
190
|
-
alias_method :
|
216
|
+
alias_method :_u, :_6b_unsigned_integer
|
217
|
+
alias_method :_U, :_6b_unsigned_integer_scaled
|
218
|
+
alias_method :_i, :_6b_integer
|
219
|
+
alias_method :_I, :_6b_integer_scaled
|
220
|
+
alias_method :_b, :_6b_boolean
|
221
|
+
alias_method :_nb, :_6b_negated_boolean
|
222
|
+
alias_method :_e, :_6b_unsigned_integer
|
223
|
+
alias_method :_t, :_6b_string_nullterminated
|
224
|
+
alias_method :_tt, :_6b_string
|
225
|
+
alias_method :_T, :_8b_data_string
|
226
|
+
alias_method :_d, :_2b_data_string
|
191
227
|
alias_method :_UU, :_6b_unsigned_integer_scaled_shifted
|
192
228
|
alias_method :_II, :_6b_integer_scaled_shifted
|
193
229
|
|
@@ -3,87 +3,453 @@ require_relative "payload"
|
|
3
3
|
module NMEAPlus
|
4
4
|
module Message
|
5
5
|
module AIS
|
6
|
-
#
|
6
|
+
# This module contains all the VDM payload types and subtypes.
|
7
|
+
# @see {VDMMsg}
|
7
8
|
module VDMPayload
|
8
|
-
|
9
|
+
|
10
|
+
# The base class for the {NMEAPlus::Message::AIS::VDM#ais AIS payload}, which uses its own encoding for its own subtypes
|
9
11
|
class VDMMsg < NMEAPlus::Message::AIS::VDMPayload::Payload
|
10
12
|
|
11
13
|
payload_reader :message_type, 0, 6, :_u
|
12
14
|
payload_reader :repeat_indicator, 6, 2, :_u
|
13
15
|
payload_reader :source_mmsi, 8, 30, :_u
|
14
16
|
|
17
|
+
# The MMSI category as defined by ITU-R M.585-7
|
18
|
+
# @!parse attr_reader :mmsi_category
|
19
|
+
# @return [Symbol] The symbol for the MMSI category
|
20
|
+
def mmsi_category
|
21
|
+
case source_mmsi.to_s.rjust(9, '0') # formatted as 9 digit string with leading 0s
|
22
|
+
when /[2-7]......../ then :individual_ship
|
23
|
+
when /00...1.../ then :coast_station
|
24
|
+
when /00...2.../ then :harbor_station
|
25
|
+
when /00...3.../ then :pilot_station
|
26
|
+
when /00...4.../ then :ais_repeater_station
|
27
|
+
when /00......./ then :coast_station
|
28
|
+
when /111...1../ then :sar_aircraft_fixed
|
29
|
+
when /111...5../ then :sar_aircraft_helicopter
|
30
|
+
when /1......../ then :sar_aircraft
|
31
|
+
when /8......../ then :handheld
|
32
|
+
when /98......./ then :auxiliary_craft
|
33
|
+
when /970....../ then :sar_transmitter
|
34
|
+
when /972....../ then :man_overboard
|
35
|
+
when /974....../ then :epirb
|
36
|
+
when /99...1.../ then :aton_physical
|
37
|
+
when /99...6.../ then :aton_virtual
|
38
|
+
when /99......./ then :aton
|
39
|
+
else
|
40
|
+
:unknown_mmsi_category
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# The MMSI Maritime Identification Digits (MID)
|
45
|
+
# @!parse attr_reader :mid
|
46
|
+
# @return [Integer] the MID
|
47
|
+
def mid
|
48
|
+
range = case mmsi_category
|
49
|
+
when :individual_ship then 0..2
|
50
|
+
when :coast_station, :harbor_station, :pilot_station, :ais_repeater_station then 2..4
|
51
|
+
when :sar_aircraft, :sar_aircraft_fixed, :sar_aircraft_helicopter then 3..5
|
52
|
+
when :aton_physical, :aton_virtual, :aton then 2..4
|
53
|
+
when :auxiliary_craft then 2..4
|
54
|
+
when :handheld then 1..3
|
55
|
+
when :sar_transmitter, :man_overboard, :epirb then 3..5
|
56
|
+
end
|
57
|
+
return nil if range.nil?
|
58
|
+
source_mmsi.to_s.rjust(9, '0')[range].to_i
|
59
|
+
end
|
60
|
+
|
61
|
+
# The ISO 3166-1 indicated by the MMSI Maritime Identification Digits (MID)
|
62
|
+
# @!parse attr_reader :mid_country
|
63
|
+
# @return [Integer] the MID
|
64
|
+
def mid_country
|
65
|
+
# https://github.com/S73417H/MIDs
|
66
|
+
# https://github.com/alexrabarts/iso_country_codes
|
67
|
+
# JSON.parse(IO.read("mids.json")).each {|k, v| puts "when #{k} then #{IsoCountryCodes.find(v[1]).numeric.to_i}" }
|
68
|
+
case mid
|
69
|
+
when 201 then 8
|
70
|
+
when 202 then 20
|
71
|
+
when 203 then 40
|
72
|
+
when 204 then 620
|
73
|
+
when 205 then 56
|
74
|
+
when 206 then 112
|
75
|
+
when 207 then 100
|
76
|
+
when 208 then 336
|
77
|
+
when 209 then 196
|
78
|
+
when 210 then 196
|
79
|
+
when 211 then 276
|
80
|
+
when 212 then 196
|
81
|
+
when 213 then 268
|
82
|
+
when 214 then 498
|
83
|
+
when 215 then 470
|
84
|
+
when 216 then 51
|
85
|
+
when 218 then 276
|
86
|
+
when 219 then 208
|
87
|
+
when 220 then 208
|
88
|
+
when 224 then 724
|
89
|
+
when 225 then 724
|
90
|
+
when 226 then 250
|
91
|
+
when 227 then 250
|
92
|
+
when 228 then 250
|
93
|
+
when 229 then 470
|
94
|
+
when 230 then 246
|
95
|
+
when 231 then 234
|
96
|
+
when 232 then 826
|
97
|
+
when 233 then 826
|
98
|
+
when 234 then 826
|
99
|
+
when 235 then 826
|
100
|
+
when 236 then 292
|
101
|
+
when 237 then 300
|
102
|
+
when 238 then 191
|
103
|
+
when 239 then 300
|
104
|
+
when 240 then 300
|
105
|
+
when 241 then 300
|
106
|
+
when 242 then 504
|
107
|
+
when 243 then 348
|
108
|
+
when 244 then 528
|
109
|
+
when 245 then 528
|
110
|
+
when 246 then 528
|
111
|
+
when 247 then 380
|
112
|
+
when 248 then 470
|
113
|
+
when 250 then 372
|
114
|
+
when 251 then 352
|
115
|
+
when 252 then 438
|
116
|
+
when 253 then 442
|
117
|
+
when 254 then 492
|
118
|
+
when 255 then 620
|
119
|
+
when 256 then 470
|
120
|
+
when 257 then 578
|
121
|
+
when 258 then 578
|
122
|
+
when 259 then 578
|
123
|
+
when 261 then 616
|
124
|
+
when 262 then 499
|
125
|
+
when 263 then 620
|
126
|
+
when 264 then 642
|
127
|
+
when 265 then 752
|
128
|
+
when 266 then 752
|
129
|
+
when 267 then 703
|
130
|
+
when 268 then 674
|
131
|
+
when 269 then 756
|
132
|
+
when 270 then 203
|
133
|
+
when 271 then 792
|
134
|
+
when 272 then 804
|
135
|
+
when 273 then 643
|
136
|
+
when 274 then 807
|
137
|
+
when 275 then 428
|
138
|
+
when 276 then 233
|
139
|
+
when 277 then 440
|
140
|
+
when 278 then 705
|
141
|
+
when 279 then 688
|
142
|
+
when 301 then 660
|
143
|
+
when 303 then 840
|
144
|
+
when 304 then 28
|
145
|
+
when 305 then 28
|
146
|
+
when 306 then 531
|
147
|
+
when 307 then 533
|
148
|
+
when 308 then 44
|
149
|
+
when 309 then 44
|
150
|
+
when 310 then 60
|
151
|
+
when 311 then 60
|
152
|
+
when 312 then 84
|
153
|
+
when 314 then 52
|
154
|
+
when 316 then 124
|
155
|
+
when 319 then 136
|
156
|
+
when 321 then 188
|
157
|
+
when 323 then 192
|
158
|
+
when 325 then 212
|
159
|
+
when 327 then 214
|
160
|
+
when 329 then 312
|
161
|
+
when 330 then 308
|
162
|
+
when 331 then 304
|
163
|
+
when 332 then 320
|
164
|
+
when 335 then 340
|
165
|
+
when 336 then 332
|
166
|
+
when 338 then 840
|
167
|
+
when 339 then 388
|
168
|
+
when 341 then 659
|
169
|
+
when 343 then 662
|
170
|
+
when 345 then 484
|
171
|
+
when 347 then 474
|
172
|
+
when 348 then 500
|
173
|
+
when 350 then 558
|
174
|
+
when 351 then 591
|
175
|
+
when 352 then 591
|
176
|
+
when 353 then 591
|
177
|
+
when 354 then 591
|
178
|
+
when 358 then 630
|
179
|
+
when 359 then 222
|
180
|
+
when 361 then 666
|
181
|
+
when 362 then 780
|
182
|
+
when 364 then 796
|
183
|
+
when 366 then 840
|
184
|
+
when 367 then 840
|
185
|
+
when 368 then 840
|
186
|
+
when 369 then 840
|
187
|
+
when 370 then 591
|
188
|
+
when 371 then 591
|
189
|
+
when 372 then 591
|
190
|
+
when 373 then 591
|
191
|
+
when 375 then 670
|
192
|
+
when 376 then 670
|
193
|
+
when 377 then 670
|
194
|
+
when 378 then 92
|
195
|
+
when 379 then 850
|
196
|
+
when 401 then 4
|
197
|
+
when 403 then 682
|
198
|
+
when 405 then 50
|
199
|
+
when 408 then 48
|
200
|
+
when 410 then 64
|
201
|
+
when 412 then 156
|
202
|
+
when 413 then 156
|
203
|
+
when 414 then 156
|
204
|
+
when 416 then 158
|
205
|
+
when 417 then 144
|
206
|
+
when 419 then 356
|
207
|
+
when 422 then 364
|
208
|
+
when 423 then 31
|
209
|
+
when 425 then 368
|
210
|
+
when 428 then 376
|
211
|
+
when 431 then 392
|
212
|
+
when 432 then 392
|
213
|
+
when 434 then 795
|
214
|
+
when 436 then 398
|
215
|
+
when 437 then 860
|
216
|
+
when 438 then 400
|
217
|
+
when 440 then 410
|
218
|
+
when 441 then 410
|
219
|
+
when 443 then 275
|
220
|
+
when 445 then 408
|
221
|
+
when 447 then 414
|
222
|
+
when 450 then 422
|
223
|
+
when 451 then 417
|
224
|
+
when 453 then 446
|
225
|
+
when 455 then 462
|
226
|
+
when 457 then 496
|
227
|
+
when 459 then 524
|
228
|
+
when 461 then 512
|
229
|
+
when 463 then 586
|
230
|
+
when 466 then 634
|
231
|
+
when 468 then 760
|
232
|
+
when 470 then 784
|
233
|
+
when 472 then 762
|
234
|
+
when 473 then 887
|
235
|
+
when 475 then 887
|
236
|
+
when 477 then 344
|
237
|
+
when 478 then 70
|
238
|
+
when 501 then 250
|
239
|
+
when 503 then 36
|
240
|
+
when 506 then 104
|
241
|
+
when 508 then 96
|
242
|
+
when 510 then 583
|
243
|
+
when 511 then 585
|
244
|
+
when 512 then 554
|
245
|
+
when 514 then 116
|
246
|
+
when 515 then 116
|
247
|
+
when 516 then 162
|
248
|
+
when 518 then 184
|
249
|
+
when 520 then 242
|
250
|
+
when 523 then 166
|
251
|
+
when 525 then 360
|
252
|
+
when 529 then 296
|
253
|
+
when 531 then 418
|
254
|
+
when 533 then 458
|
255
|
+
when 536 then 580
|
256
|
+
when 538 then 584
|
257
|
+
when 540 then 540
|
258
|
+
when 542 then 570
|
259
|
+
when 544 then 520
|
260
|
+
when 546 then 258
|
261
|
+
when 548 then 608
|
262
|
+
when 553 then 598
|
263
|
+
when 555 then 612
|
264
|
+
when 557 then 90
|
265
|
+
when 559 then 16
|
266
|
+
when 561 then 882
|
267
|
+
when 563 then 702
|
268
|
+
when 564 then 702
|
269
|
+
when 565 then 702
|
270
|
+
when 566 then 702
|
271
|
+
when 567 then 764
|
272
|
+
when 570 then 776
|
273
|
+
when 572 then 798
|
274
|
+
when 574 then 704
|
275
|
+
when 576 then 548
|
276
|
+
when 577 then 548
|
277
|
+
when 578 then 876
|
278
|
+
when 601 then 710
|
279
|
+
when 603 then 24
|
280
|
+
when 605 then 12
|
281
|
+
when 607 then 250
|
282
|
+
when 608 then 826
|
283
|
+
when 609 then 108
|
284
|
+
when 610 then 204
|
285
|
+
when 611 then 72
|
286
|
+
when 621 then 262
|
287
|
+
when 613 then 120
|
288
|
+
when 615 then 178
|
289
|
+
when 616 then 174
|
290
|
+
when 617 then 132
|
291
|
+
when 618 then 250
|
292
|
+
when 619 then 384
|
293
|
+
when 620 then 174
|
294
|
+
when 622 then 818
|
295
|
+
when 624 then 231
|
296
|
+
when 625 then 232
|
297
|
+
when 626 then 266
|
298
|
+
when 627 then 288
|
299
|
+
when 629 then 270
|
300
|
+
when 630 then 624
|
301
|
+
when 631 then 226
|
302
|
+
when 632 then 324
|
303
|
+
when 633 then 854
|
304
|
+
when 634 then 404
|
305
|
+
when 635 then 250
|
306
|
+
when 636 then 430
|
307
|
+
when 637 then 430
|
308
|
+
when 638 then 728
|
309
|
+
when 642 then 434
|
310
|
+
when 644 then 426
|
311
|
+
when 645 then 480
|
312
|
+
when 647 then 450
|
313
|
+
when 649 then 466
|
314
|
+
when 650 then 508
|
315
|
+
when 654 then 478
|
316
|
+
when 655 then 454
|
317
|
+
when 656 then 566
|
318
|
+
when 659 then 516
|
319
|
+
when 660 then 638
|
320
|
+
when 661 then 646
|
321
|
+
when 662 then 729
|
322
|
+
when 663 then 686
|
323
|
+
when 664 then 690
|
324
|
+
when 665 then 654
|
325
|
+
when 666 then 706
|
326
|
+
when 667 then 694
|
327
|
+
when 668 then 678
|
328
|
+
when 669 then 748
|
329
|
+
when 670 then 148
|
330
|
+
when 671 then 768
|
331
|
+
when 672 then 788
|
332
|
+
when 674 then 834
|
333
|
+
when 675 then 800
|
334
|
+
when 676 then 180
|
335
|
+
when 677 then 834
|
336
|
+
when 678 then 894
|
337
|
+
when 679 then 716
|
338
|
+
when 701 then 32
|
339
|
+
when 710 then 76
|
340
|
+
when 720 then 68
|
341
|
+
when 725 then 152
|
342
|
+
when 730 then 170
|
343
|
+
when 735 then 218
|
344
|
+
when 740 then 238
|
345
|
+
when 745 then 254
|
346
|
+
when 750 then 328
|
347
|
+
when 755 then 600
|
348
|
+
when 760 then 604
|
349
|
+
when 765 then 740
|
350
|
+
when 770 then 858
|
351
|
+
when 775 then 862
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# The MMSI category as defined by ITU-R M.585-7
|
356
|
+
# @!parse attr_reader :mmsi_category_description
|
357
|
+
# @return [String] the human-readable description the MMSI category
|
358
|
+
def mmsi_category_description
|
359
|
+
case mmsi_category
|
360
|
+
when :individual_ship then "Individual ship"
|
361
|
+
when :coast_station then "Coast station"
|
362
|
+
when :harbor_station then "Harbor station"
|
363
|
+
when :pilot_station then "Pilot station"
|
364
|
+
when :ais_repeater_station then "AIS repeater station"
|
365
|
+
when :sar_aircraft then "SAR aircraft"
|
366
|
+
when :sar_aircraft_fixed then "SAR fixed-wing aircraft"
|
367
|
+
when :sar_aircraft_helicopter then "SAR helicopter"
|
368
|
+
when :aton_physical then "Physical AIS AtoN"
|
369
|
+
when :aton_virtual then "Virtual AIS AtoN"
|
370
|
+
when :aton then "AIS Aid to Navigation"
|
371
|
+
when :auxiliary_craft then "Auxiliary craft"
|
372
|
+
when :handheld then "Handheld transceiver"
|
373
|
+
when :sar_transmitter then "AIS-SART"
|
374
|
+
when :man_overboard then "MOB (Man Overboard)"
|
375
|
+
when :epirb then "EPIRB"
|
376
|
+
else
|
377
|
+
mmsi_category.to_s
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
15
381
|
# The ship cargo type description lookup table
|
16
382
|
# @param code [Integer] The cargo type id
|
17
383
|
# @return [String] Cargo type description
|
18
384
|
def get_ship_cargo_type_description(code)
|
19
385
|
case code
|
20
|
-
when 0 then
|
21
|
-
when 1...19 then
|
22
|
-
when 20 then
|
23
|
-
when 21 then
|
24
|
-
when 22 then
|
25
|
-
when 23 then
|
26
|
-
when 24 then
|
27
|
-
when 25...29 then
|
28
|
-
when 30 then
|
29
|
-
when 31 then
|
30
|
-
when 32 then
|
31
|
-
when 33 then
|
32
|
-
when 34 then
|
33
|
-
when 35 then
|
34
|
-
when 36 then
|
35
|
-
when 37 then
|
36
|
-
when 38, 39 then
|
37
|
-
when 40 then
|
38
|
-
when 41 then
|
39
|
-
when 42 then
|
40
|
-
when 43 then
|
41
|
-
when 44 then
|
42
|
-
when 45...48 then
|
43
|
-
when 49 then
|
44
|
-
when 50 then
|
45
|
-
when 51 then
|
46
|
-
when 52 then
|
47
|
-
when 53 then
|
48
|
-
when 54 then
|
49
|
-
when 55 then
|
50
|
-
when 56, 57 then
|
51
|
-
when 58 then
|
52
|
-
when 59 then
|
53
|
-
when 60 then
|
54
|
-
when 61 then
|
55
|
-
when 62 then
|
56
|
-
when 63 then
|
57
|
-
when 64 then
|
58
|
-
when 65..68 then
|
59
|
-
when 69 then
|
60
|
-
when 70 then
|
61
|
-
when 71 then
|
62
|
-
when 72 then
|
63
|
-
when 73 then
|
64
|
-
when 74 then
|
65
|
-
when 75..78 then
|
66
|
-
when 79 then
|
67
|
-
when 80 then
|
68
|
-
when 81 then
|
69
|
-
when 82 then
|
70
|
-
when 83 then
|
71
|
-
when 84 then
|
72
|
-
when 85.88 then
|
73
|
-
when 89 then
|
74
|
-
when 90 then
|
75
|
-
when 91 then
|
76
|
-
when 92 then
|
77
|
-
when 93 then
|
78
|
-
when 94 then
|
79
|
-
when 95..98 then
|
80
|
-
when 99 then
|
386
|
+
when 0 then nil
|
387
|
+
when 1...19 then "(future use)"
|
388
|
+
when 20 then "WIG (any)"
|
389
|
+
when 21 then "WIG Hazardous category A"
|
390
|
+
when 22 then "WIG Hazardous category B"
|
391
|
+
when 23 then "WIG Hazardous category C"
|
392
|
+
when 24 then "WIG Hazardous category D"
|
393
|
+
when 25...29 then "WIG (future use)"
|
394
|
+
when 30 then "Fishing"
|
395
|
+
when 31 then "Towing"
|
396
|
+
when 32 then "Towing (large)"
|
397
|
+
when 33 then "Dredging/underwater ops"
|
398
|
+
when 34 then "Diving ops"
|
399
|
+
when 35 then "Military ops"
|
400
|
+
when 36 then "Sailing"
|
401
|
+
when 37 then "Pleasure craft"
|
402
|
+
when 38, 39 then "Reserved"
|
403
|
+
when 40 then "High Speed Craft"
|
404
|
+
when 41 then "HSC Hazardous category A"
|
405
|
+
when 42 then "HSC Hazardous category B"
|
406
|
+
when 43 then "HSC Hazardous category C"
|
407
|
+
when 44 then "HSC Hazardous category D"
|
408
|
+
when 45...48 then "HSC (reserved)"
|
409
|
+
when 49 then "HSC (no additional information)"
|
410
|
+
when 50 then "Pilot Vessel"
|
411
|
+
when 51 then "Search and Rescue Vessel"
|
412
|
+
when 52 then "Tug"
|
413
|
+
when 53 then "Port Tender"
|
414
|
+
when 54 then "Anti-pollution equipment"
|
415
|
+
when 55 then "Law Enforcement"
|
416
|
+
when 56, 57 then "Spare - Local Vessel"
|
417
|
+
when 58 then "Medical Transport"
|
418
|
+
when 59 then "Noncombatant ship according to RR Resolution No. 18"
|
419
|
+
when 60 then "Passenger"
|
420
|
+
when 61 then "Passenger, Hazardous category A"
|
421
|
+
when 62 then "Passenger, Hazardous category B"
|
422
|
+
when 63 then "Passenger, Hazardous category C"
|
423
|
+
when 64 then "Passenger, Hazardous category D"
|
424
|
+
when 65..68 then "Passenger, Reserved for future use"
|
425
|
+
when 69 then "Passenger, No additional information"
|
426
|
+
when 70 then "Cargo"
|
427
|
+
when 71 then "Cargo, Hazardous category A"
|
428
|
+
when 72 then "Cargo, Hazardous category B"
|
429
|
+
when 73 then "Cargo, Hazardous category C"
|
430
|
+
when 74 then "Cargo, Hazardous category D"
|
431
|
+
when 75..78 then "Cargo, Reserved for future use"
|
432
|
+
when 79 then "Cargo, No additional information"
|
433
|
+
when 80 then "Tanker"
|
434
|
+
when 81 then "Tanker, Hazardous category A"
|
435
|
+
when 82 then "Tanker, Hazardous category B"
|
436
|
+
when 83 then "Tanker, Hazardous category C"
|
437
|
+
when 84 then "Tanker, Hazardous category D"
|
438
|
+
when 85.88 then "Tanker, Reserved for future use"
|
439
|
+
when 89 then "Tanker, No additional information"
|
440
|
+
when 90 then "Other Type"
|
441
|
+
when 91 then "Other Type, Hazardous category A"
|
442
|
+
when 92 then "Other Type, Hazardous category B"
|
443
|
+
when 93 then "Other Type, Hazardous category C"
|
444
|
+
when 94 then "Other Type, Hazardous category D"
|
445
|
+
when 95..98 then "Other Type, Reserved for future use"
|
446
|
+
when 99 then "Other Type, no additional information"
|
81
447
|
end
|
82
448
|
end
|
83
449
|
|
84
450
|
# An MMSI is associated with an auxiliary craft when it is of the form 98XXXYYYY
|
85
451
|
def auxiliary_craft?
|
86
|
-
|
452
|
+
mmsi_category == :auxiliary_craft
|
87
453
|
end
|
88
454
|
|
89
455
|
# @param code [Integer] The navigational status id
|
@@ -91,23 +457,25 @@ module NMEAPlus
|
|
91
457
|
def get_navigational_status_description(code)
|
92
458
|
return nil if code.nil?
|
93
459
|
case code
|
94
|
-
when 0 then
|
95
|
-
when 1 then
|
96
|
-
when 2 then
|
97
|
-
when 3 then
|
98
|
-
when 4 then
|
99
|
-
when 5 then
|
100
|
-
when 6 then
|
101
|
-
when 7 then
|
102
|
-
when 8 then
|
103
|
-
when
|
460
|
+
when 0 then "Under way using engine"
|
461
|
+
when 1 then "At anchor"
|
462
|
+
when 2 then "Not under command"
|
463
|
+
when 3 then "Restricted manoeuverability"
|
464
|
+
when 4 then "Constrained by her draught"
|
465
|
+
when 5 then "Moored"
|
466
|
+
when 6 then "Aground"
|
467
|
+
when 7 then "Engaged in Fishing"
|
468
|
+
when 8 then "Under way sailing"
|
469
|
+
when 9...13 then "Reserved for future use"
|
470
|
+
when 14 then "AIS-SART active"
|
471
|
+
else
|
472
|
+
"Not defined"
|
104
473
|
end
|
105
|
-
"Reserved for future use"
|
106
474
|
end
|
107
475
|
|
108
476
|
end
|
109
477
|
|
110
|
-
# We haven't defined all the AIS payload types, so this is a catch-all
|
478
|
+
# We haven't defined all the {NMEAPlus::Message::AIS::VDM#ais AIS payload} types, so this is a catch-all
|
111
479
|
class VDMMsgUndefined < VDMMsg; end
|
112
480
|
|
113
481
|
end
|