Class: NMEAPlus::Message::Base Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/nmea_plus/message/base.rb

Overview

This class is abstract.

The base message type, from which all others inherit

Direct Known Subclasses

AIS::AISMessage, NMEA::NMEAMessage

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#checksumString

Returns The two-character checksum of the message.

Returns:

  • (String)

    The two-character checksum of the message



36
37
38
# File 'lib/nmea_plus/message/base.rb', line 36

def checksum
  @checksum
end

#data_typeObject (readonly)

Returns field 0 of the payload, formatted with the function #nil.

Returns:

  • field 0 of the payload, formatted with the function #nil



44
# File 'lib/nmea_plus/message/base.rb', line 44

field_reader :data_type, 0, nil

#fieldsArray<String> (readonly)

Returns The payload of the message, split into fields.

Returns:

  • (Array<String>)

    The payload of the message, split into fields



33
34
35
# File 'lib/nmea_plus/message/base.rb', line 33

def fields
  @fields
end

#interpreted_data_typeString

Returns The data type used by the NMEAPlus::MessageFactory to parse this message.

Returns:



39
40
41
# File 'lib/nmea_plus/message/base.rb', line 39

def interpreted_data_type
  @interpreted_data_type
end

#message_numberInteger (readonly)

This method is abstract.

Returns The ordinal number of this message in its sequence.

Returns:

  • (Integer)

    The ordinal number of this message in its sequence

See Also:



87
88
89
# File 'lib/nmea_plus/message/base.rb', line 87

def message_number
  1
end

#next_partNMEAPlus::Message

Returns The next part of a multipart message, if available.

Returns:



42
43
44
# File 'lib/nmea_plus/message/base.rb', line 42

def next_part
  @next_part
end

#originalString (readonly)

Returns The original message.

Returns:

  • (String)

    The original message



48
49
50
# File 'lib/nmea_plus/message/base.rb', line 48

def original
  "#{prefix}#{payload}*#{checksum}"
end

#payloadString

Returns The unprocessed payload of the message.

Returns:

  • (String)

    The unprocessed payload of the message



30
31
32
# File 'lib/nmea_plus/message/base.rb', line 30

def payload
  @payload
end

#prefixString

Returns The single character prefix for this NMEA 0183 message type.

Returns:

  • (String)

    The single character prefix for this NMEA 0183 message type



27
28
29
# File 'lib/nmea_plus/message/base.rb', line 27

def prefix
  @prefix
end

#total_messagesInteger (readonly)

This method is abstract.

Returns The number of parts to this message.

Returns:

  • (Integer)

    The number of parts to this message

See Also:



79
80
81
# File 'lib/nmea_plus/message/base.rb', line 79

def total_messages
  1
end

Class Method Details

.field_reader(name, field_num, formatter = nil) ⇒ Object

make our own shortcut syntax for message attribute accessors

Parameters:

  • name (String)

    What the accessor will be called

  • field_num (Integer)

    The index of the field in the payload

  • formatter (Symbol) (defaults to: nil)

    The symbol for the formatting function to apply to the field (optional)



18
19
20
21
22
23
24
# File 'lib/nmea_plus/message/base.rb', line 18

def self.field_reader(name, field_num, formatter = nil)
  if formatter.nil?
    self.class_eval("def #{name};@fields[#{field_num}];end")
  else
    self.class_eval("def #{name};#{formatter}(@fields[#{field_num}]);end")
  end
end

Instance Method Details

#_degrees_minutes_to_decimal(dm_string, sign_letter = "") ⇒ Float

Convert A string latitude or longitude as fields into a signed number

Parameters:

  • dm_string (String)

    An angular measurement in the form DDMM.MMM

  • sign_letter (String) (defaults to: "")

    can be N,S,E,W

Returns:

  • (Float)

    A signed latitude or longitude



132
133
134
135
136
137
138
# File 'lib/nmea_plus/message/base.rb', line 132

def _degrees_minutes_to_decimal(dm_string, sign_letter = "")
  return nil if dm_string.nil? || dm_string.empty?
  r = /(\d+)(\d{2}\.\d+)/  # (some number of digits) (2 digits for minutes).(decimal minutes)
  m = r.match(dm_string)
  raw = m.values_at(1)[0].to_f + (m.values_at(2)[0].to_f / 60)
  _nsew_signed_float(raw, sign_letter)
end

#_float(field) ⇒ Float

float or nil

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (Float)

    The value in the field or nil



162
163
164
165
# File 'lib/nmea_plus/message/base.rb', line 162

def _float(field)
  return nil if field.nil? || field.empty?
  field.to_f
end

#_hex_to_integer(field) ⇒ Integer

hex to int or nil

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (Integer)

    The value in the field or nil



178
179
180
181
# File 'lib/nmea_plus/message/base.rb', line 178

def _hex_to_integer(field)
  return nil if field.nil? || field.empty?
  field.hex
end

#_highest_contiguous_index(last_index) ⇒ Integer

Helper function to calculate the contiguous index

Parameters:

  • last_index (Integer)

    the index of the starting message

Returns:

  • (Integer)

    The highest contiguous sequence number of linked message parts

See Also:



119
120
121
122
123
124
# File 'lib/nmea_plus/message/base.rb', line 119

