nmea_plus 1.0.10 → 1.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4995804e2eba3842192e6ca02309efe1867b439a
4
- data.tar.gz: ff77b5f6dee8dc838fd7a62c321c0655f4c81033
3
+ metadata.gz: 49d631a6794e0a47ff2daef5fb5b4dac87623a5d
4
+ data.tar.gz: 16636c7450ccb964cedd1a3d76462999af63e967
5
5
  SHA512:
6
- metadata.gz: c0354acd88c7ca3c349d12d6be23e127ec8468e3db846eb99156ce8a15be2b6f461a60d3cd4473542f0ce6303ebdd6f15dcbcc8ac1aa9c0c27f6306843cf88a3
7
- data.tar.gz: fdbdb7dfbbc1164242a9226d0d19583f25180141b554db6681c4573219039a9a7fa0ec4198b1684dea6f8d47b86e9ea90935b2dbcd39a2a6cbfac434bda0f4ad
6
+ metadata.gz: 5250074e41c49831996adbcc4e9f36990257e157c3980d3bb04b48db678e2c5e7c4bd26563c0a5174854f86605c5db5427b5961e697e35882c8d7afc40cd41bb
7
+ data.tar.gz: 47e7032aaddbdb141fd4fd8175affc119ece1bd9d961f0434b8b6ff1ee7e7c47c79036187a5db93c262799218da2e37f66397386b8e342b85eab4c56689d2c2e
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # NMEA (GPS) and AIS Parser / Decoder for Ruby (nmea_plus)
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/nmea_plus.svg)](https://rubygems.org/gems/nmea_plus)
3
+ [![Gem Version](https://badge.fury.io/rb/nmea_plus.png)](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.10)
5
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/nmea_plus/1.0.11)
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
 
@@ -101,13 +101,16 @@ Support for proprietary NMEA messages is also possible. PASHR is included as pr
101
101
  AIS message type definitions were implemented from the unofficial spec found here:
102
102
  http://catb.org/gpsd/AIVDM.html
103
103
 
104
+ And some binary subtypes from the ITU spec found here:
105
+ https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-4-201004-S!!PDF-E.pdf
106
+
104
107
  The AIS payload can be found in the payload field of a `VDM` message (aka `!AIVDM`, `!ABVDM`, `!SAVDM`). Currently, the following AIS message types are supported:
105
108
 
106
109
  > 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 18, 19, 20, 21, 24, 27
107
110
 
108
- > Type 6 subtypes for DAC/FID: 235/10, 1022/61
111
+ > Type 6 subtypes for DAC/FID: 1/0, 1/2, 1/3, 1/4, 1/5, 235/10, 1022/61
109
112
 
110
- > Type 8 subtypes for DAC/FID: 1/22, 1/31, 366/56, 366/57
113
+ > Type 8 subtypes for DAC/FID: 1/0, 1/22, 1/31, 366/56, 366/57
111
114
 
112
115
 
113
116
  ## Disclaimer
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
  module NMEAPlus
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 `!`
9
+ class Decoder < Parser # The source file is in .rex format -- indentation and most yard documentation is impossible. This 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 `!`. In pratice, you should be using {NMEAPlus::SourceDecoder} (which wraps this class) to parse messages from an IO object; this class can only parse individual strings.
10
10
  require 'strscan'
11
11
 
12
12
  class ScanError < StandardError ; end
@@ -66,8 +66,9 @@ module NMEAPlus
66
66
  ptr = self
67
67
  ret = ""
68
68
  loop do
69
+ break if ptr.raw_ais_payload.nil? # guard against rare instances of message corruption
69
70
  ret << ptr.raw_ais_payload
70
- break if ptr.next_part.nil?
71
+ break if ptr.next_part.nil? # stop when we run out of messages in the chain
71
72
  ptr = ptr.next_part
72
73
  end
73
74
  ret
@@ -105,11 +106,7 @@ module NMEAPlus
105
106
  # @return [String] a binary encoded string
106
107
  def _dearmor6b(c, len = 6)
107
108
  val = c.ord
108
- if val >= 96
109
- ret = val - 56
110
- else
111
- ret = val - 48
112
- end
109
+ ret = val - (val >= 96 ? 56 : 48) # Mapped to 2 separate contiguous blocks of ascii, so choose which
113
110
  ret.to_s(2).rjust(6, "0")[0..(len - 1)]
114
111
  end
115
112
 
@@ -0,0 +1,393 @@
1
+
2
+ module NMEAPlus
3
+ module Message
4
+ module AIS
5
+ module VDMPayload
6
+
7
+ # A container for MMSI (Maritime Mobile Service Identity) information,
8
+ # all of which is indicated from the MMSI integer value itself.
9
+ class MMSIInfo
10
+
11
+ # The MMSI
12
+ # @return [Integer]
13
+ attr_reader :id
14
+
15
+ # @param mmsi [Integer] The MMSI
16
+ def initialize(mmsi)
17
+ @id = mmsi
18
+ end
19
+
20
+ # The MMSI category as defined by ITU-R M.585-7
21
+ # @!parse attr_reader :category
22
+ # @return [Symbol] The symbol for the MMSI category
23
+ def category
24
+ case id.to_s.rjust(9, '0') # formatted as 9 digit string with leading 0s
25
+ when /[2-7]......../ then :individual_ship
26
+ when /00...1.../ then :coast_station
27
+ when /00...2.../ then :harbor_station
28
+ when /00...3.../ then :pilot_station
29
+ when /00...4.../ then :ais_repeater_station
30
+ when /00......./ then :coast_station
31
+ when /111...1../ then :sar_aircraft_fixed
32
+ when /111...5../ then :sar_aircraft_helicopter
33
+ when /1......../ then :sar_aircraft
34
+ when /8......../ then :handheld
35
+ when /98......./ then :auxiliary_craft
36
+ when /970....../ then :sar_transmitter
37
+ when /972....../ then :man_overboard
38
+ when /974....../ then :epirb
39
+ when /99...1.../ then :aton_physical
40
+ when /99...6.../ then :aton_virtual
41
+ when /99......./ then :aton
42
+ else
43
+ :unknown_mmsi_category
44
+ end
45
+ end
46
+
47
+ # The MMSI category as defined by ITU-R M.585-7
48
+ # @!parse attr_reader :category_description
49
+ # @return [String] the human-readable description the MMSI category
50
+ def category_description
51
+ case category
52
+ when :individual_ship then "Individual ship"
53
+ when :coast_station then "Coast station"
54
+ when :harbor_station then "Harbor station"
55
+ when :pilot_station then "Pilot station"
56
+ when :ais_repeater_station then "AIS repeater station"
57
+ when :sar_aircraft then "SAR aircraft"
58
+ when :sar_aircraft_fixed then "SAR fixed-wing aircraft"
59
+ when :sar_aircraft_helicopter then "SAR helicopter"
60
+ when :aton_physical then "Physical AIS AtoN"
61
+ when :aton_virtual then "Virtual AIS AtoN"
62
+ when :aton then "AIS Aid to Navigation"
63
+ when :auxiliary_craft then "Auxiliary craft"
64
+ when :handheld then "Handheld transceiver"
65
+ when :sar_transmitter then "AIS-SART"
66
+ when :man_overboard then "MOB (Man Overboard)"
67
+ when :epirb then "EPIRB"
68
+ else
69
+ category.to_s
70
+ end
71
+ end
72
+
73
+ # The MMSI Maritime Identification Digits (MID), indicating country codes as specified by the ITU.
74
+ # http://www.itu.int/online/mms/glad/cga_mids.sh
75
+ # @!parse attr_reader :mid
76
+ # @return [Integer] the MID
77
+ def mid
78
+ range = case category
79
+ when :individual_ship then 0..2
80
+ when :coast_station, :harbor_station, :pilot_station, :ais_repeater_station then 2..4
81
+ when :sar_aircraft, :sar_aircraft_fixed, :sar_aircraft_helicopter then 3..5
82
+ when :aton_physical, :aton_virtual, :aton then 2..4
83
+ when :auxiliary_craft then 2..4
84
+ when :handheld then 1..3
85
+ when :sar_transmitter, :man_overboard, :epirb then 3..5
86
+ end
87
+ return nil if range.nil?
88
+ id.to_s.rjust(9, '0')[range].to_i
89
+ end
90
+
91
+ # The ISO 3166-1 country ID indicated by the MMSI Maritime Identification Digits (MID)
92
+ # @!parse attr_reader :country_id
93
+ # @return [Integer] the MID
94
+ def country_id
95
+ # https://github.com/S73417H/MIDs
96
+ # https://github.com/alexrabarts/iso_country_codes
97
+ # JSON.parse(IO.read("mids.json")).each {|k, v| puts "when #{k} then #{IsoCountryCodes.find(v[1]).numeric.to_i}" }
98
+ case mid
99
+ when 201 then 8
100
+ when 202 then 20
101
+ when 203 then 40
102
+ when 204 then 620
103
+ when 205 then 56
104
+ when 206 then 112
105
+ when 207 then 100
106
+ when 208 then 336
107
+ when 209 then 196
108
+ when 210 then 196
109
+ when 211 then 276
110
+ when 212 then 196
111
+ when 213 then 268
112
+ when 214 then 498
113
+ when 215 then 470
114
+ when 216 then 51
115
+ when 218 then 276
116
+ when 219 then 208
117
+ when 220 then 208
118
+ when 224 then 724
119
+ when 225 then 724
120
+ when 226 then 250
121
+ when 227 then 250
122
+ when 228 then 250
123
+ when 229 then 470
124
+ when 230 then 246
125
+ when 231 then 234
126
+ when 232 then 826
127
+ when 233 then 826
128
+ when 234 then 826
129
+ when 235 then 826
130
+ when 236 then 292
131
+ when 237 then 300
132
+ when 238 then 191
133
+ when 239 then 300
134
+ when 240 then 300
135
+ when 241 then 300
136
+ when 242 then 504
137
+ when 243 then 348
138
+ when 244 then 528
139
+ when 245 then 528
140
+ when 246 then 528
141
+ when 247 then 380
142
+ when 248 then 470
143
+ when 250 then 372
144
+ when 251 then 352
145
+ when 252 then 438
146
+ when 253 then 442
147
+ when 254 then 492
148
+ when 255 then 620
149
+ when 256 then 470
150
+ when 257 then 578
151
+ when 258 then 578
152
+ when 259 then 578
153
+ when 261 then 616
154
+ when 262 then 499
155
+ when 263 then 620
156
+ when 264 then 642
157
+ when 265 then 752
158
+ when 266 then 752
159
+ when 267 then 703
160
+ when 268 then 674
161
+ when 269 then 756
162
+ when 270 then 203
163
+ when 271 then 792
164
+ when 272 then 804
165
+ when 273 then 643
166
+ when 274 then 807
167
+ when 275 then 428
168
+ when 276 then 233
169
+ when 277 then 440
170
+ when 278 then 705
171
+ when 279 then 688
172
+ when 301 then 660
173
+ when 303 then 840
174
+ when 304 then 28
175
+ when 305 then 28
176
+ when 306 then 531
177
+ when 307 then 533
178
+ when 308 then 44
179
+ when 309 then 44
180
+ when 310 then 60
181
+ when 311 then 60
182
+ when 312 then 84
183
+ when 314 then 52
184
+ when 316 then 124
185
+ when 319 then 136
186
+ when 321 then 188
187
+ when 323 then 192
188
+ when 325 then 212
189
+ when 327 then 214
190
+ when 329 then 312
191
+ when 330 then 308
192
+ when 331 then 304
193
+ when 332 then 320
194
+ when 335 then 340
195
+ when 336 then 332
196
+ when 338 then 840
197
+ when 339 then 388
198
+ when 341 then 659
199
+ when 343 then 662
200
+ when 345 then 484
201
+ when 347 then 474
202
+ when 348 then 500
203
+ when 350 then 558
204
+ when 351 then 591
205
+ when 352 then 591
206
+ when 353 then 591
207
+ when 354 then 591
208
+ when 355 then 591
209
+ when 356 then 591
210
+ when 357 then 591
211
+ when 358 then 630
212
+ when 359 then 222
213
+ when 361 then 666
214
+ when 362 then 780
215
+ when 364 then 796
216
+ when 366 then 840
217
+ when 367 then 840
218
+ when 368 then 840
219
+ when 369 then 840
220
+ when 370 then 591
221
+ when 371 then 591
222
+ when 372 then 591
223
+ when 373 then 591
224
+ when 375 then 670
225
+ when 376 then 670
226
+ when 377 then 670
227
+ when 378 then 92
228
+ when 379 then 850
229
+ when 401 then 4
230
+ when 403 then 682
231
+ when 405 then 50
232
+ when 408 then 48
233
+ when 410 then 64
234
+ when 412 then 156
235
+ when 413 then 156
236
+ when 414 then 156
237
+ when 416 then 158
238
+ when 417 then 144
239
+ when 419 then 356
240
+ when 422 then 364
241
+ when 423 then 31
242
+ when 425 then 368
243
+ when 428 then 376
244
+ when 431 then 392
245
+ when 432 then 392
246
+ when 434 then 795
247
+ when 436 then 398
248
+ when 437 then 860
249
+ when 438 then 400
250
+ when 440 then 410
251
+ when 441 then 410
252
+ when 443 then 275
253
+ when 445 then 408
254
+ when 447 then 414
255
+ when 450 then 422
256
+ when 451 then 417
257
+ when 453 then 446
258
+ when 455 then 462
259
+ when 457 then 496
260
+ when 459 then 524
261
+ when 461 then 512
262
+ when 463 then 586
263
+ when 466 then 634
264
+ when 468 then 760
265
+ when 470 then 784
266
+ when 472 then 762
267
+ when 473 then 887
268
+ when 475 then 887
269
+ when 477 then 344
270
+ when 478 then 70
271
+ when 501 then 250
272
+ when 503 then 36
273
+ when 506 then 104
274
+ when 508 then 96
275
+ when 510 then 583
276
+ when 511 then 585
277
+ when 512 then 554
278
+ when 514 then 116
279
+ when 515 then 116
280
+ when 516 then 162
281
+ when 518 then 184
282
+ when 520 then 242
283
+ when 523 then 166
284
+ when 525 then 360
285
+ when 529 then 296
286
+ when 531 then 418
287
+ when 533 then 458
288
+ when 536 then 580
289
+ when 538 then 584
290
+ when 540 then 540
291
+ when 542 then 570
292
+ when 544 then 520
293
+ when 546 then 258
294
+ when 548 then 608
295
+ when 553 then 598
296
+ when 555 then 612
297
+ when 557 then 90
298
+ when 559 then 16
299
+ when 561 then 882
300
+ when 563 then 702
301
+ when 564 then 702
302
+ when 565 then 702
303
+ when 566 then 702
304
+ when 567 then 764
305
+ when 570 then 776
306
+ when 572 then 798
307
+ when 574 then 704
308
+ when 576 then 548
309
+ when 577 then 548
310
+ when 578 then 876
311
+ when 601 then 710
312
+ when 603 then 24
313
+ when 605 then 12
314
+ when 607 then 250
315
+ when 608 then 826
316
+ when 609 then 108
317
+ when 610 then 204
318
+ when 611 then 72
319
+ when 621 then 262
320
+ when 613 then 120
321
+ when 615 then 178
322
+ when 616 then 174
323
+ when 617 then 132
324
+ when 618 then 250
325
+ when 619 then 384
326
+ when 620 then 174
327
+ when 622 then 818
328
+ when 624 then 231
329
+ when 625 then 232
330
+ when 626 then 266
331
+ when 627 then 288
332
+ when 629 then 270
333
+ when 630 then 624
334
+ when 631 then 226
335
+ when 632 then 324
336
+ when 633 then 854
337
+ when 634 then 404
338
+ when 635 then 250
339
+ when 636 then 430
340
+ when 637 then 430
341
+ when 638 then 728
342
+ when 642 then 434
343
+ when 644 then 426
344
+ when 645 then 480
345
+ when 647 then 450
346
+ when 649 then 466
347
+ when 650 then 508
348
+ when 654 then 478
349
+ when 655 then 454
350
+ when 656 then 566
351
+ when 659 then 516
352
+ when 660 then 638
353
+ when 661 then 646
354
+ when 662 then 729
355
+ when 663 then 686
356
+ when 664 then 690
357
+ when 665 then 654
358
+ when 666 then 706
359
+ when 667 then 694
360
+ when 668 then 678
361
+ when 669 then 748
362
+ when 670 then 148
363
+ when 671 then 768
364
+ when 672 then 788
365
+ when 674 then 834
366
+ when 675 then 800
367
+ when 676 then 180
368
+ when 677 then 834
369
+ when 678 then 894
370
+ when 679 then 716
371
+ when 701 then 32
372
+ when 710 then 76
373
+ when 720 then 68
374
+ when 725 then 152
375
+ when 730 then 170
376
+ when 735 then 218
377
+ when 740 then 238
378
+ when 745 then 254
379
+ when 750 then 328
380
+ when 755 then 600
381
+ when 760 then 604
382
+ when 765 then 740
383
+ when 770 then 858
384
+ when 775 then 862
385
+ end
386
+ end
387
+
388
+ end
389
+
390
+ end
391
+ end
392
+ end
393
+ end
@@ -216,19 +216,19 @@ module NMEAPlus
216
216
  end
217
217
 
218
218
  # use shorthand for data types as defined in http://catb.org/gpsd/AIVDM.html
219
- alias_method :_u, :_6b_unsigned_integer
220
- alias_method :_U, :_6b_unsigned_integer_scaled
221
- alias_method :_i, :_6b_integer
222
- alias_method :_I, :_6b_integer_scaled
223
- alias_method :_b, :_6b_boolean
224
- alias_method :_nb, :_6b_negated_boolean
225
- alias_method :_e, :_6b_unsigned_integer
226
- alias_method :_t, :_6b_string_nullterminated
227
- alias_method :_tt, :_6b_string
228
- alias_method :_T, :_8b_data_string
229
- alias_method :_d, :_2b_data_string
230
- alias_method :_UU, :_6b_unsigned_integer_scaled_shifted
231
- alias_method :_II, :_6b_integer_scaled_shifted
219
+ alias _u _6b_unsigned_integer
220
+ alias _U _6b_unsigned_integer_scaled
221
+ alias _i _6b_integer
222
+ alias _I _6b_integer_scaled
223
+ alias _b _6b_boolean
224
+ alias _nb _6b_negated_boolean
225
+ alias _e _6b_unsigned_integer
226
+ alias _t _6b_string_nullterminated
227
+ alias _tt _6b_string
228
+ alias _T _8b_data_string
229
+ alias _d _2b_data_string
230
+ alias _UU _6b_unsigned_integer_scaled_shifted
231
+ alias _II _6b_integer_scaled_shifted
232
232
 
233
233
  end
234
234
  end
@@ -102,14 +102,21 @@ module NMEAPlus
102
102
  payload_reader :bearing4, 65, 10, :_u, 720
103
103
  payload_reader :distance4, 75, 10, :_u
104
104
 
105
+ # Container for bearing / distance
105
106
  class ShapePoint
106
107
  attr_accessor :bearing
107
108
  attr_accessor :distance
108
- attr_accessor :distance_meters
109
+ attr_accessor :scale_factor
110
+
111
+ # @!parse attr_reader :distance_meters
112
+ # @return [Integer] The scaled distance in meters
113
+ def distance_meters
114
+ distance * (10**scale_factor)
115
+ end
109
116
  end
110
117
 
111
118
  # @!parse attr_reader :points
112
- # @return [Array] Array of points
119
+ # @return [Array] Array of {ShapePoint} objects
113
120
  def points
114
121
  ret = []
115
122
 
@@ -119,7 +126,7 @@ module NMEAPlus
119
126
  sp = ShapePoint.new
120
127
  sp.bearing = send("bearing#{i}")
121
128
  sp.distance = d
122
- sp.distance_meters = d * scale_meters
129
+ sp.scale_factor = scale_Factor
123
130
  ret << sp
124
131
  end
125
132
  ret
@@ -1,4 +1,5 @@
1
1
  require_relative "payload"
2
+ require_relative "mmsi_info"
2
3
 
3
4
  module NMEAPlus
4
5
  module Message
@@ -12,368 +13,11 @@ module NMEAPlus
12
13
  payload_reader :repeat_indicator, 6, 2, :_u
13
14
  payload_reader :source_mmsi, 8, 30, :_u
14
15
 
15
- # The MMSI category as defined by ITU-R M.585-7
16
- # @!parse attr_reader :mmsi_category
17
- # @return [Symbol] The symbol for the MMSI category
18
- def mmsi_category
19
- case source_mmsi.to_s.rjust(9, '0') # formatted as 9 digit string with leading 0s
20
- when /[2-7]......../ then :individual_ship
21
- when /00...1.../ then :coast_station
22
- when /00...2.../ then :harbor_station
23
- when /00...3.../ then :pilot_station
24
- when /00...4.../ then :ais_repeater_station
25
- when /00......./ then :coast_station
26
- when /111...1../ then :sar_aircraft_fixed
27
- when /111...5../ then :sar_aircraft_helicopter
28
- when /1......../ then :sar_aircraft
29
- when /8......../ then :handheld
30
- when /98......./ then :auxiliary_craft
31
- when /970....../ then :sar_transmitter
32
- when /972....../ then :man_overboard
33
- when /974....../ then :epirb
34
- when /99...1.../ then :aton_physical
35
- when /99...6.../ then :aton_virtual
36
- when /99......./ then :aton
37
- else
38
- :unknown_mmsi_category
39
- end
40
- end
41
-
42
- # The MMSI Maritime Identification Digits (MID)
43
- # @!parse attr_reader :mid
44
- # @return [Integer] the MID
45
- def mid
46
- range = case mmsi_category
47
- when :individual_ship then 0..2
48
- when :coast_station, :harbor_station, :pilot_station, :ais_repeater_station then 2..4
49
- when :sar_aircraft, :sar_aircraft_fixed, :sar_aircraft_helicopter then 3..5
50
- when :aton_physical, :aton_virtual, :aton then 2..4
51
- when :auxiliary_craft then 2..4
52
- when :handheld then 1..3
53
- when :sar_transmitter, :man_overboard, :epirb then 3..5
54
- end
55
- return nil if range.nil?
56
- source_mmsi.to_s.rjust(9, '0')[range].to_i
57
- end
58
-
59
- # The ISO 3166-1 indicated by the MMSI Maritime Identification Digits (MID)
60
- # @!parse attr_reader :mid_country
61
- # @return [Integer] the MID
62
- def mid_country
63
- # https://github.com/S73417H/MIDs
64
- # https://github.com/alexrabarts/iso_country_codes
65
- # JSON.parse(IO.read("mids.json")).each {|k, v| puts "when #{k} then #{IsoCountryCodes.find(v[1]).numeric.to_i}" }
66
- case mid
67
- when 201 then 8
68
- when 202 then 20
69
- when 203 then 40
70
- when 204 then 620
71
- when 205 then 56
72
- when 206 then 112
73
- when 207 then 100
74
- when 208 then 336
75
- when 209 then 196
76
- when 210 then 196
77
- when 211 then 276
78
- when 212 then 196
79
- when 213 then 268
80
- when 214 then 498
81
- when 215 then 470
82
- when 216 then 51
83
- when 218 then 276
84
- when 219 then 208
85
- when 220 then 208
86
- when 224 then 724
87
- when 225 then 724
88
- when 226 then 250
89
- when 227 then 250
90
- when 228 then 250
91
- when 229 then 470
92
- when 230 then 246
93
- when 231 then 234
94
- when 232 then 826
95
- when 233 then 826
96
- when 234 then 826
97
- when 235 then 826
98
- when 236 then 292
99
- when 237 then 300
100
- when 238 then 191
101
- when 239 then 300
102
- when 240 then 300
103
- when 241 then 300
104
- when 242 then 504
105
- when 243 then 348
106
- when 244 then 528
107
- when 245 then 528
108
- when 246 then 528
109
- when 247 then 380
110
- when 248 then 470
111
- when 250 then 372
112
- when 251 then 352
113
- when 252 then 438
114
- when 253 then 442
115
- when 254 then 492
116
- when 255 then 620
117
- when 256 then 470
118
- when 257 then 578
119
- when 258 then 578
120
- when 259 then 578
121
- when 261 then 616
122
- when 262 then 499
123
- when 263 then 620
124
- when 264 then 642
125
- when 265 then 752
126
- when 266 then 752
127
- when 267 then 703
128
- when 268 then 674
129
- when 269 then 756
130
- when 270 then 203
131
- when 271 then 792
132
- when 272 then 804
133
- when 273 then 643
134
- when 274 then 807
135
- when 275 then 428
136
- when 276 then 233
137
- when 277 then 440
138
- when 278 then 705
139
- when 279 then 688
140
- when 301 then 660
141
- when 303 then 840
142
- when 304 then 28
143
- when 305 then 28
144
- when 306 then 531
145
- when 307 then 533
146
- when 308 then 44
147
- when 309 then 44
148
- when 310 then 60
149
- when 311 then 60
150
- when 312 then 84
151
- when 314 then 52
152
- when 316 then 124
153
- when 319 then 136
154
- when 321 then 188
155
- when 323 then 192
156
- when 325 then 212
157
- when 327 then 214
158
- when 329 then 312
159
- when 330 then 308
160
- when 331 then 304
161
- when 332 then 320
162
- when 335 then 340
163
- when 336 then 332
164
- when 338 then 840
165
- when 339 then 388
166
- when 341 then 659
167
- when 343 then 662
168
- when 345 then 484
169
- when 347 then 474
170
- when 348 then 500
171
- when 350 then 558
172
- when 351 then 591
173
- when 352 then 591
174
- when 353 then 591
175
- when 354 then 591
176
- when 358 then 630
177
- when 359 then 222
178
- when 361 then 666
179
- when 362 then 780
180
- when 364 then 796
181
- when 366 then 840
182
- when 367 then 840
183
- when 368 then 840
184
- when 369 then 840
185
- when 370 then 591
186
- when 371 then 591
187
- when 372 then 591
188
- when 373 then 591
189
- when 375 then 670
190
- when 376 then 670
191
- when 377 then 670
192
- when 378 then 92
193
- when 379 then 850
194
- when 401 then 4
195
- when 403 then 682
196
- when 405 then 50
197
- when 408 then 48
198
- when 410 then 64
199
- when 412 then 156
200
- when 413 then 156
201
- when 414 then 156
202
- when 416 then 158
203
- when 417 then 144
204
- when 419 then 356
205
- when 422 then 364
206
- when 423 then 31
207
- when 425 then 368
208
- when 428 then 376
209
- when 431 then 392
210
- when 432 then 392
211
- when 434 then 795
212
- when 436 then 398
213
- when 437 then 860
214
- when 438 then 400
215
- when 440 then 410
216
- when 441 then 410
217
- when 443 then 275
218
- when 445 then 408
219
- when 447 then 414
220
- when 450 then 422
221
- when 451 then 417
222
- when 453 then 446
223
- when 455 then 462
224
- when 457 then 496
225
- when 459 then 524
226
- when 461 then 512
227
- when 463 then 586
228
- when 466 then 634
229
- when 468 then 760
230
- when 470 then 784
231
- when 472 then 762
232
- when 473 then 887
233
- when 475 then 887
234
- when 477 then 344
235
- when 478 then 70
236
- when 501 then 250
237
- when 503 then 36
238
- when 506 then 104
239
- when 508 then 96
240
- when 510 then 583
241
- when 511 then 585
242
- when 512 then 554
243
- when 514 then 116
244
- when 515 then 116
245
- when 516 then 162
246
- when 518 then 184
247
- when 520 then 242
248
- when 523 then 166
249
- when 525 then 360
250
- when 529 then 296
251
- when 531 then 418
252
- when 533 then 458
253
- when 536 then 580
254
- when 538 then 584
255
- when 540 then 540
256
- when 542 then 570
257
- when 544 then 520
258
- when 546 then 258
259
- when 548 then 608
260
- when 553 then 598
261
- when 555 then 612
262
- when 557 then 90
263
- when 559 then 16
264
- when 561 then 882
265
- when 563 then 702
266
- when 564 then 702
267
- when 565 then 702
268
- when 566 then 702
269
- when 567 then 764
270
- when 570 then 776
271
- when 572 then 798
272
- when 574 then 704
273
- when 576 then 548
274
- when 577 then 548
275
- when 578 then 876
276
- when 601 then 710
277
- when 603 then 24
278
- when 605 then 12
279
- when 607 then 250
280
- when 608 then 826
281
- when 609 then 108
282
- when 610 then 204
283
- when 611 then 72
284
- when 621 then 262
285
- when 613 then 120
286
- when 615 then 178
287
- when 616 then 174
288
- when 617 then 132
289
- when 618 then 250
290
- when 619 then 384
291
- when 620 then 174
292
- when 622 then 818
293
- when 624 then 231
294
- when 625 then 232
295
- when 626 then 266
296
- when 627 then 288
297
- when 629 then 270
298
- when 630 then 624
299
- when 631 then 226
300
- when 632 then 324
301
- when 633 then 854
302
- when 634 then 404
303
- when 635 then 250
304
- when 636 then 430
305
- when 637 then 430
306
- when 638 then 728
307
- when 642 then 434
308
- when 644 then 426
309
- when 645 then 480
310
- when 647 then 450
311
- when 649 then 466
312
- when 650 then 508
313
- when 654 then 478
314
- when 655 then 454
315
- when 656 then 566
316
- when 659 then 516
317
- when 660 then 638
318
- when 661 then 646
319
- when 662 then 729
320
- when 663 then 686
321
- when 664 then 690
322
- when 665 then 654
323
- when 666 then 706
324
- when 667 then 694
325
- when 668 then 678
326
- when 669 then 748
327
- when 670 then 148
328
- when 671 then 768
329
- when 672 then 788
330
- when 674 then 834
331
- when 675 then 800
332
- when 676 then 180
333
- when 677 then 834
334
- when 678 then 894
335
- when 679 then 716
336
- when 701 then 32
337
- when 710 then 76
338
- when 720 then 68
339
- when 725 then 152
340
- when 730 then 170
341
- when 735 then 218
342
- when 740 then 238
343
- when 745 then 254
344
- when 750 then 328
345
- when 755 then 600
346
- when 760 then 604
347
- when 765 then 740
348
- when 770 then 858
349
- when 775 then 862
350
- end
351
- end
352
-
353
- # The MMSI category as defined by ITU-R M.585-7
354
- # @!parse attr_reader :mmsi_category_description
355
- # @return [String] the human-readable description the MMSI category
356
- def mmsi_category_description
357
- case mmsi_category
358
- when :individual_ship then "Individual ship"
359
- when :coast_station then "Coast station"
360
- when :harbor_station then "Harbor station"
361
- when :pilot_station then "Pilot station"
362
- when :ais_repeater_station then "AIS repeater station"
363
- when :sar_aircraft then "SAR aircraft"
364
- when :sar_aircraft_fixed then "SAR fixed-wing aircraft"
365
- when :sar_aircraft_helicopter then "SAR helicopter"
366
- when :aton_physical then "Physical AIS AtoN"
367
- when :aton_virtual then "Virtual AIS AtoN"
368
- when :aton then "AIS Aid to Navigation"
369
- when :auxiliary_craft then "Auxiliary craft"
370
- when :handheld then "Handheld transceiver"
371
- when :sar_transmitter then "AIS-SART"
372
- when :man_overboard then "MOB (Man Overboard)"
373
- when :epirb then "EPIRB"
374
- else
375
- mmsi_category.to_s
376
- end
16
+ # Detailed information produced from the MMSI
17
+ # @!parse attr_reader :source_mmsi_info
18
+ # @return [MMSIInfo] MMSI information structure
19
+ def source_mmsi_info
20
+ MMSIInfo.new(source_mmsi)
377
21
  end
378
22
 
379
23
  # The ship cargo type description lookup table
@@ -447,7 +91,7 @@ module NMEAPlus
447
91
 
448
92
  # An MMSI is associated with an auxiliary craft when it is of the form 98XXXYYYY
449
93
  def auxiliary_craft?
450
- mmsi_category == :auxiliary_craft
94
+ source_mmsi_info.category == :auxiliary_craft
451
95
  end
452
96
 
453
97
  # @param code [Integer] The navigational status id
@@ -1,4 +1,9 @@
1
1
  require_relative 'vdm_msg'
2
+ require_relative 'vdm_msg6d1f0'
3
+ require_relative 'vdm_msg6d1f2'
4
+ require_relative 'vdm_msg6d1f3'
5
+ require_relative 'vdm_msg6d1f4'
6
+ require_relative 'vdm_msg6d1f5'
2
7
  require_relative 'vdm_msg6d235f10'
3
8
  require_relative 'vdm_msg6d1022f61'
4
9
 
@@ -0,0 +1,17 @@
1
+ require_relative 'vdm_msg6_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 6: Binary Addressed Message Subtype: IFM 0: Text using 6-bit ASCII
9
+ class VDMMsg6d1f0 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg6DynamicPayload
10
+ payload_reader :acknowledge_required?, 88, 1, :_b
11
+ payload_reader :sequence_number, 89, 11, :_u
12
+ payload_reader :text, 100, 906, :_t
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'vdm_msg6_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 6: Binary Addressed Message Subtype: IFM 2: Interrogation for a specific FM
9
+ class VDMMsg6d1f2 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg6DynamicPayload
10
+ payload_reader :requested_dac, 88, 10, :_u
11
+ payload_reader :requested_fid, 98, 6, :_u
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'vdm_msg6_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 6: Binary Addressed Message Subtype: IFM 3: Capability interrogation
9
+ class VDMMsg6d1f3 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg6DynamicPayload
10
+ payload_reader :requested_dac, 88, 10, :_u
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'vdm_msg6_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 6: Binary Addressed Message Subtype: IFM 4: Capability reply
9
+ class VDMMsg6d1f4 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg6DynamicPayload
10
+
11
+ # The availibility table for functional IDs; there are 64 boolean entries
12
+ # @!parse attr_reader :fid_availability
13
+ # @return [Array] An array of booleans
14
+ def fid_availability
15
+ (0...128).step(2).to_a.map do |pos|
16
+ _6b_boolean(88 + pos, 1)
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ require_relative 'vdm_msg6_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 6: Binary Addressed Message Subtype: IFM 5: Application acknowledgement to an addressed binary message
9
+ class VDMMsg6d1f5 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg6DynamicPayload
10
+ payload_reader :received_fm_dac, 88, 10, :_u
11
+ payload_reader :received_fm_fid, 98, 6, :_u
12
+ payload_reader :sequence_number, 104, 11, :_u
13
+ payload_reader :ai_available?, 115, 1, :_b
14
+ payload_reader :ai_response, 116, 3, :_e
15
+
16
+ # The AI response description
17
+ # @!parse attr_reader :ai_response_description
18
+ # @return [String] The description of the AI response
19
+ def ai_response_description
20
+ case ai_response
21
+ when 0 then "Unable to respond"
22
+ when 1 then "Reception acknowledged"
23
+ when 2 then "Response to follow"
24
+ when 3 then "Able to respond but currently inhibited"
25
+ else
26
+ "Reserved for future use"
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,4 +1,5 @@
1
1
  require_relative 'vdm_msg'
2
+ require_relative 'vdm_msg8d1f0'
2
3
  require_relative 'vdm_msg8d1f22'
3
4
  require_relative 'vdm_msg8d1f31'
4
5
  require_relative 'vdm_msg8d366f56'
@@ -0,0 +1,17 @@
1
+ require_relative 'vdm_msg8_dynamic_payload'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+
8
+ # Type 8: Binary Addressed Message Subtype: IFM 0: Text using 6-bit ASCII
9
+ class VDMMsg8d1f0 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg8DynamicPayload
10
+ payload_reader :acknowledge_required?, 56, 1, :_b
11
+ payload_reader :sequence_number, 57, 11, :_u
12
+ payload_reader :text, 68, 906, :_t
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -63,7 +63,7 @@ module NMEAPlus
63
63
 
64
64
  # @return [bool] Whether the checksum calculated from the payload matches the checksum given in the message
65
65
  def checksum_ok?
66
- calculated_checksum.upcase == checksum.upcase
66
+ 0 == calculated_checksum.casecmp(checksum)
67
67
  end
68
68
 
69
69
  # return [bool] Whether the checksums for all available message parts are OK
@@ -1,3 +1,3 @@
1
1
  module NMEAPlus
2
- VERSION = '1.0.10'
2
+ VERSION = '1.0.11'.freeze
3
3
  end
data/lib/nmea_plus.rb CHANGED
@@ -3,14 +3,16 @@ require 'nmea_plus/version'
3
3
  require 'nmea_plus/generated_parser/parser'
4
4
  require 'nmea_plus/generated_parser/tokenizer'
5
5
 
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}.
6
+ # NMEAPlus contains classes for parsing and decoding NMEA and AIS messages, of which the {NMEAPlus::SourceDecoder}
7
+ # is most relevant. Parsed messages extend from the {Message::NMEA::NMEAMessage} object, and any binary
8
+ # AIS playloads are decoded into objects that extend from {Message::AIS::AISMessage}.
9
9
  # @author Ian Katz
10
10
  module NMEAPlus
11
11
 
12
- # The NMEA source decoder wraps an IO object, converting each_line functionality
13
- # to {#each_message} or {#each_complete_message}
12
+ # The SourceDecoder is meant as the primary entry point into the {NMEAPlus} module.
13
+ # It wraps a {Decoder} object and an IO object, converting IO's #each_line functionality
14
+ # to {#each_message} and/or {#each_complete_message},
15
+ # which yield {NMEAPlus::Message} objects representing the parsed data.
14
16
  class SourceDecoder
15
17
  # False by default.
16
18
  # @return [bool] whether to throw an exception on lines that don't properly parse
@@ -30,9 +32,20 @@ module NMEAPlus
30
32
  @decoder = NMEAPlus::Decoder.new
31
33
  end
32
34
 
33
- # Executes the block for every valid NMEA message in the source stream
35
+ # Executes the block for every valid NMEA message in the source stream.
36
+ # In practice, you should use {#each_complete_message} unless you have a very compelling reason not to.
34
37
  # @yield [NMEAPlus::Message] A parsed message
35
38
  # @return [void]
39
+ # @example
40
+ # input = "$GPGGA,123519,4807.038,N,01131.000,W,1,08,0.9,545.4,M,46.9,M,2.2,123*4b"
41
+ # io_source = StringIO.new(input) # source decoder works on any IO object
42
+ # source_decoder = NMEAPlus::SourceDecoder.new(io_source)
43
+ # source_decoder.each_message do |message|
44
+ # if "GGA" == message.interpreted_data_type
45
+ # puts "Latitude: #{message.latitude} / Longitude: #{message.longtitude}"
46
+ # # prints "Latitude: 48.1173 / Longitude: -11.516666666666666666"
47
+ # end
48
+ # end
36
49
  def each_message
37
50
  @source.each_line do |line|
38
51
  if @throw_on_parse_fail
@@ -49,25 +62,34 @@ module NMEAPlus
49
62
  end
50
63
  end
51
64
 
52
- # Executes the block for every valid NMEA message in the source stream, attempting to
53
- # group multipart messages into message chains.
65
+ # Attempts to group multipart NMEA messages into chains, and executes the block once for every complete chain.
66
+ #
54
67
  # @yield [NMEAPlus::Message] A parsed message that may contain subsequent parts
55
68
  # @return [void]
69
+ # @example
70
+ # input1 = "!AIVDM,2,1,0,A,58wt8Ui`g??r21`7S=:22058<v05Htp000000015>8OA;0sk,0*7B"
71
+ # input2 = "!AIVDM,2,2,0,A,eQ8823mDm3kP00000000000,2*5D"
72
+ # io_source = StringIO.new("#{input1}\n#{input2}") # source decoder works on any IO object
73
+ # source_decoder = NMEAPlus::SourceDecoder.new(io_source)
74
+ # source_decoder.each_complete_message do |message|
75
+ # if message.ais && message.ais.message_type == 5
76
+ # ais = message.ais # ais payload shortcut
77
+ # puts "Ship with MMSI #{ais.source_mmsi} (#{ais.name.strip}) is going to #{ais.destination.strip}"
78
+ # # prints "Ship with MMSI 603916439 (ARCO AVON) is going to HOUSTON"
79
+ # end
80
+ # end
56
81
  def each_complete_message
57
- partials = {}
82
+ partials = {} # hash of message type to message-chain-in-progress
58
83
  each_message do |msg|
59
- slot = msg.data_type
84
+ slot = msg.data_type # the slot in the hash
60
85
 
61
- if partials[slot].nil?
86
+ if partials[slot].nil? # no message in there
62
87
  partials[slot] = msg
63
- else
64
- # the message was already in there
65
- if 1 != (msg.message_number - partials[slot].message_number)
66
- # error! just overwrite what was there
67
- partials[slot] = msg
68
- else
69
- partials[slot].add_message_part(msg)
70
- end
88
+ elsif 1 != (msg.message_number - partials[slot].message_number) # broken sequence
89
+ # error! just overwrite what was there
90
+ partials[slot] = msg
91
+ else # chain on to what's there
92
+ partials[slot].add_message_part(msg)
71
93
  end
72
94
 
73
95
  # take action if we've completed the chain
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nmea_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Katz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-26 00:00:00.000000000 Z
11
+ date: 2016-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: racc
@@ -70,7 +70,7 @@ dependencies:
70
70
  requirements:
71
71
  - - ~>
72
72
  - !ruby/object:Gem::Version
73
- version: '0.31'
73
+ version: '0.36'
74
74
  - - '>='
75
75
  - !ruby/object:Gem::Version
76
76
  version: 0.31.0
@@ -80,7 +80,7 @@ dependencies:
80
80
  requirements:
81
81
  - - ~>
82
82
  - !ruby/object:Gem::Version
83
- version: '0.31'
83
+ version: '0.36'
84
84
  - - '>='
85
85
  - !ruby/object:Gem::Version
86
86
  version: 0.31.0
@@ -196,6 +196,7 @@ files:
196
196
  - lib/nmea_plus/generated_parser/tokenizer.rb
197
197
  - lib/nmea_plus/message/ais/base_ais.rb
198
198
  - lib/nmea_plus/message/ais/vdm.rb
199
+ - lib/nmea_plus/message/ais/vdm_payload/mmsi_info.rb
199
200
  - lib/nmea_plus/message/ais/vdm_payload/payload.rb
200
201
  - lib/nmea_plus/message/ais/vdm_payload/sub_area.rb
201
202
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg.rb
@@ -212,10 +213,16 @@ files:
212
213
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6.rb
213
214
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6_dynamic_payload.rb
214
215
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1022f61.rb
216
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1f0.rb
217
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1f2.rb
218
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1f3.rb
219
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1f4.rb
220
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d1f5.rb
215
221
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg6d235f10.rb
216
222
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg7.rb
217
223
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8.rb
218
224
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8_dynamic_payload.rb
225
+ - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8d1f0.rb
219
226
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8d1f22.rb
220
227
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8d1f31.rb
221
228
  - lib/nmea_plus/message/ais/vdm_payload/vdm_msg8d366f56.rb