xbee-ruby 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 321bcafd8643eeefad99385371c041eb2b78df6c
4
+ data.tar.gz: cafca7e2d4bbc9b718ba7c733fc9a0c5e9b00064
5
+ SHA512:
6
+ metadata.gz: dfcdfa8f34eef91c61d0f67e19063e52bdb0e2e58ca5b6196349a5000ad30d88f6c47c1dc4c2abe5f58109ee90ad65d0d9b2af141cdfe91934fff7aebfe33999
7
+ data.tar.gz: b47dbe7c9ffb11660284bc1cebd790964064b82d56c1433dabed054191a86a280d41974c273659e608814d1c8a7c2e8dacf81ce8340fad3eb3053086a1442561
data/lib/xbee-ruby.rb ADDED
@@ -0,0 +1,19 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'serialport'
12
+ require 'xbee-ruby/version'
13
+ require 'xbee-ruby/address_16'
14
+ require 'xbee-ruby/address_64'
15
+ require 'xbee-ruby/tx_request'
16
+ require 'xbee-ruby/tx_response'
17
+ require 'xbee-ruby/rx_response'
18
+ require 'xbee-ruby/modem_status_response'
19
+ require 'xbee-ruby/xbee'
@@ -0,0 +1,53 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/adress'
12
+
13
+ module XBeeRuby
14
+
15
+ class Address16 < Address
16
+
17
+ def initialize msb, lsb
18
+ @address = [msb, lsb]
19
+ end
20
+
21
+ def self.from_s string
22
+ if matcher = /^(\h\h)[^\h]*(\h\h)$/.match(string)
23
+ self.new *(matcher[1..2].map &:hex)
24
+ else
25
+ raise ArgumentError, "#{string} is not a valid 16-bit address string"
26
+ end
27
+ end
28
+
29
+ def self.from_a array
30
+ if array.length == 2 && array.all? {|x| (0..255).cover? x }
31
+ self.new *array
32
+ else
33
+ raise ArgumentError, "#{array} is not a valid 16-bit address array"
34
+ end
35
+ end
36
+
37
+ def to_s
38
+ '%02x%02x' % @address
39
+ end
40
+
41
+ def to_a
42
+ @address
43
+ end
44
+
45
+ def == other
46
+ to_a == other.to_a
47
+ end
48
+
49
+ BROADCAST = Address16.new 0xff, 0xfe
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,53 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/adress'
12
+
13
+ module XBeeRuby
14
+
15
+ class Address64 < Address
16
+
17
+ def initialize b1, b2, b3, b4, b5, b6, b7, b8
18
+ @address = [b1, b2, b3, b4, b5, b6, b7, b8]
19
+ end
20
+
21
+ def self.from_s string
22
+ if matcher = /^(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)[^\h]*(\h\h)$/.match(string)
23
+ self.new *(matcher[1..8].map &:hex)
24
+ else
25
+ raise ArgumentError, "#{string} is not a valid 64-bit address string"
26
+ end
27
+ end
28
+
29
+ def self.from_a array
30
+ if array.length == 8 && array.all? {|x| (0..255).cover? x }
31
+ self.new *array
32
+ else
33
+ raise ArgumentError, "#{array} is not a valid 64-bit address array"
34
+ end
35
+ end
36
+
37
+ def to_a
38
+ @address
39
+ end
40
+
41
+ def == other
42
+ to_a == other.to_a
43
+ end
44
+
45
+ def to_s
46
+ ('%02x' * 8) % @address
47
+ end
48
+
49
+ BROADCAST = Address64.new 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
50
+ COORDINATOR = Address64.new 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
51
+ end
52
+
53
+ end
@@ -0,0 +1,21 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ module XBeeRuby
12
+
13
+ class Address
14
+
15
+ def to_a
16
+ raise 'Override to return the address as a byte array'
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,34 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/response'
12
+
13
+ module XBeeRuby
14
+
15
+ class ModemStatusResponse < Response
16
+
17
+ frame_type 0x8a
18
+
19
+ attr_reader :modem_status
20
+
21
+ def initialize bytes
22
+ @modem_status = bytes[1]
23
+ end
24
+
25
+ def == other
26
+ other.class == ModemStatusResponse && self.modem_status == other.modem_status
27
+ end
28
+
29
+ def to_s
30
+ "ModemStatusResponse[#{super}](modem_status=0x#{modem_status})"
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,128 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ module XBeeRuby
12
+
13
+ class Packet
14
+
15
+ START_BYTE = 0x7e
16
+ ESCAPE = 0x7d
17
+ XON = 0x11
18
+ XOFF = 0x13
19
+
20
+ def self.special_byte? byte
21
+ [START_BYTE, ESCAPE, XON, XOFF].include? byte
22
+ end
23
+
24
+ def self.checksum bytes
25
+ 255 - bytes.reduce(&:+) % 256
26
+ end
27
+
28
+ def self.unescape bytes
29
+ bytes.inject([]) do |unescaped, b|
30
+ if unescaped.last == ESCAPE
31
+ unescaped.pop
32
+ unescaped << (0x20 ^ b)
33
+ else
34
+ unescaped << b
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.from_bytes bytes
40
+ if bytes.length < 4
41
+ raise ArgumentError, "Packet is too short (only #{bytes.length} bytes)"
42
+ end
43
+ if bytes[0] != START_BYTE
44
+ raise ArgumentError, 'Missing start byte'
45
+ end
46
+ data = [START_BYTE] + unescape(bytes[1..-1])
47
+ length = (data[1] << 8) + data[2]
48
+ if length != data.length - 4
49
+ raise ArgumentError, "Expected data length to be #{length} but was #{data.length - 4}"
50
+ end
51
+ crc = checksum(data[3..-2])
52
+ if crc != data[-1]
53
+ raise ArgumentError, "Expected checksum to be 0x#{crc.to_s 16} but was 0x#{data[-1].to_s 16}"
54
+ end
55
+ self.new data[3..-2]
56
+ end
57
+
58
+ def self.next_unescaped_byte bytes
59
+ byte = bytes.next
60
+ if byte == ESCAPE then
61
+ 0x20 ^ bytes.next
62
+ else
63
+ byte
64
+ end
65
+ end
66
+
67
+ def self.from_byte_enum bytes
68
+ begin
69
+ loop until bytes.next == Packet::START_BYTE
70
+ length = (next_unescaped_byte(bytes) << 8) + next_unescaped_byte(bytes)
71
+ rescue
72
+ raise IOError, 'Packet is too short, unable to read length fields'
73
+ end
74
+ begin
75
+ data = (1..length).map { next_unescaped_byte bytes }
76
+ rescue
77
+ raise IOError, "Expected data length to be #{length} but got fewer bytes"
78
+ end
79
+ begin
80
+ crc = next_unescaped_byte bytes
81
+ rescue
82
+ raise IOError, 'Packet is too short, unable to read checksum'
83
+ end
84
+ if crc != Packet::checksum(data) then
85
+ raise IOError, "Excpected checksum to be 0x#{Packet::checksum(data).to_s 16} but was 0x#{crc.to_s 16}"
86
+ end
87
+ Packet.new data
88
+ end
89
+
90
+ def initialize data
91
+ @data = data
92
+ end
93
+
94
+ def data
95
+ @data
96
+ end
97
+
98
+ def length
99
+ @data.length
100
+ end
101
+
102
+ def checksum
103
+ Packet.checksum @data
104
+ end
105
+
106
+ def bytes
107
+ [START_BYTE, length >> 8, length & 0xff] + @data + [checksum]
108
+ end
109
+
110
+ def bytes_escaped
111
+ [START_BYTE] + bytes[1..-1].flat_map { |b|
112
+ if Packet.special_byte?(b) then
113
+ [ESCAPE, 0x20 ^ b]
114
+ else
115
+ b
116
+ end }
117
+ end
118
+
119
+ def == other
120
+ self.data == other.data
121
+ end
122
+
123
+ def to_s
124
+ 'Packet [' + data.map { |b| "0x#{b.to_s 16}" }.join(', ') + ']'
125
+ end
126
+ end
127
+
128
+ end
@@ -0,0 +1,42 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ module XBeeRuby
12
+
13
+ class Request
14
+
15
+ @@frame_id = 1
16
+
17
+ def self.next_frame_id
18
+ @@frame_id.tap do |id|
19
+ @@frame_id = (id + 1) % 256
20
+ end
21
+ end
22
+
23
+ attr_reader :frame_id
24
+ attr_reader :frame_type
25
+
26
+ def initialize frame_type = 0
27
+ @frame_id = Request.next_frame_id
28
+ @frame_type = frame_type
29
+ end
30
+
31
+ def frame_data
32
+ raise 'Override to return frame data as a byte array'
33
+ end
34
+
35
+ def packet
36
+ Packet.new([frame_type, frame_id] + frame_data)
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
@@ -0,0 +1,32 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ module XBeeRuby
12
+
13
+ class Response
14
+
15
+ @@response_types = {}
16
+
17
+ def self.frame_type type
18
+ @@response_types[type] = self
19
+ end
20
+
21
+ def self.from_packet packet
22
+ @@response_types[packet.data[0]].new packet.data rescue raise IOError, "Unknown response type 0x#{packet.data[0].to_s 16}"
23
+ end
24
+
25
+ def to_s
26
+ 'Response'
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,43 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/response'
12
+
13
+ module XBeeRuby
14
+
15
+
16
+ class RxResponse < Response
17
+
18
+ frame_type 0x90
19
+
20
+ attr_reader :address64
21
+ attr_reader :address16
22
+ attr_reader :receive_options
23
+ attr_reader :data
24
+
25
+ def initialize bytes
26
+ @address64 = Address64.new *bytes[1..8]
27
+ @address16 = Address16.new *bytes[9..10]
28
+ @receive_options = bytes[11]
29
+ @data = bytes[12..-1]
30
+ end
31
+
32
+ def == other
33
+ other.class == RxResponse && self.address64 == other.address64 &&
34
+ self.address16 == other.address16 && self.receive_options == other.receive_options
35
+ end
36
+
37
+ def to_s
38
+ "RxResponse[#{super}](address64=0x#{address64}, address16=0x#{address16}, receive_otions=#{receive_options})"
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,40 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/request'
12
+
13
+ module XBeeRuby
14
+
15
+ class TxRequest < Request
16
+
17
+ attr_reader :address64
18
+ attr_reader :address16
19
+ attr_reader :data
20
+ attr_reader :options
21
+ attr_reader :radius
22
+
23
+ def initialize address64, data, opt = {}
24
+ super 0x10
25
+ @address64 = address64
26
+ @data = data
27
+ @frame_id = Request.next_frame_id
28
+ @address16 = opt[:address16] || Address16::BROADCAST
29
+ @options = opt[:options] || 0
30
+ @radius = opt[:radius] || 0
31
+ end
32
+
33
+ def frame_data
34
+ @address64.to_a + @address16.to_a + [@radius, @options] + @data
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,46 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/response'
12
+
13
+ module XBeeRuby
14
+
15
+ class TxResponse < Response
16
+
17
+ frame_type 0x8b
18
+
19
+ attr_reader :frame_id
20
+ attr_reader :address16
21
+ attr_reader :retry_count
22
+ attr_reader :delivery_status
23
+ attr_reader :discovery_status
24
+
25
+ def initialize bytes
26
+ @frame_id = bytes[1]
27
+ @address16 = Address16.new *bytes[2..3]
28
+ @retry_count = bytes[4]
29
+ @delivery_status = bytes[5]
30
+ @discovery_status = bytes[6]
31
+ end
32
+
33
+ def == other
34
+ other.class == TxResponse && self.address16 == other.address16 &&
35
+ self.retry_count == other.retry_count && self.delivery_status == other.delivery_status &&
36
+ self.discovery_status == other.discovery_status
37
+ end
38
+
39
+ def to_s
40
+ "TxResponse[#{super}](address16=0x#{address16}, retry_count=#{retry_count}, " +
41
+ "delivery_status=#{delivery_status}, discovery_status=#{discovery_status})"
42
+ end
43
+ end
44
+
45
+ end
46
+
@@ -0,0 +1,15 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ module XBeeRuby
12
+
13
+ VERSION = '0.0.3'
14
+
15
+ end
@@ -0,0 +1,85 @@
1
+ =begin
2
+
3
+ This file is part of the xbee-ruby gem.
4
+
5
+ Copyright 2013-2014 Dirk Grappendorf, www.grappendorf.net
6
+
7
+ Licensed under the The MIT License (MIT)
8
+
9
+ =end
10
+
11
+ require 'xbee-ruby/packet'
12
+
13
+ module XBeeRuby
14
+
15
+ class XBee
16
+
17
+ # Either specify the port and serial parameters
18
+ #
19
+ # xbee = XBeeRuby::Xbee.new port: '/dev/ttyUSB0', rate: 9600
20
+ #
21
+ # or pass in a SerialPort like object
22
+ #
23
+ # xbee = XBeeRuby::XBee.new serial: some_serial_mockup_for_testing
24
+ #
25
+ def initialize port: '/dev/ttyUSB0', rate: 9600, serial: nil
26
+ @port = port
27
+ @rate = rate
28
+ @serial = serial
29
+ @connected = false
30
+ @logger = nil
31
+ end
32
+
33
+ def open
34
+ @serial ||= SerialPort.new @port, @rate
35
+ @serial_input = Enumerator.new { |y| loop do
36
+ y.yield @serial.readbyte
37
+ end }
38
+ @connected = true
39
+ end
40
+
41
+ def close
42
+ @serial.close if @serial
43
+ @connected = false
44
+ end
45
+
46
+ def connected?
47
+ @connected
48
+ end
49
+
50
+ alias :open? :connected?
51
+
52
+ def write_packet packet
53
+ @serial.write packet.bytes_escaped.pack('C*').force_encoding('ascii')
54
+ @serial.flush
55
+ end
56
+
57
+ def write_request request
58
+ write_packet request.packet
59
+ log { "Packet sent: #{request.packet.bytes.map { |b| b.to_s(16) }.join(',')}" }
60
+ end
61
+
62
+ def read_packet
63
+ Packet.from_byte_enum(@serial_input).tap do |packet|
64
+ log { "Packet received: #{packet.bytes.map { |b| b.to_s(16) }.join(',')}" }
65
+ end
66
+ end
67
+
68
+ def read_response
69
+ Response.from_packet read_packet
70
+ end
71
+
72
+ def serial= io
73
+ @serial = io
74
+ end
75
+
76
+ def logger= logger
77
+ @logger = logger
78
+ end
79
+
80
+ def log
81
+ @logger.call yield if @logger
82
+ end
83
+ end
84
+
85
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xbee-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Dirk Grappendorf (http://www.grappendorf.net)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: serialport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.1.0
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.1'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.1.0
89
+ description: A Ruby API for Digi XBee RF Modules
90
+ email:
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - lib/xbee-ruby.rb
96
+ - lib/xbee-ruby/address_16.rb
97
+ - lib/xbee-ruby/address_64.rb
98
+ - lib/xbee-ruby/adress.rb
99
+ - lib/xbee-ruby/modem_status_response.rb
100
+ - lib/xbee-ruby/packet.rb
101
+ - lib/xbee-ruby/request.rb
102
+ - lib/xbee-ruby/response.rb
103
+ - lib/xbee-ruby/rx_response.rb
104
+ - lib/xbee-ruby/tx_request.rb
105
+ - lib/xbee-ruby/tx_response.rb
106
+ - lib/xbee-ruby/version.rb
107
+ - lib/xbee-ruby/xbee.rb
108
+ homepage:
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.2.0
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A Ruby API for Digi XBee RF Modules
132
+ test_files: []