def _highest_contiguous_index(last_index)
  mn = message_number # just in case this is expensive to compute
  return last_index if mn - last_index != 1      # indicating a skip or restart
  return mn if @next_part.nil?                   # indicating we're the last message
  @next_part._highest_contiguous_index(mn)       # recurse down
end

#_integer(field) ⇒ Integer

integer or nil

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (Integer)

    The value in the field or nil



154
155
156
157
# File 'lib/nmea_plus/message/base.rb', line 154

def _integer(field)
  return nil if field.nil? || field.empty?
  field.to_i
end

#_interval_hms(field) ⇒ Time

time interval or nil (HHMMSS or HHMMSS.SS)

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (Time)

    The value in the field or nil



201
202
203
204
205
206
207
208
209
210
# File 'lib/nmea_plus/message/base.rb', line 201

def _interval_hms(field)
  return nil if field.nil? || field.empty?
  re_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
  begin
    hms = re_format.match(field)
    Time.new(0, 0, 0, hms[1].to_i, hms[2].to_i, hms[3].to_f)
  rescue
    nil
  end
end

#_nsew_signed_float(mixed_val, sign_letter = "") ⇒ Float

Use cardinal directions to assign positive or negative to mixed_val. Of possible directions NSEW (sign_letter) treat N/E as + and S/W as -

Parameters:

  • mixed_val (String)

    input value, can be string or float

  • sign_letter (String) (defaults to: "")

    can be N,S,E,W, or empty

Returns:

  • (Float)

    The input value signed as per the sign letter.



145
146
147
148
149
# File 'lib/nmea_plus/message/base.rb', line 145

def _nsew_signed_float(mixed_val, sign_letter = "")
  value = mixed_val.to_f
  value *= -1 if !sign_letter.empty? && "SW".include?(sign_letter.upcase)
  value
end

#_string(field) ⇒ String

string or nil

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (String)

    The value in the field or nil



170
171
172
173
# File 'lib/nmea_plus/message/base.rb', line 170

def _string(field)
  return nil if field.nil? || field.empty?
  field
end

#_utc_date_time(d_field, t_field) ⇒ Time

Returns The value in the fields, or nil if either is not provided.

Parameters:

  • d_field (String)

    the date value in the field to be checked

  • t_field (String)

    the time value in the field to be checked

Returns:

  • (Time)

    The value in the fields, or nil if either is not provided



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/nmea_plus/message/base.rb', line 215

def _utc_date_time(d_field, t_field)
  return nil if t_field.nil? || t_field.empty?
  return nil if d_field.nil? || d_field.empty?

  # get formats and time
  time_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
  date_format = /(\d{2})(\d{2})(\d{2})/

  # crunch numbers
  begin
    dmy = date_format.match(d_field)
    hms = time_format.match(t_field)
    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)
  rescue
    nil
  end
end

#_utctime_hms(field) ⇒ Time

utc time or nil (HHMMSS or HHMMSS.SS)

Parameters:

  • field (String)

    the value in the field to be checked

Returns:

  • (Time)

    The value in the field or nil



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/nmea_plus/message/base.rb', line 186

def _utctime_hms(field)
  return nil if field.nil? || field.empty?
  re_format = /(\d{2})(\d{2})(\d{2}(\.\d+)?)/
  now = Time.now
  begin
    hms = re_format.match(field)
    Time.new(now.year, now.month, now.day, hms[1].to_i, hms[2].to_i, hms[3].to_f)
  rescue
    nil
  end
end

#add_message_part(msg) ⇒ void

This method returns an undefined value.

Create a linked list of messages by appending a new message to the end of the chain that starts with this message. (O(n) implementation; message parts assumed to be < 10)

Parameters:



95
96
97
98
99
100
101
# File 'lib/nmea_plus/message/base.rb', line 95

def add_message_part(msg)
  if @next_part.nil?
    @next_part = msg
  else
    @next_part.add_message_part(msg)
  end
end

#all_checksums_ok?Boolean

return [bool] Whether the checksums for all available message parts are OK

Returns:

  • (Boolean)


64
65
66
67
68
# File 'lib/nmea_plus/message/base.rb', line 64

def all_checksums_ok?
  return false unless checksum_ok?
  return true if @next_part.nil?
  @next_part.all_checksums_ok?
end

#all_messages_received?bool

Returns Whether all messages in a multipart message have been received.

Returns:

  • (bool)

    Whether all messages in a multipart message have been received.



104
105
106
# File 'lib/nmea_plus/message/base.rb', line 104

def all_messages_received?
  total_messages == highest_contiguous_index
end

#calculated_checksumObject

return [String] The calculated checksum for this payload as a two-character string



71
72
73
# File 'lib/nmea_plus/message/base.rb', line 71

def calculated_checksum
  "%02x" % @payload.each_byte.map(&:ord).reduce(:^)
end

#checksum_ok?bool

Returns Whether the checksum calculated from the payload matches the checksum given in the message.

Returns:

  • (bool)

    Whether the checksum calculated from the payload matches the checksum given in the message



59
60
61
# File 'lib/nmea_plus/message/base.rb', line 59

def checksum_ok?
  calculated_checksum.upcase == checksum.upcase
end

#highest_contiguous_indexInteger

Returns The highest contiguous sequence number of linked message parts.

Returns:

  • (Integer)

    The highest contiguous sequence number of linked message parts

See Also:



111
112
113
# File 'lib/nmea_plus/message/base.rb', line 111

def highest_contiguous_index
  _highest_contiguous_index(0)
end