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”



216
217
218
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 216

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



56
57
58
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 56

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)


198
199
200
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 198

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



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

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



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

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



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

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)


207
208
209
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 207

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)


77
78
79
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 77

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)


104
105
106
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 104

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



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

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



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

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



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

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)


86
87
88
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 86

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



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

def _access(start, length)
  part = @payload_bitstring[start, length]
  return nil if part.nil? || part.empty?
  block_given? ? (yield part) : 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



95
96
97
# File 'lib/nmea_plus/message/ais/vdm_payload/payload.rb', line 95

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



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

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

Parameters:

  • class_identifier (String)

    The ruby class identifier

Returns:

  • (Object)

    An object of the given class



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

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