Module: E3DCMqtt::RSCP::MessageCodec

Defined in:
lib/e3dc_mqtt/rscp/message.rb

Class Method Summary collapse

Class Method Details

.decode(bytes, offset = 0) ⇒ Object

Decode one message starting at ‘offset` within `bytes`. Returns [Message, new_offset].



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/e3dc_mqtt/rscp/message.rb', line 96

def decode(bytes, offset = 0)
  if bytes.bytesize - offset < DATA_HEADER_SIZE
    raise InvalidFrameLength, "truncated message header"
  end

  tag       = bytes.byteslice(offset, 4).unpack1("L<")
  data_type = bytes.getbyte(offset + 4)
  length    = bytes.byteslice(offset + 5, 2).unpack1("S<")
  payload_offset = offset + DATA_HEADER_SIZE

  if length > DATA_MAX_DATA_SIZE
    raise DataLimitExceeded, "message payload size %d exceeds max" % length
  end

  expected = DataType.fixed_length(data_type)
  if expected && expected != 0 && expected != length
    raise DataLimitExceeded, "length %d does not match fixed length of %s" %
      [length, DataType.name(data_type)]
  end

  if bytes.bytesize < payload_offset + length
    raise InvalidFrameLength, "truncated message payload"
  end

  value =
    if data_type == DataType::CONTAINER
      decode_container(bytes, payload_offset, length)
    else
      DataType.unpack(data_type, bytes.byteslice(payload_offset, length))
    end

  [Message.new(tag: tag, data_type: data_type, value: value), payload_offset + length]
end

.decode_all(bytes, offset, total_length) ⇒ Object

Raises:



130
131
132
133
134
135
136
137
138
139
140
# File 'lib/e3dc_mqtt/rscp/message.rb', line 130

def decode_all(bytes, offset, total_length)
  messages = []
  stop = offset + total_length
  while offset < stop
    m, offset = decode(bytes, offset)
    messages << m
  end
  raise InvalidFrameLength, "message data overflowed block" if offset != stop

  messages
end

.decode_container(bytes, offset, length) ⇒ Object



142
143
144
# File 'lib/e3dc_mqtt/rscp/message.rb', line 142

def decode_container(bytes, offset, length)
  decode_all(bytes, offset, length)
end

.encode(message) ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/e3dc_mqtt/rscp/message.rb', line 73

def encode(message)
  body = encode_value(message.data_type, message.value)
  if body.bytesize > DATA_MAX_DATA_SIZE
    raise DataLimitExceeded, "message body size %d exceeds max %d" % [body.bytesize, DATA_MAX_DATA_SIZE]
  end

  [message.tag].pack("L<") + [message.data_type].pack("C") + [body.bytesize].pack("S<") + body
end

.encode_all(messages) ⇒ Object



82
83
84
# File 'lib/e3dc_mqtt/rscp/message.rb', line 82

def encode_all(messages)
  messages.map { |m| encode(m) }.join.b
end

.encode_value(data_type, value) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/e3dc_mqtt/rscp/message.rb', line 86

def encode_value(data_type, value)
  if data_type == DataType::CONTAINER
    encode_all(value || [])
  else
    DataType.pack(data_type, value)
  end
end