Class: XBeeRuby::Packet

Inherits:
Object
  • Object
show all
Defined in:
lib/xbee-ruby/packet.rb

Constant Summary collapse

START_BYTE =
0x7e
ESCAPE =
0x7d
XON =
0x11
XOFF =
0x13

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Packet

Returns a new instance of Packet.



90
91
92
# File 'lib/xbee-ruby/packet.rb', line 90

def initialize data
	@data = data
end

Class Method Details

.checksum(bytes) ⇒ Object



24
25
26
# File 'lib/xbee-ruby/packet.rb', line 24

def self.checksum bytes
	255 - bytes.reduce(&:+) % 256
end

.from_byte_enum(bytes) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/xbee-ruby/packet.rb', line 67

def self.from_byte_enum bytes
	begin
		loop until bytes.next == Packet::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 != Packet::checksum(data) then
		raise IOError, "Excpected checksum to be 0x#{Packet::checksum(data).to_s 16} but was 0x#{crc.to_s 16}"
	end
	Packet.new data
end

.from_bytes(bytes) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/xbee-ruby/packet.rb', line 39

def self.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
	self.new data[3..-2]
end

.next_unescaped_byte(bytes) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/xbee-ruby/packet.rb', line 58

def self.next_unescaped_byte bytes
	byte = bytes.next
	if byte == ESCAPE then
		0x20 ^ bytes.next
	else
		byte
	end
end

.special_byte?(byte) ⇒ Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/xbee-ruby/packet.rb', line 20

def self.special_byte? byte
	[START_BYTE, ESCAPE, XON, XOFF].include? byte
end

.unescape(bytes) ⇒ Object



28
29
30
31
32
33
34
35
36
37
# File 'lib/xbee-ruby/packet.rb', line 28

def self.unescape bytes
	bytes.inject([]) do |unescaped, b|
		if unescaped.last == ESCAPE
			unescaped.pop
			unescaped << (0x20 ^ b)
		else
			unescaped << b
		end
	end
end

Instance Method Details

#==(other) ⇒ Object



119
120
121
# File 'lib/xbee-ruby/packet.rb', line 119

def == other
	self.data == other.data
end

#bytesObject



106
107
108
# File 'lib/xbee-ruby/packet.rb', line 106

def bytes
	[START_BYTE, length >> 8, length & 0xff] + @data + [checksum]
end

#bytes_escapedObject



110
111
112
113
114
115
116
117
# File 'lib/xbee-ruby/packet.rb', line 110

def bytes_escaped
	[START_BYTE] + bytes[1..-1].flat_map { |b|
		if Packet.special_byte?(b) then
			[ESCAPE, 0x20 ^ b]
		else
			b
		end }
end

#checksumObject



102
103
104
# File 'lib/xbee-ruby/packet.rb', line 102

def checksum
	Packet.checksum @data
end

#dataObject



94
95
96
# File 'lib/xbee-ruby/packet.rb', line 94

def data
	@data
end

#lengthObject



98
99
100
# File 'lib/xbee-ruby/packet.rb', line 98

def length
	@data.length
end

#to_sObject



123
124
125
# File 'lib/xbee-ruby/packet.rb', line 123

def to_s
	'Packet [' + data.map { |b| "0x#{b.to_s 16}" }.join(', ') + ']'
end