nmea_plus 1.0.0

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/gem/lib/nmea_plus.rb +63 -0
  3. data/gem/lib/nmea_plus/ais_message_factory.rb +17 -0
  4. data/gem/lib/nmea_plus/generated_parser/parser.rb +127 -0
  5. data/gem/lib/nmea_plus/generated_parser/tokenizer.rb +100 -0
  6. data/gem/lib/nmea_plus/message/ais/base_ais.rb +20 -0
  7. data/gem/lib/nmea_plus/message/ais/vdm.rb +100 -0
  8. data/gem/lib/nmea_plus/message/ais/vdm_payload/vdm_msg.rb +99 -0
  9. data/gem/lib/nmea_plus/message/ais/vdm_payload/vdm_msg1.rb +65 -0
  10. data/gem/lib/nmea_plus/message/ais/vdm_payload/vdm_msg5.rb +38 -0
  11. data/gem/lib/nmea_plus/message/ais/vdm_payload/vdm_msg8.rb +43 -0
  12. data/gem/lib/nmea_plus/message/base.rb +172 -0
  13. data/gem/lib/nmea_plus/message/nmea/aam.rb +17 -0
  14. data/gem/lib/nmea_plus/message/nmea/alm.rb +25 -0
  15. data/gem/lib/nmea_plus/message/nmea/apa.rb +20 -0
  16. data/gem/lib/nmea_plus/message/nmea/apb.rb +14 -0
  17. data/gem/lib/nmea_plus/message/nmea/base_nmea.rb +36 -0
  18. data/gem/lib/nmea_plus/message/nmea/bod.rb +14 -0
  19. data/gem/lib/nmea_plus/message/nmea/bwc.rb +12 -0
  20. data/gem/lib/nmea_plus/message/nmea/bwr.rb +25 -0
  21. data/gem/lib/nmea_plus/message/nmea/bww.rb +11 -0
  22. data/gem/lib/nmea_plus/message/nmea/dbk.rb +13 -0
  23. data/gem/lib/nmea_plus/message/nmea/dbs.rb +11 -0
  24. data/gem/lib/nmea_plus/message/nmea/dbt.rb +11 -0
  25. data/gem/lib/nmea_plus/message/nmea/dcn.rb +26 -0
  26. data/gem/lib/nmea_plus/message/nmea/dpt.rb +12 -0
  27. data/gem/lib/nmea_plus/message/nmea/dtm.rb +24 -0
  28. data/gem/lib/nmea_plus/message/nmea/fsi.rb +14 -0
  29. data/gem/lib/nmea_plus/message/nmea/gbs.rb +18 -0
  30. data/gem/lib/nmea_plus/message/nmea/gga.rb +32 -0
  31. data/gem/lib/nmea_plus/message/nmea/glc.rb +23 -0
  32. data/gem/lib/nmea_plus/message/nmea/gll.rb +21 -0
  33. data/gem/lib/nmea_plus/message/nmea/gns.rb +28 -0
  34. data/gem/lib/nmea_plus/message/nmea/grs.rb +24 -0
  35. data/gem/lib/nmea_plus/message/nmea/gsa.rb +27 -0
  36. data/gem/lib/nmea_plus/message/nmea/gst.rb +18 -0
  37. data/gem/lib/nmea_plus/message/nmea/gsv.rb +29 -0
  38. data/gem/lib/nmea_plus/message/nmea/gtd.rb +15 -0
  39. data/gem/lib/nmea_plus/message/nmea/gxa.rb +22 -0
  40. data/gem/lib/nmea_plus/message/nmea/hdg.rb +20 -0
  41. data/gem/lib/nmea_plus/message/nmea/hdm.rb +11 -0
  42. data/gem/lib/nmea_plus/message/nmea/hdt.rb +11 -0
  43. data/gem/lib/nmea_plus/message/nmea/hfb.rb +12 -0
  44. data/gem/lib/nmea_plus/message/nmea/hsc.rb +12 -0
  45. data/gem/lib/nmea_plus/message/nmea/its.rb +11 -0
  46. data/gem/lib/nmea_plus/message/nmea/lcd.rb +23 -0
  47. data/gem/lib/nmea_plus/message/nmea/msk.rb +15 -0
  48. data/gem/lib/nmea_plus/message/nmea/mss.rb +15 -0
  49. data/gem/lib/nmea_plus/message/nmea/mtw.rb +12 -0
  50. data/gem/lib/nmea_plus/message/nmea/mwv.rb +15 -0
  51. data/gem/lib/nmea_plus/message/nmea/oln.rb +22 -0
  52. data/gem/lib/nmea_plus/message/nmea/osd.rb +19 -0
  53. data/gem/lib/nmea_plus/message/nmea/pashr.rb +21 -0
  54. data/gem/lib/nmea_plus/message/nmea/r00.rb +11 -0
  55. data/gem/lib/nmea_plus/message/nmea/rma.rb +30 -0
  56. data/gem/lib/nmea_plus/message/nmea/rmb.rb +30 -0
  57. data/gem/lib/nmea_plus/message/nmea/rmc.rb +33 -0
  58. data/gem/lib/nmea_plus/message/nmea/rot.rb +12 -0
  59. data/gem/lib/nmea_plus/message/nmea/rpm.rb +15 -0
  60. data/gem/lib/nmea_plus/message/nmea/rsa.rb +17 -0
  61. data/gem/lib/nmea_plus/message/nmea/rsd.rb +14 -0
  62. data/gem/lib/nmea_plus/message/nmea/rte.rb +16 -0
  63. data/gem/lib/nmea_plus/message/nmea/sfi.rb +18 -0
  64. data/gem/lib/nmea_plus/message/nmea/stn.rb +11 -0
  65. data/gem/lib/nmea_plus/message/nmea/tds.rb +11 -0
  66. data/gem/lib/nmea_plus/message/nmea/tfi.rb +13 -0
  67. data/gem/lib/nmea_plus/message/nmea/tpc.rb +13 -0
  68. data/gem/lib/nmea_plus/message/nmea/tpr.rb +13 -0
  69. data/gem/lib/nmea_plus/message/nmea/tpt.rb +13 -0
  70. data/gem/lib/nmea_plus/message/nmea/trf.rb +28 -0
  71. data/gem/lib/nmea_plus/message/nmea/ttm.rb +22 -0
  72. data/gem/lib/nmea_plus/message/nmea/vbw.rb +16 -0
  73. data/gem/lib/nmea_plus/message/nmea/vdr.rb +13 -0
  74. data/gem/lib/nmea_plus/message/nmea/vhw.rb +14 -0
  75. data/gem/lib/nmea_plus/message/nmea/vlw.rb +12 -0
  76. data/gem/lib/nmea_plus/message/nmea/vpw.rb +12 -0
  77. data/gem/lib/nmea_plus/message/nmea/vtg.rb +41 -0
  78. data/gem/lib/nmea_plus/message/nmea/vwr.rb +15 -0
  79. data/gem/lib/nmea_plus/message/nmea/wcv.rb +12 -0
  80. data/gem/lib/nmea_plus/message/nmea/wnc.rb +14 -0
  81. data/gem/lib/nmea_plus/message/nmea/wpl.rb +19 -0
  82. data/gem/lib/nmea_plus/message/nmea/xdr.rb +14 -0
  83. data/gem/lib/nmea_plus/message/nmea/xte.rb +16 -0
  84. data/gem/lib/nmea_plus/message/nmea/xtr.rb +12 -0
  85. data/gem/lib/nmea_plus/message/nmea/zda.rb +23 -0
  86. data/gem/lib/nmea_plus/message/nmea/zfo.rb +13 -0
  87. data/gem/lib/nmea_plus/message/nmea/ztg.rb +13 -0
  88. data/gem/lib/nmea_plus/message_factory.rb +68 -0
  89. data/gem/lib/nmea_plus/nmea_message_factory.rb +110 -0
  90. data/gem/lib/nmea_plus/version.rb +3 -0
  91. metadata +285 -0
