Class: XBee::Packet
- Inherits:
-
Object
- Object
- XBee::Packet
- Defined in:
- lib/xbee/packet.rb
Constant Summary collapse
- START_BYTE =
0x7E
- ESCAPE =
0x7D
- XON =
0x11- XOFF =
0x13- ESCAPE_XOR =
0x20- ESCAPE_BYTES =
[ START_BYTE, ESCAPE, XON, XOFF ].freeze
Class Method Summary collapse
- .checksum(bytes) ⇒ Object
-
.escape(bytes, options = {}) ⇒ Array<Integer>
Escapes an array of bytes.
- .from_byte_enum(bytes) ⇒ Object
- .from_bytes(bytes) ⇒ Object
- .next_unescaped_byte(bytes) ⇒ Object
- .special_byte?(byte) ⇒ Boolean
-
.unescape(bytes) ⇒ Array<Integer>
When provided a byte array that has escaped data, this returns a new byte array with just the raw data.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #bytes ⇒ Object
- #bytes_escaped ⇒ Object
- #checksum ⇒ Object
- #data ⇒ Object
-
#initialize(data) ⇒ Packet
constructor
A new instance of Packet.
- #length ⇒ Object
- #to_s ⇒ Object
Constructor Details
#initialize(data) ⇒ Packet
Returns a new instance of Packet.
130 131 132 |
# File 'lib/xbee/packet.rb', line 130 def initialize(data) @data = data end |
Class Method Details
.checksum(bytes) ⇒ Object
23 24 25 |
# File 'lib/xbee/packet.rb', line 23 def checksum(bytes) 255 - bytes.reduce(&:+) % 256 end |
.escape(bytes, options = {}) ⇒ Array<Integer>
Escapes an array of bytes. Ignores the first byte unless ignore_first_byte is set to false in the options hash.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/xbee/packet.rb', line 33 def escape(bytes, = {}) ignore_first_byte = .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) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# 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) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# 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 |
.next_unescaped_byte(bytes) ⇒ Object
94 95 96 97 98 99 100 101 |
# 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) ⇒ Boolean
18 19 20 |
# File 'lib/xbee/packet.rb', line 18 def special_byte?(byte) ESCAPE_BYTES.include? byte end |
.unescape(bytes) ⇒ Array<Integer>
When provided a byte array that has escaped data, this returns a new byte array with just the raw data.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# 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 |
Instance Method Details
#==(other) ⇒ Object
166 167 168 |
# File 'lib/xbee/packet.rb', line 166 def ==(other) data == other.data end |
#bytes ⇒ Object
150 151 152 |
# File 'lib/xbee/packet.rb', line 150 def bytes [START_BYTE, length >> 8, length & 0xff] + @data + [checksum] end |
#bytes_escaped ⇒ Object
155 156 157 158 159 160 161 162 163 |
# 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 ⇒ Object
145 146 147 |
# File 'lib/xbee/packet.rb', line 145 def checksum Packet.checksum @data end |
#data ⇒ Object
135 136 137 |
# File 'lib/xbee/packet.rb', line 135 def data @data end |
#length ⇒ Object
140 141 142 |
# File 'lib/xbee/packet.rb', line 140 def length @data.length end |
#to_s ⇒ Object
171 172 173 |
# File 'lib/xbee/packet.rb', line 171 def to_s 'Packet [' + data.map { |b| "0x#{b.to_s 16}" }.join(', ') + ']' end |