nmea_plus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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