xbee 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +13 -0
- data/.gitignore +25 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/examples/check_and_set_destination_address.rb +161 -0
- data/examples/read_frames.rb +45 -0
- data/examples/response_parser_throughput.rb +35 -0
- data/lib/xbee.rb +5 -0
- data/lib/xbee/address.rb +23 -0
- data/lib/xbee/address_16.rb +39 -0
- data/lib/xbee/address_64.rb +40 -0
- data/lib/xbee/bytes.rb +21 -0
- data/lib/xbee/exceptions/exception.rb +9 -0
- data/lib/xbee/exceptions/frame_format_error.rb +9 -0
- data/lib/xbee/exceptions/unknown_frame_type.rb +9 -0
- data/lib/xbee/frames/addressed_frame.rb +27 -0
- data/lib/xbee/frames/at_command.rb +35 -0
- data/lib/xbee/frames/at_command_queue_parameter_value.rb +21 -0
- data/lib/xbee/frames/at_command_response.rb +31 -0
- data/lib/xbee/frames/create_source_route.rb +15 -0
- data/lib/xbee/frames/data/sample.rb +72 -0
- data/lib/xbee/frames/data_sample_rx_indicator.rb +51 -0
- data/lib/xbee/frames/explicit_addressing_command.rb +68 -0
- data/lib/xbee/frames/explicit_rx_indicator.rb +60 -0
- data/lib/xbee/frames/frame.rb +65 -0
- data/lib/xbee/frames/identified_frame.rb +24 -0
- data/lib/xbee/frames/many_to_one_route_request_indicator.rb +11 -0
- data/lib/xbee/frames/modem_status.rb +47 -0
- data/lib/xbee/frames/node_identification_indicator.rb +38 -0
- data/lib/xbee/frames/over_the_air_firmware_update_status.rb +28 -0
- data/lib/xbee/frames/receive_packet.rb +44 -0
- data/lib/xbee/frames/remote_at_command_request.rb +53 -0
- data/lib/xbee/frames/remote_at_command_response.rb +45 -0
- data/lib/xbee/frames/route_record_indicator.rb +28 -0
- data/lib/xbee/frames/transmit_request.rb +70 -0
- data/lib/xbee/frames/transmit_status.rb +63 -0
- data/lib/xbee/frames/unidentified_addressed_frame.rb +26 -0
- data/lib/xbee/frames/xbee_sensor_read_indicator.rb +50 -0
- data/lib/xbee/packet.rb +175 -0
- data/lib/xbee/version.rb +5 -0
- data/lib/xbee/xbee.rb +109 -0
- data/xbee.gemspec +40 -0
- metadata +245 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8610d87b16c2a9335c2ce72be4dc5a602aff5f10
|
4
|
+
data.tar.gz: 4844015c3481f1de20c56b61361b87d546ab5a78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 509e9b13d5baddcae59ba5193763840aa88f0cd7e4212294bb85405ab4c9af5ca6b4f703263d36af06d2d4020d19e620dbb03808082cef22477a16b2ee786f5a
|
7
|
+
data.tar.gz: 0e3895e30803d0e1708a701ae823220118bd8ebd02fabc12474c2690fadc8eeef62064c942393173fd02b3303852aa2b2fa98dd491f1ca05d4aa17d2653caca9
|
data/.editorconfig
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# EditorConfig is awesome: http://EditorConfig.org
|
2
|
+
|
3
|
+
# top-most EditorConfig file
|
4
|
+
root = true
|
5
|
+
|
6
|
+
# Unix-style newlines with a newline ending every file
|
7
|
+
[*]
|
8
|
+
end_of_line = lf
|
9
|
+
insert_final_newline = true
|
10
|
+
indent_size = tab
|
11
|
+
indent_style = tab
|
12
|
+
#tab_width = 4
|
13
|
+
trim_trailing_whitespace = true
|
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# IntelliJ
|
2
|
+
/.idea
|
3
|
+
|
4
|
+
*.gem
|
5
|
+
*.rbc
|
6
|
+
.bundle
|
7
|
+
.config
|
8
|
+
.yardoc
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
*~
|
22
|
+
|
23
|
+
|
24
|
+
# Sublime
|
25
|
+
*.sublime-workspace
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2012-2013 Dirk Grappendorf, www.grappendorf.net
|
4
|
+
Copyright (c) 2017 Aaron Ten Clay, https://aarontc.com
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
XBee
|
2
|
+
====
|
3
|
+
|
4
|
+
A Ruby API for XBee ZigBee-RF-Modules
|
5
|
+
-------------------------------------
|
6
|
+
|
7
|
+
This gem is forked from the original XBee-Ruby gem. Because major API changes are being made a new name is appropriate.
|
8
|
+
|
9
|
+
See the `examples/` directory for some working examples with slightly more complexity than the samples below.
|
10
|
+
|
11
|
+
The `spec/` directory is left over from the forked gem, and will be converted to Minitest in the near future.
|
12
|
+
|
13
|
+
Example: Transmit a packet to another node
|
14
|
+
------------------------------------------
|
15
|
+
|
16
|
+
xbee = XBee::XBee.new device_path: '/dev/ttyUSB0', rate: 115200
|
17
|
+
xbee.open
|
18
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
19
|
+
request.address64 = XBee::Address64.from_string '0013A232408BACE4'
|
20
|
+
request.at_command = 'NI'
|
21
|
+
request.id = 0x01
|
22
|
+
xbee.write_frame request
|
23
|
+
puts xbee.read_frame
|
24
|
+
xbee.close
|
25
|
+
|
26
|
+
Example: Receive packets
|
27
|
+
------------------------
|
28
|
+
|
29
|
+
xbee = XBee::XBee.new port: '/dev/ttyUSB0', rate: 115200
|
30
|
+
xbee.open
|
31
|
+
loop do
|
32
|
+
frame = xbee.read_frame
|
33
|
+
puts "Frame received: #{frame.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
Contributing
|
37
|
+
------------
|
38
|
+
All development happens via Git using the [Git Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model. The canonical source location is
|
39
|
+
[XBee Bitbucket](https://work.techtonium.com/bitbucket/projects/XBEE). This repository is automatically mirrored to [GitHub](https://github.com/IdleEngineers/xbee).
|
40
|
+
|
41
|
+
If you find a bug or have a feature request, please create an issue in the [XBee issue tracker](https://work.techtonium.com/jira/browse/XBEE).
|
42
|
+
|
43
|
+
|
44
|
+
License
|
45
|
+
-------
|
46
|
+
|
47
|
+
The XBee code is licensed under the the MIT License
|
48
|
+
|
49
|
+
You find the license in the attached LICENSE.txt file
|
@@ -0,0 +1,161 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'timeout'
|
4
|
+
require_relative '../lib/xbee'
|
5
|
+
|
6
|
+
class CheckAndSetDestinationAddress
|
7
|
+
def run
|
8
|
+
xbee = XBee::XBee.new device_path: '/dev/ttyUSB0', rate: 115200
|
9
|
+
xbee.open
|
10
|
+
|
11
|
+
# First get Identifier
|
12
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
13
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
14
|
+
request.at_command = 'NI'
|
15
|
+
request.id = 0x01
|
16
|
+
puts "Transmitting frame: #{request.inspect}"
|
17
|
+
xbee.write_frame request
|
18
|
+
Timeout.timeout(10) do
|
19
|
+
loop do
|
20
|
+
response = xbee.read_frame
|
21
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
22
|
+
if response.address64 == request.address64
|
23
|
+
@ni = response.data.pack('C*')
|
24
|
+
puts format('Got node identity from %s: %s', request.address64.to_s, response.data.pack('C*'))
|
25
|
+
break
|
26
|
+
else
|
27
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
puts "Got response we don't need: #{response}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Now get destination address
|
36
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
37
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
38
|
+
request.at_command = 'DH'
|
39
|
+
request.id = 0x02
|
40
|
+
puts "Transmitting frame: #{request.inspect}"
|
41
|
+
xbee.write_frame request
|
42
|
+
Timeout.timeout(10) do
|
43
|
+
loop do
|
44
|
+
response = xbee.read_frame
|
45
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
46
|
+
if response.address64 == request.address64
|
47
|
+
puts format('Got DH from %s: %s', request.address64.to_s, response.data)
|
48
|
+
@dh = response.data
|
49
|
+
break
|
50
|
+
else
|
51
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
puts "Got response we don't need: #{response}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
59
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
60
|
+
request.at_command = 'DL'
|
61
|
+
request.id = 0x03
|
62
|
+
puts "Transmitting frame: #{request.inspect}"
|
63
|
+
xbee.write_frame request
|
64
|
+
Timeout.timeout(10) do
|
65
|
+
loop do
|
66
|
+
response = xbee.read_frame
|
67
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
68
|
+
if response.address64 == request.address64
|
69
|
+
puts format('Got DL from %s: %s', request.address64.to_s, response.data)
|
70
|
+
@dl = response.data
|
71
|
+
break
|
72
|
+
else
|
73
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
puts "Got response we don't need: #{response}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
@dest = XBee::Address64.new *@dh, *@dl
|
81
|
+
puts "Node #{@ni.inspect} Destination: #{@dest}"
|
82
|
+
# @target = XBee::Address64::COORDINATOR
|
83
|
+
@target = XBee::Address64.from_string '0013A20040B79952'
|
84
|
+
|
85
|
+
unless @dest == @target
|
86
|
+
puts "Updating destination address to be #{@target}..."
|
87
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
88
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
89
|
+
request.at_command = 'DH'
|
90
|
+
request.command_parameter = @target.to_a[0..3]
|
91
|
+
request.id = 0x04
|
92
|
+
puts "Transmitting frame: #{request.inspect}"
|
93
|
+
xbee.write_frame request
|
94
|
+
Timeout.timeout(10) do
|
95
|
+
loop do
|
96
|
+
response = xbee.read_frame
|
97
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
98
|
+
if response.address64 == request.address64
|
99
|
+
puts format('Got DH from %s: %s', request.address64.to_s, response.data)
|
100
|
+
@dl = response.data
|
101
|
+
break
|
102
|
+
else
|
103
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
puts "Got response we don't need: #{response}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
111
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
112
|
+
request.at_command = 'DL'
|
113
|
+
request.command_parameter = @target.to_a[4..7]
|
114
|
+
request.id = 0x05
|
115
|
+
puts "Transmitting frame: #{request.inspect}"
|
116
|
+
xbee.write_frame request
|
117
|
+
Timeout.timeout(10) do
|
118
|
+
loop do
|
119
|
+
response = xbee.read_frame
|
120
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
121
|
+
if response.address64 == request.address64
|
122
|
+
puts format('Got DL from %s: %s', request.address64.to_s, response.data)
|
123
|
+
@dl = response.data
|
124
|
+
break
|
125
|
+
else
|
126
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
puts "Got response we don't need: #{response}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
request = XBee::Frames::RemoteATCommandRequest.new
|
134
|
+
request.address64 = XBee::Address64.from_string '0013A200408BACE4'
|
135
|
+
request.at_command = 'AC'
|
136
|
+
request.id = 0x06
|
137
|
+
puts "Transmitting frame: #{request.inspect}"
|
138
|
+
xbee.write_frame request
|
139
|
+
Timeout.timeout(10) do
|
140
|
+
loop do
|
141
|
+
response = xbee.read_frame
|
142
|
+
if response.is_a?(XBee::Frames::RemoteATCommandResponse)
|
143
|
+
if response.address64 == request.address64
|
144
|
+
puts format('Got AC from %s: %s', request.address64.to_s, response.data)
|
145
|
+
@dl = response.data
|
146
|
+
break
|
147
|
+
else
|
148
|
+
puts format('Got response from wrong node %s: %s', request.address64.to_s, response.data.pack('C*'))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
puts "Got response we don't need: #{response}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
ensure
|
157
|
+
xbee.close
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
CheckAndSetDestinationAddress.new.run if $0 == __FILE__
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'semantic_logger'
|
6
|
+
require 'trollop'
|
7
|
+
|
8
|
+
@options = Trollop.options do
|
9
|
+
opt :device, 'Path to serial device', default: '/dev/ttyUSB0', type: :string
|
10
|
+
opt :baud, 'Baud rate for XBee radio', default: 115200, type: :integer
|
11
|
+
opt :log_path, 'Path for log file', default: nil, type: :string
|
12
|
+
opt :log_level, 'Logging level - trace, debug, info, warn, error, fatal', default: 'debug', type: :string, callback: lambda { |s| raise Trollop::CommandlineError, 'Invalid logging level specified' unless SemanticLogger::LEVELS.include? s.to_sym}
|
13
|
+
end
|
14
|
+
|
15
|
+
SemanticLogger.default_level = @options.log_level.to_sym
|
16
|
+
SemanticLogger.add_appender file_name: @options.log_path, formatter: :color if @options.log_path
|
17
|
+
SemanticLogger.add_appender io: $stdout, formatter: :color
|
18
|
+
|
19
|
+
|
20
|
+
require 'xbee'
|
21
|
+
|
22
|
+
class ReadFrames
|
23
|
+
include SemanticLogger::Loggable
|
24
|
+
|
25
|
+
|
26
|
+
def initialize(device_path: @options.device, rate: @options.baud)
|
27
|
+
@device_path = device_path
|
28
|
+
@rate = rate
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def run
|
33
|
+
xbee = XBee::XBee.new device_path: @device_path, rate: @rate
|
34
|
+
xbee.open
|
35
|
+
loop do
|
36
|
+
frame = xbee.read_frame
|
37
|
+
logger.info 'Frame received.', frame: frame
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if $0 == __FILE__
|
43
|
+
reader = ReadFrames.new device_path: @options.device, rate: @options.baud
|
44
|
+
reader.run
|
45
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../lib/xbee'
|
4
|
+
|
5
|
+
class FakeIO
|
6
|
+
def initialize
|
7
|
+
@queue = Queue.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def readbyte
|
11
|
+
if @queue.empty?
|
12
|
+
load_queue
|
13
|
+
end
|
14
|
+
@queue.pop
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_queue
|
18
|
+
[0x7e, 0x00, 0x07, 0x8b, 0x02, 0x79, 0x38, 0x00, 0x00, 0x00, 0xc1].each do |b|
|
19
|
+
@queue.push b
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
xbee = XBee::XBee.new io: FakeIO.new
|
25
|
+
xbee.open
|
26
|
+
num_reads = 0
|
27
|
+
start_time = Time.now.to_f
|
28
|
+
end_time = start_time + 10
|
29
|
+
puts 'Reading responses from a faked serial connection for 10 seconds'
|
30
|
+
while Time.now.to_f < end_time
|
31
|
+
xbee.read_frame
|
32
|
+
num_reads += 1
|
33
|
+
end
|
34
|
+
puts 'Done'
|
35
|
+
puts "#{num_reads / 10.0} per second"
|
data/lib/xbee.rb
ADDED
data/lib/xbee/address.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module XBee
|
4
|
+
class Address
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
|
8
|
+
def <=>(other)
|
9
|
+
to_a <=> other.to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def ==(other)
|
14
|
+
to_a == other.to_a
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
@bytes
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'address'
|
3
|
+
|
4
|
+
module XBee
|
5
|
+
class Address16 < Address
|
6
|
+
def initialize(msb, lsb)
|
7
|
+
@bytes = [msb, lsb]
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def from_string(string)
|
13
|
+
if (matcher = /^(\h\h)[^\h]*(\h\h)$/.match(string))
|
14
|
+
new *(matcher[1..2].map &:hex)
|
15
|
+
else
|
16
|
+
raise ArgumentError, "#{string} is not a valid 16-bit address string"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def from_array(array)
|
22
|
+
if array.length == 2 && array.all? { |x| (0..255).cover? x }
|
23
|
+
new *array
|
24
|
+
else
|
25
|
+
raise ArgumentError, "#{array.inspect} is not a valid 16-bit address array"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
'%02x%02x' % @bytes
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
BROADCAST = new(0xff, 0xfe).freeze
|
37
|
+
COORDINATOR = new(0x00, 0x00).freeze
|
38
|
+
end
|
39
|
+
end
|