@@ -0,0 +1,65 @@
1
+ require_relative 'vdm_msg'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+ class VDMMsgCNB < NMEAPlus::Message::AIS::VDMPayload::VDMMsg
8
+
9
+ payload_reader :navigational_status, 38, 4, :_u
10
+
11
+ def navigational_status_description
12
+ case navigational_status
13
+ when 0 then return "Under way using engine"
14
+ when 1 then return "At anchor"
15
+ when 2 then return "Not under command"
16
+ when 3 then return "Restricted manoeuverability"
17
+ when 4 then return "Constrained by her draught"
18
+ when 5 then return "Moored"
19
+ when 6 then return "Aground"
20
+ when 7 then return "Engaged in Fishing"
21
+ when 8 then return "Under way sailing"
22
+ when 14 then return "AIS-SART active"
23
+ else
24
+ return "undefined"
25
+ end
26
+ end
27
+
28
+ def rate_of_turn
29
+ ret = _i(42, 8)
30
+ return nil if ret == -128
31
+ (_I(42, 8, 3) / 4.733) ** 2
32
+ end
33
+
34
+ payload_reader :speed_over_ground, 50, 10, :_U, 1
35
+ payload_reader :position_10m_accuracy?, 60, 1, :_b
36
+
37
+ def longitude
38
+ _I(61, 28, 4) / 60
39
+ end
40
+
41
+ def latitude
42
+ _U(89, 27, 4) / 60
43
+ end
44
+
45
+ payload_reader :course_over_ground, 116, 12, :_U, 1
46
+
47
+ def true_heading
48
+ ret = _u(128, 9)
49
+ return nil if ret == 511 # means "not available"
50
+ ret
51
+ end
52
+
53
+ payload_reader :time_stamp, 137, 6, :_u
54
+ payload_reader :special_manoeuvre, 143, 2, :_e
55
+ payload_reader :raim?, 148, 1, :_b
56
+
57
+ end
58
+
59
+ class VDMMsg1 < VDMMsgCNB; end
60
+ class VDMMsg2 < VDMMsgCNB; end
61
+ class VDMMsg3 < VDMMsgCNB; end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'vdm_msg'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+ class VDMMsg5 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg
8
+
9
+ payload_reader :ais_version, 38, 2, :_u
10
+ payload_reader :imo_number, 40, 30, :_u
11
+ payload_reader :callsign, 70, 42, :_t
12
+ payload_reader :name, 112, 120, :_t
13
+ payload_reader :ship_cargo_type, 232, 8, :_e
14
+ payload_reader :ship_dimension_to_bow, 240, 9, :_u
15
+ payload_reader :ship_dimension_to_stern, 249, 9, :_u
16
+ payload_reader :ship_dimension_to_port, 258, 6, :_u
17
+ payload_reader :ship_dimension_to_starboard, 264, 6, :_u
18
+ payload_reader :epfd_type, 270, 4, :_e
19
+
20
+ def eta
21
+ now = Time.now
22
+ Time.new(now.year,
23
+ _u(274, 4),
24
+ _u(278, 5),
25
+ _u(283, 5),
26
+ _u(288, 6),
27
+ 0)
28
+ end
29
+
30
+ payload_reader :static_draught, 294, 8, :_U, 1
31
+ payload_reader :destination, 302, 120, :_t
32
+ payload_reader :dte?, 422, 1, :_b
33
+
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ require_relative 'vdm_msg'
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module AIS
6
+ module VDMPayload
7
+ class VDMMsg8 < NMEAPlus::Message::AIS::VDMPayload::VDMMsg
8
+ payload_reader :designated_area_code, 40, 10, :_u
9
+ payload_reader :functional_id, 50, 6, :_u
10
+ payload_reader :application_data_2b, 56, 952, :_d
11
+ payload_reader :application_data_6b, 56, 952, :_6b_string
12
+ payload_reader :application_data_8b, 56, 952, :_8b_data_string
13
+
14
+ payload_reader :ais_version, 38, 2, :_u
15
+ payload_reader :imo_number, 40, 30, :_u
16
+ payload_reader :callsign, 70, 42, :_t
17
+ payload_reader :name, 112, 120, :_t
18
+ payload_reader :ship_cargo_type, 232, 8, :_e
19
+ payload_reader :ship_dimension_to_bow, 240, 9, :_u
20
+ payload_reader :ship_dimension_to_stern, 249, 9, :_u
21
+ payload_reader :ship_dimension_to_port, 258, 6, :_u
22
+ payload_reader :ship_dimension_to_starboard, 264, 6, :_u
23
+ payload_reader :epfd_type, 270, 4, :_e
24
+
25
+ def eta
26
+ now = Time.now
27
+ Time.new(now.year,
28
+ _u(274, 4),
29
+ _u(278, 5),
30
+ _u(283, 5),
31
+ _u(288, 6),
32
+ 0)
33
+ end
34
+
35
+ payload_reader :static_draught, 294, 8, :_U, 1
36
+ payload_reader :destination, 302, 120, :_t
37
+ payload_reader :dte?, 422, 1, :_b
38
+
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,172 @@
1
+
2
+ class Class
3
+ # make our own shortcut syntax for message attributes
4
+ def field_reader(name, field_num, formatter = nil)
5
+ if formatter.nil?
6
+ self.class_eval("def #{name};@fields[#{field_num}];end")
7
+ else
8
+ self.class_eval("def #{name};#{formatter}(@fields[#{field_num}]);end")
9
+ end
10
+ end
11
+ end
12
+
13
+ module NMEAPlus
14
+ module Message
15
+ class Base
16
+ attr_accessor :prefix
17
+ attr_reader :payload
18
+ attr_reader :fields
19
+ attr_accessor :checksum
20
+ attr_accessor :interpreted_data_type
21
+ attr_accessor :next_part
22
+
23
+ field_reader :data_type, 0, nil
24
+
25
+ def original
26
+ "#{prefix}#{payload}*#{checksum}"
27
+ end
28
+
29
+ def payload=(val)
30
+ @payload = val
31
+ @fields = val.split(',', -1)
32
+ end
33
+
34
+ def checksum_ok?
35
+ calculated_checksum.upcase == checksum.upcase
36
+ end
37
+
38
+ def all_checksums_ok?
39
+ return false unless checksum_ok?
40
+ return true if @next_part.nil?
41
+ @next_part.all_checksums_ok?
42
+ end
43
+
44
+ def calculated_checksum
45
+ "%02x" % @payload.each_byte.map(&:ord).reduce(:^)
46
+ end
47
+
48
+ # many messages override these fields
49
+ def total_messages
50
+ 1
51
+ end
52
+
53
+ # sequence number
54
+ def message_number
55
+ 1
56
+ end
57
+
58
+ # create a linked list (O(n) implementation; message parts assumed to be < 10) of message parts
59
+ def add_message_part(msg)
60
+ if @next_part.nil?
61
+ @next_part = msg
62
+ else
63
+ @next_part.add_message_part(msg)
64
+ end
65
+ end
66
+
67
+ def all_messages_received?
68
+ total_messages == highest_contiguous_index
69
+ end
70
+
71
+ def highest_contiguous_index
72
+ _highest_contiguous_index(0)
73
+ end
74
+
75
+ def _highest_contiguous_index(last_index)
76
+ mn = message_number # just in case this is expensive to compute
77
+ return last_index if mn - last_index != 1 # indicating a skip or restart
78
+ return mn if @next_part.nil? # indicating we're the last message
79
+ @next_part._highest_contiguous_index(mn) # recurse down
80
+ end
81
+
82
+ ######################### Conversion functions
83
+
84
+ # convert DDMM.MMM to single decimal value.
85
+ # sign_letter can be N,S,E,W
86
+ def _degrees_minutes_to_decimal(dm_string, sign_letter = "")
87
+ return nil if dm_string.nil? || dm_string.empty?
88
+ r = /(\d+)(\d{2}\.\d+)/ # (some number of digits) (2 digits for minutes).(decimal minutes)
89
+ m = r.match(dm_string)
90
+ raw = m.values_at(1)[0].to_f + (m.values_at(2)[0].to_f / 60)
91
+ _nsew_signed_float(raw, sign_letter)
92
+ end
93
+
94
+ # Use cardinal directions to assign positive or negative to mixed_val
95
+ # mixed_val can be string or float
96
+ # Of possible directions NSEW (sign_letter) treat N/E as + and S/W as -
97
+ def _nsew_signed_float(mixed_val, sign_letter = "")
98
+ value = mixed_val.to_f
99
+ value *= -1 if !sign_letter.empty? && "SW".include?(sign_letter.upcase)
100
+ value
101
+ end
102
+
103
+ # integer or nil
104
+ def _integer(field)
105
+ return nil if field.nil? || field.empty?
106
+ field.to_i
107
+ end
108
+
109
+ # float or nil
110
+ def _float(field)
111
+ return nil if field.nil? || field.empty?
112
+ field.to_f
113
+ end
114
+
115
+ # string or nil
116
+ def _string(field)
117
+ return nil if field.nil? || field.empty?
118
+ field
119
+ end
120
+
121
+ # hex to int or nil
122
+ def _hex_to_integer(field)
123
+ return nil if field.nil? || field.empty?
124
+ field.hex
125
+ end
126
+
127
+ # utc time or nil (HHMMSS or HHMMSS.SS)
128
+ def _utctime_hms(field)
129
+ return nil if field.nil? || field.empty?
130
+ re_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
131
+ now = Time.now
132
+ begin
133
+ hms = re_format.match(field)
134
+ Time.new(now.year, now.month, now.day, hms[1].to_i, hms[2].to_i, hms[3].to_f)
135
+ rescue
136
+ nil
137
+ end
138
+ end
139
+
140
+ # time interval or nil (HHMMSS or HHMMSS.SS)
141
+ def _interval_hms(field)
142
+ return nil if field.nil? || field.empty?
143
+ re_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
144
+ begin
145
+ hms = re_format.match(field)
146
+ Time.new(0, 0, 0, hms[1].to_i, hms[2].to_i, hms[3].to_f)
147
+ rescue
148
+ nil
149
+ end
150
+ end
151
+
152
+ def _utc_date_time(d_field, t_field)
153
+ return nil if t_field.nil? || t_field.empty?
154
+ return nil if d_field.nil? || d_field.empty?
155
+
156
+ # get formats and time
157
+ time_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
158
+ date_format = /(\d{2})(\d{2})(\d{2})/
159
+
160
+ # crunch numbers
161
+ begin
162
+ dmy = date_format.match(d_field)
163
+ hms = time_format.match(t_field)
164
+ Time.new(2000 + dmy[3].to_i, dmy[2].to_i, dmy[1].to_i, hms[1].to_i, hms[2].to_i, hms[3].to_f)
165
+ rescue
166
+ nil
167
+ end
168
+ end
169
+
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,17 @@
1
+
2
+ require_relative "base_nmea"
3
+
4
+ module NMEAPlus
5
+ module Message
6
+ module NMEA
7
+
8
+ class AAM < NMEAPlus::Message::NMEA::NMEAMessage
9
+ field_reader :arrival_circle_entered?, 1, :_av_boolean
10
+ field_reader :waypoint_passed?, 2, :_av_boolean
11
+ field_reader :arrival_circle_radius, 3, :_float
12
+ field_reader :arrival_circle_radius_units, 4, :_string
13
+ field_reader :waypoint_id, 5, :_string
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ require_relative "base_nmea"
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module NMEA
6
+ class ALM < NMEAPlus::Message::NMEA::NMEAMessage
7
+ field_reader :total_messages, 1, :_integer
8
+ field_reader :message_number, 2, :_integer
9
+ field_reader :satellite_prn, 3, :_integer
10
+ field_reader :gps_week, 4, :_integer
11
+ field_reader :sv_health, 5, :_hex_to_integer
12
+ field_reader :eccentricity, 6, :_hex_to_integer
13
+ field_reader :reference_time, 7, :_hex_to_integer
14
+ field_reader :inclination_angle, 8, :_hex_to_integer
15
+ field_reader :ascension_rate, 9, :_hex_to_integer
16
+ field_reader :semimajor_axis_root, 10, :_hex_to_integer
17
+ field_reader :perigee_argument, 11, :_hex_to_integer
18
+ field_reader :ascension_node_longitude, 12, :_hex_to_integer
19
+ field_reader :mean_anomaly, 13, :_hex_to_integer
20
+ field_reader :f0_clock, 14, :_hex_to_integer
21
+ field_reader :f1_clock, 15, :_hex_to_integer
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "base_nmea"
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module NMEA
6
+ class APA < NMEAPlus::Message::NMEA::NMEAMessage
7
+ field_reader :no_general_warning?, 1, :_av_boolean
8
+ field_reader :no_cyclelock_warning?, 2, :_av_boolean
9
+ field_reader :cross_track_error, 3, :_float
10
+ field_reader :direction_to_steer, 4, :_string
11
+ field_reader :cross_track_units, 5, :_string
12
+ field_reader :arrival_circle_entered?, 6, :_av_boolean
13
+ field_reader :perpendicular_passed?, 7, :_av_boolean
14
+ field_reader :bearing_origin_to_destination, 8, :_float
15
+ field_reader :compass_type, 9, :_string
16
+ field_reader :destination_waypoint_id, 10, :_string
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "base_nmea"
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module NMEA
6
+ class APB < NMEAPlus::Message::NMEA::APA
7
+ field_reader :bearing_position_to_destination, 11, :_float
8
+ field_reader :bearing_position_to_destination_compass_type, 12, :_string
9
+ field_reader :heading_to_waypoint, 13, :_float
10
+ field_reader :heading_to_waypoint_compass_type, 14, :_string
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+
2
+ require_relative "../base"
3
+
4
+ module NMEAPlus
5
+ module Message
6
+ module NMEA
7
+
8
+ class NMEAMessage < NMEAPlus::Message::Base
9
+ def talker
10
+ data_type[0..1]
11
+ end
12
+
13
+ def message_type
14
+ data_type[2..-1]
15
+ end
16
+
17
+ def _av_boolean(data)
18
+ case data
19
+ when 'A' then return true
20
+ when 'V' then return false
21
+ end
22
+ nil
23
+ end
24
+
25
+ def _10_boolean(data)
26
+ case data
27
+ when '1' then return true
28
+ when '0' then return false
29
+ end
30
+ nil
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "base_nmea"
2
+
3
+ module NMEAPlus
4
+ module Message
5
+ module NMEA
6
+ class BOD < NMEAPlus::Message::NMEA::NMEAMessage
7
+ field_reader :bearing_true, 1, :_float
8
+ field_reader :bearing_magnetic, 3, :_float
9
+ field_reader :waypoint_to, 5, :_string
10
+ field_reader :waypoint_from, 6, :_string
11
+ end
12
+ end
13
+ end
14
+ end