Class: NMEAPlus::Message::AIS::VDMPayload::Payload

Inherits:
Object
  • Object
show all
Defined in:
lib/nmea_plus/message/ais/vdm_payload/payload.rb

Overview

Basic tools for interpreting the armored (binary) payload encoding of AIS. This class provides convenience functions for accessing the fields as the appropriate data type, as well as logic for AIS bit-level formats

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePayload

Returns a new instance of Payload.



14
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 14

def initialize; end

Instance Attribute Details

#fill_bitsInteger

Returns The number of padding characters required to bring the payload to a 6 bit boundary.

Returns:

  • (Integer)

    The number of padding characters required to bring the payload to a 6 bit boundary



20
21
22
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 20

def fill_bits
  @fill_bits
end

#payload_bitstringString

Returns The raw “armored payload” in the original message.

Returns:

  • (String)

    The raw “armored payload” in the original message



17
18
19
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 17

def payload_bitstring
  @payload_bitstring
end

Class Method Details

.payload_reader(name, start_bit, length, formatter, fmt_arg = nil, fmt_arg2 = nil, fmt_arg3 = nil) ⇒ void

This method returns an undefined value.

Enable a shortcut syntax for AIS payload attributes, in the style of ‘attr_accessor` metaprogramming. This is used to create a named field pointing to a specific bit range in the payload, applying a specific formatting function with up to 3 arguments as necessary

Parameters:

  • name (String)

    What the accessor will be called

  • start_bit (Integer)

    The index of first bit of this field in the payload

  • length (Integer)

    The number of bits in this field

  • formatter (Symbol)

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

  • fmt_arg (defaults to: nil)

    Any argument necessary for the formatting function

  • fmt_arg2 (defaults to: nil)

    Any other argument necessary for the formatting function

  • fmt_arg3 (defaults to: nil)

    Any other argument necessary for the formatting function



36
37
38
39
40
41
42
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 36

def self.payload_reader(name, start_bit, length, formatter, fmt_arg = nil, fmt_arg2 = nil, fmt_arg3 = nil)
  args = [start_bit, length]
  args << fmt_arg unless fmt_arg.nil?
  args << fmt_arg2 unless fmt_arg2.nil?
  args << fmt_arg3 unless fmt_arg3.nil?
  self.class_eval("def #{name};#{formatter}(#{args.join(', ')});end")
end

Instance Method Details

#_2b_data_string(start, length) ⇒ String Also known as: _d

Return a string representing binary digits. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Returns:

  • (String)

    e.g. “0101010101011000”



214
215
216
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 214

def _2b_data_string(start, length)
  _access(start, length)
end

#_6b_ascii(ord) ⇒ String

Convert 6-bit ascii to a character, according to catb.org/gpsd/AIVDM.html#_ais_payload_data_types

Parameters:

  • ord (Integer)

    The 6-bit ascii code

Returns:

  • (String)

    the character for that code



54
55
56
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 54

def _6b_ascii(ord)
  '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !"#$%&\'()*+,-./0123456789:;<=>?'[ord]
end

#_6b_boolean(start, _) ⇒ bool Also known as: _b

Get the value of a bit in the payload. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • _ (Integer)

    Doesn’t matter. Here so signatures match; we hard-code 1 because it’s 1 bit.

Returns:

  • (bool)


196
197
198
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 196

def _6b_boolean(start, _)
  _access(start, 1) { |bits| bits.to_i == 1 }
end

#_6b_integer(start, length, equiv_nil = nil) ⇒ Integer Also known as: _i

perform a twos complement operation on part of the payload. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an integer value



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 124

def _6b_integer(start, length, equiv_nil = nil)
  case @payload_bitstring[start]
  when "0"
    _6b_unsigned_integer(start, length, equiv_nil)
  when "1"
    # MSB is 1 for negative
    # two's complement: flip bits, then add 1
    ret = _access(start, length) { |bits| (bits.tr("01", "10").to_i(2) + 1) * -1 }
    return nil if ret == equiv_nil
    ret
  end
end

#_6b_integer_scaled(start, length, denominator, equiv_nil = nil) ⇒ Integer Also known as: _I

scale an integer by dividing it by a denominator. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • denominator (Integer)

    The divisor to use in scaling down the result

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an integer value



144
145
146
147
148
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 144

def _6b_integer_scaled(start, length, denominator, equiv_nil = nil)
  ret = _6b_integer(start, length, equiv_nil)
  return nil if ret.nil?
  ret.to_f / denominator
end

#_6b_integer_scaled_shifted(start, length, denominator, shift, equiv_nil = nil) ⇒ Integer Also known as: _II

scale an integer by dividing it by a denominator. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • denominator (Integer)

    The divisor to use in scaling down the result

  • shift (Float)

    the amount to shift (up) the result by

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an integer value



171
172
173
174
175
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 171

def _6b_integer_scaled_shifted(start, length, denominator, shift, equiv_nil = nil)
  ret = _6b_integer_scaled(start, length, denominator, equiv_nil)
  return nil if ret.nil?
  ret + shift
end

#_6b_negated_boolean(start, _) ⇒ bool Also known as: _nb

Get the flipped value of a bit in the payload. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • _ (Integer)

    Doesn’t matter. Here so signatures match; we hard-code 1 because it’s 1 bit.

Returns:

  • (bool)


205
206
207
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 205

def _6b_negated_boolean(start, _)
  !_6b_boolean(start, 1)
end

#_6b_string(start, length) ⇒ String Also known as: _tt

pull out 6b chunks from the payload, then convert those to their more familar characters This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Returns:

  • (String)


75
76
77
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 75

def _6b_string(start, length)
  _bit_slices(start, length, 6).to_a.map(&:join).map { |x| _6b_ascii(x.to_i(2)) }.join
end

#_6b_string_nullterminated(start, length) ⇒ String Also known as: _t

convert a 6b string but trim off the 0s (‘@’). This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Returns:

  • (String)


102
103
104
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 102

def _6b_string_nullterminated(start, length)
  _6b_string(start, length).split("@", 2)[0]
end

#_6b_unsigned_integer(start, length, equiv_nil = nil) ⇒ Integer Also known as: _u, _e

directly convert a string to a binary number as you’d read it. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an unsigned integer value



112
113
114
115
116
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 112

def _6b_unsigned_integer(start, length, equiv_nil = nil)
  ret = _access(start, length) { |bits| bits.to_i(2) }
  return nil if ret == equiv_nil
  ret
end

#_6b_unsigned_integer_scaled(start, length, denominator, equiv_nil = nil) ⇒ Integer Also known as: _U

scale an unsigned integer by dividing it by a denominator. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • denominator (Integer)

    The divisor to use in scaling down the result

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an integer value



157
158
159
160
161
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 157

def _6b_unsigned_integer_scaled(start, length, denominator, equiv_nil = nil)
  ret = _6b_unsigned_integer(start, length, equiv_nil)
  return nil if ret.nil?
  ret.to_f / denominator
end

#_6b_unsigned_integer_scaled_shifted(start, length, denominator, shift, equiv_nil = nil) ⇒ Integer Also known as: _UU

scale an unsigned integer by dividing it by a denominator. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

  • denominator (Integer)

    The divisor to use in scaling down the result

  • shift (Float)

    the amount to shift (up) the result by

  • equiv_nil (Integer) (defaults to: nil)

    If applicable, the value for this field that would indicate nil

Returns:

  • (Integer)

    an integer value



185
186
187
188
189
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 185

def _6b_unsigned_integer_scaled_shifted(start, length, denominator, shift, equiv_nil = nil)
  ret = _6b_unsigned_integer_scaled(start, length, denominator, equiv_nil)
  return nil if ret.nil?
  ret + shift
end

#_8b_data_string(start, length) ⇒ String Also known as: _T

pull out 8b chunks from the payload, then convert those to their more familar characters. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Returns:

  • (String)


84
85
86
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 84

def _8b_data_string(start, length)
  _bit_slices(start, length, 8).to_a.map(&:join).map { |x| x.to_i(2).chr }.join
end

#_access(start, length) {|String| ... } ⇒ Object

Access part of the payload. If there aren’t bytes, there, return nil. Else, execute a block

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Yields:

  • (String)

    A binary coded string (“010010101” etc)

Returns:

  • Nil or whatever is yielded by the block



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

def _access(start, length)
  part = @payload_bitstring[start, length]
  return nil if part.nil? || part.empty?
  yield part
end

#_bit_slices(start, length, chunk_size) ⇒ Array<String>

Slice a part of the payload into binary chunks of a given size. This function is meant to be passed as a formatter to payload_reader.

Parameters:

  • start (Integer)

    The index of the first bit in the payload field

  • length (Integer)

    The number of bits in the payload field

Returns:

  • (Array<String>)

    Strings representing binary (“01010101” etc) for each slice



93
94
95
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 93

def _bit_slices(start, length, chunk_size)
  _access(start, length) { |bits| bits.chars.each_slice(chunk_size) }
end

#_get_date_mdhm(month, day, hour, minute) ⇒ Object

Get the date value of a month/day/hour/minute package This function is meant to be used for commonly-found date operations in which year, seconds, and timezone are not specified.

Parameters:

  • month (Integer)

    the month number, 1-indexed, optional

  • day (Integer)

    the day number, 1-indexed

  • hour (Integer)

    the hour number, 0-indexed

  • minute (Integer)

    the minute number, 0-indexed



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 240

def _get_date_mdhm(month, day, hour, minute)
  now = Time.now
  month = now.month if month.nil?

  return nil if month.zero?
  return nil if day.zero?
  return nil if hour == 24
  return nil if minute == 60

  # try to be smart about picking a year
  rollover = 0
  rollover = 1 if now.month > month
  rollover = -1 if now.month == 1 && month == 12
  Time.new(now.year + rollover, month, day, hour, minute, 0, '+00:00')
end

#_object_by_name(class_identifier) ⇒ Object

Return an object by its class name, or nil if it isn’t defined



45
46
47
48
49
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 45

def _object_by_name(class_identifier)
  Object::const_get(class_identifier).new
rescue ::NameError
  nil
end