class MQTT::SN::Packet

Class representing a MQTT::SN Packet Performs binary encoding and decoding of headers

Constants

DEFAULTS

Attributes

clean_session[RW]
duplicate[RW]
qos[RW]
request_will[RW]
retain[RW]
topic_id_type[RW]

Public Class Methods

new(args={}) click to toggle source

Create a new empty packet

# File lib/mqttbridge/sn/packet.rb, line 42
def initialize(args={})
  update_attributes(self.class::DEFAULTS.merge(args))
end
parse(buffer) click to toggle source

Parse buffer into new packet object

# File lib/mqttbridge/sn/packet.rb, line 17
def self.parse(buffer)
  # Parse the fixed header (length and type)
  length,type_id,body = buffer.unpack('CCa*')
  if length == 1
    length,type_id,body = buffer.unpack('xnCa*')
  end

  # Double-check the length
  if buffer.length != length
    raise ProtocolException.new("Length of packet is not the same as the length header")
  end

  packet_class = PACKET_TYPES[type_id]
  if packet_class.nil?
    raise ProtocolException.new("Invalid packet type identifier: #{type_id}")
  end

  # Create a new packet object
  packet = packet_class.new
  packet.parse_body(body)

  return packet
end

Public Instance Methods

parse_body(buffer) click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 76
def parse_body(buffer)
end
to_s() click to toggle source

Serialise the packet

# File lib/mqttbridge/sn/packet.rb, line 61
def to_s
  # Get the packet's variable header and payload
  body = self.encode_body

  # Build up the body length field bytes
  body_length = body.length
  if body_length > 65531
    raise "MQTT-SN Packet is too big, maximum packet body size is 65531"
  elsif body_length > 253
    [0x01, body_length + 4, type_id].pack('CnC') + body
  else
    [body_length + 2, type_id].pack('CC') + body
  end
end
type_id() click to toggle source

Get the identifer for this packet type

# File lib/mqttbridge/sn/packet.rb, line 53
def type_id
  PACKET_TYPES.each_pair do |key, value|
    return key if self.class == value
  end
  raise "Invalid packet type: #{self.class}"
end
update_attributes(attr={}) click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 46
def update_attributes(attr={})
  attr.each_pair do |k,v|
    send("#{k}=", v)
  end
end

Protected Instance Methods

encode_body() click to toggle source

Get serialisation of packet's body (variable header and payload)

# File lib/mqttbridge/sn/packet.rb, line 101
def encode_body
  '' # No body by default
end
encode_flags() click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 105
def encode_flags
  flags = 0x00
  flags += 0x80 if duplicate
  case qos
    when -1
      flags += 0x60
    when 1
      flags += 0x20
    when 2
      flags += 0x40
  end
  flags += 0x10 if retain
  flags += 0x08 if request_will
  flags += 0x04 if clean_session
  case topic_id_type
    when :normal
      flags += 0x0
    when :predefined
      flags += 0x1
    when :short
      flags += 0x2
  end
  return flags
end
encode_topic() click to toggle source

Used where a field can either be a Topic Id or a Topic Name (the Subscribe and Unsubscribe packet types)

# File lib/mqttbridge/sn/packet.rb, line 155
def encode_topic
  case topic_id_type
    when :normal
      topic_name
    when :short
      unless topic_name.nil?
        topic_name
      else
        topic_id
      end
    when :predefined
      [topic_id].pack('n')
  end
end
encode_topic_id() click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 130
def encode_topic_id
  if topic_id_type == :short
    unless topic_id.is_a?(String)
      raise "topic_id must be an String for type #{topic_id_type}"
    end
    (topic_id[0].ord << 8) + topic_id[1].ord
  else
    unless topic_id.is_a?(Integer)
      raise "topic_id must be an Integer for type #{topic_id_type}"
    end
    topic_id
  end
end
parse_flags(flags) click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 81
def parse_flags(flags)
  self.duplicate = ((flags & 0x80) >> 7) == 0x01
  self.qos = (flags & 0x60) >> 5
  self.qos = -1 if self.qos == 3
  self.retain = ((flags & 0x10) >> 4) == 0x01
  self.request_will = ((flags & 0x08) >> 3) == 0x01
  self.clean_session = ((flags & 0x04) >> 2) == 0x01
  case (flags & 0x03)
    when 0x0
      self.topic_id_type = :normal
    when 0x1
      self.topic_id_type = :predefined
    when 0x2
      self.topic_id_type = :short
    else
      self.topic_id_type = nil
  end
end
parse_topic(topic) click to toggle source

Used where a field can either be a Topic Id or a Topic Name (the Subscribe and Unsubscribe packet types)

# File lib/mqttbridge/sn/packet.rb, line 172
def parse_topic(topic)
  case topic_id_type
    when :normal
      self.topic_name = topic
    when :short
      self.topic_name = topic
      self.topic_id = topic
    when :predefined
      self.topic_id = topic.unpack('n').first
  end
end
parse_topic_id(topic_id) click to toggle source
# File lib/mqttbridge/sn/packet.rb, line 144
def parse_topic_id(topic_id)
  if topic_id_type == :short
    int = topic_id.to_i
    self.topic_id = [(int >> 8) & 0xFF, int & 0xFF].pack('CC')
  else
    self.topic_id = topic_id
  end
end