xbee-ruby 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []