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/mqtt/sn/packet.rb, line 38
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/mqtt/sn/packet.rb, line 19
def self.parse(buffer)
  # Parse the fixed header (length and type)
  length, type_id, body = buffer.unpack('CCa*')
  length, type_id, body = buffer.unpack('xnCa*') if length == 1

  # Double-check the length
  raise ProtocolException, 'Length of packet is not the same as the length header' if buffer.length != length

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

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

  packet
end

Public Instance Methods

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

Serialise the packet

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

  # Build up the body length field bytes
  body_length = body.length
  raise 'MQTT-SN Packet is too big, maximum packet body size is 65531' if body_length > 65_531

  if 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/mqtt/sn/packet.rb, line 49
def type_id
  PACKET_TYPES.each_pair do |key, value|
    return key if instance_of?(value)
  end
  raise "Invalid packet type: #{self.class}"
end
update_attributes(attr = {}) click to toggle source
# File lib/mqtt/sn/packet.rb, line 42
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/mqtt/sn/packet.rb, line 96
def encode_body
  '' # No body by default
end
encode_flags() click to toggle source
# File lib/mqtt/sn/packet.rb, line 100
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
  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/mqtt/sn/packet.rb, line 148
def encode_topic
  case topic_id_type
  when :normal
    topic_name
  when :short
    if topic_name.nil?
      topic_id
    else
      topic_name
    end
  when :predefined
    [topic_id].pack('n')
  end
end
encode_topic_id() click to toggle source
# File lib/mqtt/sn/packet.rb, line 125
def encode_topic_id
  if topic_id_type == :short
    raise "topic_id must be an String for type #{topic_id_type}" unless topic_id.is_a?(String)

    (topic_id[0].ord << 8) + topic_id[1].ord
  else
    raise "topic_id must be an Integer for type #{topic_id_type}" unless topic_id.is_a?(Integer)

    topic_id
  end
end
parse_flags(flags) click to toggle source
# File lib/mqtt/sn/packet.rb, line 76
def parse_flags(flags)
  self.duplicate = ((flags & 0x80) >> 7) == 0x01
  self.qos = (flags & 0x60) >> 5
  self.qos = -1 if qos == 3
  self.retain = ((flags & 0x10) >> 4) == 0x01
  self.request_will = ((flags & 0x08) >> 3) == 0x01
  self.clean_session = ((flags & 0x04) >> 2) == 0x01

  self.topic_id_type =
    case (flags & 0x03)
    when 0x0
      :normal
    when 0x1
      :predefined
    when 0x2
      :short
    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/mqtt/sn/packet.rb, line 165
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.unpack1('n')
  end
end
parse_topic_id(topic_id) click to toggle source
# File lib/mqtt/sn/packet.rb, line 137
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