nmea_plus 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -9
  3. data/lib/nmea_plus/ais_message_factory.rb +3 -1
  4. data/lib/nmea_plus/generated_parser/tokenizer.rb +1 -1
  5. data/lib/nmea_plus/message/ais/base_ais.rb +9 -2
  6. data/lib/nmea_plus/message/ais/vdm.rb +8 -2
  7. data/lib/nmea_plus/message/ais/vdm_payload/payload.rb +59 -23
  8. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg.rb +444 -76
  9. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg1.rb +6 -5
  10. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg12.rb +5 -2
  11. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg14.rb +1 -1
  12. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg18.rb +5 -3
  13. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg20.rb +2 -1
  14. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg21.rb +2 -1
  15. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg24.rb +2 -1
  16. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg27.rb +2 -1
  17. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg4.rb +15 -2
  18. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg5.rb +3 -2
  19. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6.rb +55 -0
  20. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1022f61.rb +122 -0
  21. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d235f10.rb +54 -0
  22. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg7.rb +36 -0
  23. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg8.rb +2 -9
  24. data/lib/nmea_plus/message/ais/vdm_payload/vdm_msg9.rb +5 -5
  25. data/lib/nmea_plus/message/base.rb +27 -14
  26. data/lib/nmea_plus/message/nmea/base_nmea.rb +13 -7
  27. data/lib/nmea_plus/message/nmea/bwr.rb +2 -2
  28. data/lib/nmea_plus/message/nmea/dtm.rb +2 -2
  29. data/lib/nmea_plus/message/nmea/gga.rb +2 -2
  30. data/lib/nmea_plus/message/nmea/gll.rb +2 -2
  31. data/lib/nmea_plus/message/nmea/gns.rb +2 -2
  32. data/lib/nmea_plus/message/nmea/gxa.rb +2 -2
  33. data/lib/nmea_plus/message/nmea/hdg.rb +2 -2
  34. data/lib/nmea_plus/message/nmea/rma.rb +3 -3
  35. data/lib/nmea_plus/message/nmea/rmb.rb +2 -2
  36. data/lib/nmea_plus/message/nmea/rmc.rb +3 -3
  37. data/lib/nmea_plus/message/nmea/trf.rb +2 -2
  38. data/lib/nmea_plus/message/nmea/wpl.rb +2 -2
  39. data/lib/nmea_plus/nmea_message_factory.rb +3 -1
  40. data/lib/nmea_plus/version.rb +1 -1
  41. metadata +9 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad7de05d0b6299139bf89734517185b1056c2055
4
- data.tar.gz: d77eced056aac4fb30998039e41fc9bcdc02e5a5
3
+ metadata.gz: 8b9332e5d45ba59ff6572c20801c15205fcfc674
4
+ data.tar.gz: ddc8d5117a0b4c4774eb5ffe552b07a1ce2873ed
5
5
  SHA512:
