class BWA::Message

Attributes

raw_data[R]
src[R]

Public Class Methods

format_duration(hours, minutes) click to toggle source
# File lib/bwa/message.rb, line 97
def format_duration(hours, minutes)
  "#{hours}:#{"%02d" % minutes}"
end
format_time(hour, minute, twenty_four_hour_time = true) click to toggle source
# File lib/bwa/message.rb, line 86
def format_time(hour, minute, twenty_four_hour_time = true)
  if twenty_four_hour_time
    print_hour = "%02d" % hour
  else
    print_hour = hour % 12
    print_hour = 12 if print_hour == 0
    am_pm = (hour >= 12 ? "PM" : "AM")
  end
  "#{print_hour}:#{"%02d" % minute}#{am_pm}"
end
inherited(klass) click to toggle source
# File lib/bwa/message.rb, line 18
def inherited(klass)
  @messages ||= []
  @messages << klass
end
new() click to toggle source
# File lib/bwa/message.rb, line 104
def initialize
  # most messages we're sending come from this address
  @src = 0x0a
end
parse(data) click to toggle source
# File lib/bwa/message.rb, line 23
def parse(data)
  offset = -1
  message_type = length = message_class = nil
  loop do
    offset += 1
    return nil if data.length - offset < 5

    # Keep scanning until message start char
    next unless data[offset] == '~'

    # Read length (safe since we have at least 5 chars)
    length = data[offset + 1].ord

    # No message is this short or this long; keep scanning
    next if length < 5 or length >= '~'.ord

    # don't have enough data for what this message wants;
    # return and hope for more (yes this might cause a
    # delay, but the protocol is very chatty so it won't
    # be long)
    return nil if length + 2 > data.length - offset

    # Not properly terminated; keep scanning
    next unless data[offset + length + 1] == '~'

    # Not a valid checksum; keep scanning
    next unless CRC.checksum(data.slice(offset + 1, length - 1)) == data[offset + length].ord

    # Got a valid message!
    break
  end

  puts "discarding invalid data prior to message #{data[0...offset].unpack('H*').first}" unless offset == 0
  #puts "read #{data.slice(offset, length + 2).unpack('H*').first}"

  src = data[offset + 2].ord
  message_type = data.slice(offset + 3, 2)
  klass = @messages.find { |k| k::MESSAGE_TYPE == message_type }


  return [nil, offset + length + 2] if [
                "\xbf\x00".force_encoding(Encoding::ASCII_8BIT),
                "\xbf\xe1".force_encoding(Encoding::ASCII_8BIT),
                "\xbf\x07".force_encoding(Encoding::ASCII_8BIT)].include?(message_type)

  if klass
    valid_length = if klass::MESSAGE_LENGTH.respond_to?(:include?)
      klass::MESSAGE_LENGTH.include?(length - 5)
    else
      length - 5 == klass::MESSAGE_LENGTH
    end
    raise InvalidMessage.new("Unrecognized data length (#{length}) for message #{klass}", data) unless valid_length
  else
    klass = Unrecognized
  end

  message = klass.new
  message.parse(data.slice(offset + 5, length - 5))
  message.instance_variable_set(:@raw_data, data.slice(offset, length + 2))
  message.instance_variable_set(:@src, src)
  [message, offset + length + 2]
end

Public Instance Methods

inspect() click to toggle source
# File lib/bwa/message.rb, line 119
def inspect
  "#<#{self.class.name} #{raw_data.unpack("H*").first}>"
end
parse(_data) click to toggle source
# File lib/bwa/message.rb, line 109
def parse(_data)
end
serialize(message = "") click to toggle source
# File lib/bwa/message.rb, line 112
def serialize(message = "")
  length = message.length + 5
  full_message = "#{length.chr}#{src.chr}#{self.class::MESSAGE_TYPE}#{message}".force_encoding(Encoding::ASCII_8BIT)
  checksum = CRC.checksum(full_message)
  "\x7e#{full_message}#{checksum.chr}\x7e".force_encoding(Encoding::ASCII_8BIT)
end