class XBee::Packet

Constants

ESCAPE
ESCAPE_BYTES
ESCAPE_XOR
START_BYTE
XOFF
XON

Public Class Methods

checksum(bytes) click to toggle source
# File lib/xbee/packet.rb, line 23
def checksum(bytes)
        255 - bytes.reduce(&:+) % 256
end
escape(bytes, options = {}) click to toggle source

Escapes an array of bytes. Ignores the first byte unless ignore_first_byte is set to false in the options hash. @param bytes [Array<Integer>] The array of bytes to escape. @param options [Hash] Options hash. @option options [Boolean] :ignore_first_byte If the first byte should be ignored (usually true for handling an entire packet since the first byte is START_BYTE). Default true. @return [Array<Integer>] Escaped bytes.

# File lib/xbee/packet.rb, line 33
def escape(bytes, options = {})
        ignore_first_byte = options.fetch :ignore_first_byte, true

        prepend = []
        if ignore_first_byte
                bytes = bytes.dup
                prepend = [bytes.shift]
        end

        prepend + bytes.reduce([]) do |escaped, b|
                if ESCAPE_BYTES.include?(b)
                        escaped << ESCAPE
                        escaped << (ESCAPE_XOR ^ b)
                else
                        escaped << b
                end
        end
end
from_byte_enum(bytes) click to toggle source
# File lib/xbee/packet.rb, line 104
def from_byte_enum(bytes)
        begin
                loop until bytes.next == START_BYTE
                length = (next_unescaped_byte(bytes) << 8) + next_unescaped_byte(bytes)
        rescue
                raise IOError, 'Packet is too short, unable to read length fields.'
        end
        begin
                data = (1..length).map { next_unescaped_byte bytes }
        rescue
                raise IOError, "Expected data length to be #{length} but got fewer bytes"
        end
        begin
                crc = next_unescaped_byte bytes
        rescue
                raise IOError, 'Packet is too short, unable to read checksum'
        end
        if crc != checksum(data)
                raise IOError, "Expected checksum to be 0x#{checksum(data).to_s 16} but was 0x#{crc.to_s 16}"
        end
        new data
end
from_bytes(bytes) click to toggle source
# File lib/xbee/packet.rb, line 74
def from_bytes(bytes)
        if bytes.length < 4
                raise ArgumentError, "Packet is too short (only #{bytes.length} bytes)"
        end
        if bytes[0] != START_BYTE
                raise ArgumentError, 'Missing start byte'
        end
        data = [START_BYTE] + unescape(bytes[1..-1])
        length = (data[1] << 8) + data[2]
        if length != data.length - 4
                raise ArgumentError, "Expected data length to be #{length} but was #{data.length - 4}"
        end
        crc = checksum(data[3..-2])
        if crc != data[-1]
                raise ArgumentError, "Expected checksum to be 0x#{crc.to_s 16} but was 0x#{data[-1].to_s 16}"
        end
        new data[3..-2]
end
new(data) click to toggle source

@param data [Array<Integer>] Byte array

# File lib/xbee/packet.rb, line 130
def initialize(data)
        @data = data
end
next_unescaped_byte(bytes) click to toggle source
# File lib/xbee/packet.rb, line 94
def next_unescaped_byte(bytes)
        byte = bytes.next
        if byte == ESCAPE
                0x20 ^ bytes.next
        else
                byte
        end
end
special_byte?(byte) click to toggle source

@param byte [Integer]

# File lib/xbee/packet.rb, line 18
def special_byte?(byte)
        ESCAPE_BYTES.include? byte
end
unescape(bytes) click to toggle source

When provided a byte array that has escaped data, this returns a new byte array with just the raw data. @param bytes [Array<Integer>] Array of bytes to unescape. @return [Array<Integer>] Array of unescaped bytes.

# File lib/xbee/packet.rb, line 56
def unescape(bytes)
        byte_escaped = false
        bytes.reduce([]) do |unescaped, b|
                if byte_escaped
                        unescaped << (0x20 ^ b)
                        byte_escaped = false
                else
                        if b == ESCAPE
                                byte_escaped = true
                        else
                                unescaped << b
                        end
                end
                unescaped
        end
end

Public Instance Methods

==(other) click to toggle source
# File lib/xbee/packet.rb, line 166
def ==(other)
        data == other.data
end
bytes() click to toggle source
# File lib/xbee/packet.rb, line 150
def bytes
        [START_BYTE, length >> 8, length & 0xff] + @data + [checksum]
end
bytes_escaped() click to toggle source
# File lib/xbee/packet.rb, line 155
def bytes_escaped
        [START_BYTE] + bytes[1..-1].flat_map do |b|
                if self.class.special_byte?(b)
                        [ESCAPE, 0x20 ^ b]
                else
                        b
                end
        end
end
checksum() click to toggle source
# File lib/xbee/packet.rb, line 145
def checksum
        Packet.checksum @data
end
data() click to toggle source
# File lib/xbee/packet.rb, line 135
def data
        @data
end
length() click to toggle source
# File lib/xbee/packet.rb, line 140
def length
        @data.length
end
to_s() click to toggle source
# File lib/xbee/packet.rb, line 171
def to_s
        'Packet [' + data.map { |b| "0x#{b.to_s 16}" }.join(', ') + ']'
end