6
- metadata.gz: 337635824791c01b604b2e8027db96711375ad5fe521568953d3c5daac1e9df5605b79434b54ce90b474ff683fd5c532a18ac969585f9cf6a3dc3fc1ae2e42be
7
- data.tar.gz: 91dd8c299619df14559f74120e56141d790d413557cd2d8be038f2b0f4df55b21fb42e78561d865b0d4b3a04c13ddd76278fc2cfb535399a33084ce72ee3f4ab
6
+ metadata.gz: 4163c6ee8e9d1ba684cd30f18a94e4d8b42b11c5401a23c57ff0d82b27ce18b9b0ce2a21090e95f9fe96316bda9034f4224ae1b0d12176e75b90309f4369e09b
7
+ data.tar.gz: 538f7e47902a954c116d1c7d630c51b32a821b5d2cdc1b95e54ad9148ddb3e4b6ef2546b550bda734680e6f0da806d0bf3a87edc947d67ebdc47f1b2ce2d15d5
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # NMEA Ruby Gem (nmea_plus)
1
+ # NMEA (GPS) and AIS Parser / Decoder for Ruby (nmea_plus)
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://www.rubydoc.info/gems/nmea_plus/1.0.8)
5
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](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
- ## Design documents
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
- ### AIS
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 AIVDM message types are supported:
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 # This file is in .rex format, so no indenting. And yard docs are impossible.
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
- # NMEA (AIS) message types are 5 characters, the first 2 of which are the talker ID
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
- # NMEA (AIS) message types are 5 characters (or so), the last of which are the message type
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 class and instantiate it
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
- # make our own shortcut syntax for payload attributes
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. If there aren't bytes, there, return nil
44
- # else execute a block
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
- # Return a string representing binary
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, :_6b_unsigned_integer
184
- alias_method :_U, :_6b_unsigned_integer_scaled
185
- alias_method :_i, :_6b_integer
186
- alias_method :_I, :_6b_integer_scaled
187
- alias_method :_b, :_6b_boolean
188
- alias_method :_e, :_6b_unsigned_integer
189
- alias_method :_t, :_6b_string_nullterminated
190
- alias_method :_d, :_2b_data_string
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
- # There are many VDM payload types, and this is their container. See {VDMMsg}.
6
+ # This module contains all the VDM payload types and subtypes.
7
+ # @see {VDMMsg}
7
8
  module VDMPayload
8
- # The base class for the AIS payload (of {NMEAPlus::Message::AIS::VDM}), which uses its own encoding for its own subtypes
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 return nil
21
- when 1...19 then return "(future use)"
22
- when 20 then return "WIG (any)"
23
- when 21 then return "WIG Hazardous category A"
24
- when 22 then return "WIG Hazardous category B"
25
- when 23 then return "WIG Hazardous category C"
26
- when 24 then return "WIG Hazardous category D"
27
- when 25...29 then return "WIG (future use)"
28
- when 30 then return "Fishing"
29
- when 31 then return "Towing"
30
- when 32 then return "Towing (large)"
31
- when 33 then return "Dredging/underwater ops"
32
- when 34 then return "Diving ops"
33
- when 35 then return "Military ops"
34
- when 36 then return "Sailing"
35
- when 37 then return "Pleasure craft"
36
- when 38, 39 then return "Reserved"
37
- when 40 then return "High Speed Craft"
38
- when 41 then return "HSC Hazardous category A"
39
- when 42 then return "HSC Hazardous category B"
40
- when 43 then return "HSC Hazardous category C"
41
- when 44 then return "HSC Hazardous category D"
42
- when 45...48 then return "HSC (reserved)"
43
- when 49 then return "HSC (no additional information)"
44
- when 50 then return "Pilot Vessel"
45
- when 51 then return "Search and Rescue Vessel"
46
- when 52 then return "Tug"
47
- when 53 then return "Port Tender"
48
- when 54 then return "Anti-pollution equipment"
49
- when 55 then return "Law Enforcement"
50
- when 56, 57 then return "Spare - Local Vessel"
51
- when 58 then return "Medical Transport"
52
- when 59 then return "Noncombatant ship according to RR Resolution No. 18"
53
- when 60 then return "Passenger"
54
- when 61 then return "Passenger, Hazardous category A"
55
- when 62 then return "Passenger, Hazardous category B"
56
- when 63 then return "Passenger, Hazardous category C"
57
- when 64 then return "Passenger, Hazardous category D"
58
- when 65..68 then return "Passenger, Reserved for future use"
59
- when 69 then return "Passenger, No additional information"
60
- when 70 then return "Cargo"
61
- when 71 then return "Cargo, Hazardous category A"
62
- when 72 then return "Cargo, Hazardous category B"
63
- when 73 then return "Cargo, Hazardous category C"
64
- when 74 then return "Cargo, Hazardous category D"
65
- when 75..78 then return "Cargo, Reserved for future use"
66
- when 79 then return "Cargo, No additional information"
67
- when 80 then return "Tanker"
68
- when 81 then return "Tanker, Hazardous category A"
69
- when 82 then return "Tanker, Hazardous category B"
70
- when 83 then return "Tanker, Hazardous category C"
71
- when 84 then return "Tanker, Hazardous category D"
72
- when 85.88 then return "Tanker, Reserved for future use"
73
- when 89 then return "Tanker, No additional information"
74
- when 90 then return "Other Type"
75
- when 91 then return "Other Type, Hazardous category A"
76
- when 92 then return "Other Type, Hazardous category B"
77
- when 93 then return "Other Type, Hazardous category C"
78
- when 94 then return "Other Type, Hazardous category D"
79
- when 95..98 then return "Other Type, Reserved for future use"
80
- when 99 then return "Other Type, no additional information"
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
- 980_000_000 < source_mmsi && source_mmsi < 990_000_000
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 return "Under way using engine"
95
- when 1 then return "At anchor"
96
- when 2 then return "Not under command"
97
- when 3 then return "Restricted manoeuverability"
98
- when 4 then return "Constrained by her draught"
99
- when 5 then return "Moored"
100
- when 6 then return "Aground"
101
- when 7 then return "Engaged in Fishing"
102
- when 8 then return "Under way sailing"
103
- when 14 then return "AIS-SART active"
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