ruxbee 0.1.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +11 -0
- data/README.md +36 -0
- data/README.rdoc +233 -0
- data/Rakefile +6 -0
- data/agpl.txt +661 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/listen_api.rb +35 -0
- data/icon.jpg +0 -0
- data/lib/ruxbee/at_commands.rb +28 -0
- data/lib/ruxbee/config.rb +96 -0
- data/lib/ruxbee/frame/at_command.rb +35 -0
- data/lib/ruxbee/frame/at_command_response.rb +33 -0
- data/lib/ruxbee/frame/base_frame.rb +32 -0
- data/lib/ruxbee/frame/explicit_addressing_command.rb +52 -0
- data/lib/ruxbee/frame/explicit_rx_indicator.rb +23 -0
- data/lib/ruxbee/frame/frame.rb +128 -0
- data/lib/ruxbee/frame/io_data_sample_rx_indicator.rb +10 -0
- data/lib/ruxbee/frame/modem_status.rb +32 -0
- data/lib/ruxbee/frame/receive_packet.rb +6 -0
- data/lib/ruxbee/frame/receive_packet_16.rb +29 -0
- data/lib/ruxbee/frame/received_frame.rb +16 -0
- data/lib/ruxbee/frame/remote_command_request.rb +34 -0
- data/lib/ruxbee/frame/remote_command_response.rb +22 -0
- data/lib/ruxbee/frame/transmit_request.rb +7 -0
- data/lib/ruxbee/frame/transmit_status.rb +6 -0
- data/lib/ruxbee/rfmodule.rb +85 -0
- data/lib/ruxbee/version.rb +3 -0
- data/lib/ruxbee/xbee_api.rb +642 -0
- data/lib/ruxbee/xbee_cmd.rb +554 -0
- data/lib/ruxbee.rb +37 -0
- data/ruxbee.gemspec +34 -0
- metadata +140 -0
@@ -0,0 +1,642 @@
|
|
1
|
+
require 'ruxbee/rfmodule'
|
2
|
+
require 'ruxbee/frame/frame'
|
3
|
+
|
4
|
+
module XBee
|
5
|
+
##
|
6
|
+
# This is the main class for API mode for XBee radios.
|
7
|
+
class BaseAPIModeInterface < RFModule
|
8
|
+
|
9
|
+
VERSION = "1.2.0" # Version of this class
|
10
|
+
|
11
|
+
##
|
12
|
+
# ==== Attributes
|
13
|
+
# * +xbee_usbdev_str+ - USB Device as a string
|
14
|
+
#
|
15
|
+
# ==== Options
|
16
|
+
# * +uart_config+ - XBeeUARTConfig
|
17
|
+
# * +operation_mode+ - Either :AT or :API for XBee operation mode
|
18
|
+
# * +transmission_mode+ - :SYNC for Synchronous communication or :ASYNC for Asynchonrous communication.
|
19
|
+
#
|
20
|
+
# A note on the asynchronous vs synchronous communication modes - A
|
21
|
+
# simplistic network of a few XBee nodes can pretty much work according to
|
22
|
+
# expected flows where requests and responses are always handled in
|
23
|
+
# synchronous ways. However, if bigger radio networks are being deployed
|
24
|
+
# (real scenarios) you cannot guarantee the synchronous nature of the network.
|
25
|
+
# You will have nodes joining/removing themselves, sleeping, sending data
|
26
|
+
# samples etc. Although the default behaviour is set as :SYNC, if you have a
|
27
|
+
# real network, then by design the network is Asynchronous, use :ASYNC instead.
|
28
|
+
# Otherwise you will most definitely run into "Invalid responses" issues.
|
29
|
+
#
|
30
|
+
# For handling the Asynchronous communication logic, use an external Queue
|
31
|
+
# and database to effectively handle the command/response and other frames
|
32
|
+
# that are concurrently being conversed on the PAN.
|
33
|
+
#
|
34
|
+
# ==== Example
|
35
|
+
# require 'ruby_xbee'
|
36
|
+
# @uart_config = XBee::Config::XBeeUARTConfig.new()
|
37
|
+
# @xbee_usbdev_str = '/dev/tty.usbserial-A101KYF6'
|
38
|
+
# @xbee = XBee::BaseAPIModeInterface.new(@xbee_usbdev_str, @uart_config, :API, :ASYNC)
|
39
|
+
#
|
40
|
+
def initialize(xbee_usbdev_str, uart_config = XBeeUARTConfig.new, operation_mode = :API, transmission_mode = :SYNC)
|
41
|
+
super(xbee_usbdev_str, uart_config, operation_mode, transmission_mode)
|
42
|
+
@frame_id = 1
|
43
|
+
if self.operation_mode == :AT
|
44
|
+
start_apimode_communication
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def next_frame_id
|
49
|
+
@frame_id += 1
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Switch to API mode - note that in Series 2 the Operation Mode is defined
|
54
|
+
# by the firmware flashed to the device. Only Series 1 can switch from
|
55
|
+
# AT (Transparent) to API Opearation and back seamlessly.
|
56
|
+
#
|
57
|
+
# API Mode 1 - API Enabled
|
58
|
+
# API Mode 2 - API Enabled, with escaped control characters
|
59
|
+
def start_apimode_communication
|
60
|
+
in_command_mode do
|
61
|
+
puts "Entering api mode"
|
62
|
+
# Set API Mode 2 (include escaped characters)
|
63
|
+
self.xbee_serialport.write("ATAP1\r")
|
64
|
+
self.xbee_serialport.read(3)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_param(at_param_name, at_param_unpack_string = nil)
|
69
|
+
frame_id = self.next_frame_id
|
70
|
+
at_command_frame = XBee::Frame::ATCommand.new(at_param_name,frame_id,nil,at_param_unpack_string)
|
71
|
+
puts "Sending ... [#{at_command_frame._dump(self.api_mode.in_symbol).unpack("C*").join(", ")}]" if $VERBOSE
|
72
|
+
self.xbee_serialport.write(at_command_frame._dump(self.api_mode.in_symbol))
|
73
|
+
if self.transmission_mode == :SYNC
|
74
|
+
r = XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
75
|
+
if r.kind_of?(XBee::Frame::ATCommandResponse) && r.status == :OK && r.frame_id == frame_id
|
76
|
+
if block_given?
|
77
|
+
yield r
|
78
|
+
else
|
79
|
+
#### DEBUG ####
|
80
|
+
if $DEBUG then
|
81
|
+
print "At parameter unpack string to be used: #{at_param_unpack_string} | "
|
82
|
+
puts "Debug Return value for value: #{r.retrieved_value.unpack(at_param_unpack_string)}"
|
83
|
+
end
|
84
|
+
#### DEBUG ####
|
85
|
+
at_param_unpack_string.nil? ? r.retrieved_value : r.retrieved_value.unpack(at_param_unpack_string).first
|
86
|
+
end
|
87
|
+
else
|
88
|
+
raise "Response did not indicate successful retrieval of that parameter: #{r.inspect}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_param(at_param_name, param_value, at_param_unpack_string = nil)
|
94
|
+
frame_id = self.next_frame_id
|
95
|
+
at_command_frame = XBee::Frame::ATCommand.new(at_param_name,frame_id,param_value,at_param_unpack_string)
|
96
|
+
# puts "Sending ... [#{at_command_frame._dump(self.api_mode.in_symbol).unpack("C*").join(", ")}]"
|
97
|
+
self.xbee_serialport.write(at_command_frame._dump(self.api_mode.in_symbol))
|
98
|
+
if self.transmission_mode == :SYNC
|
99
|
+
r = XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
100
|
+
if r.kind_of?(XBee::Frame::ATCommandResponse) && r.status == :OK && r.frame_id == frame_id
|
101
|
+
if block_given?
|
102
|
+
yield r
|
103
|
+
else
|
104
|
+
at_param_unpack_string.nil? ? r.retrieved_value : r.retrieved_value.unpack(at_param_unpack_string).first
|
105
|
+
end
|
106
|
+
else
|
107
|
+
raise "Response did not indicate successful retrieval of that parameter: #{r.inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_remote_param(at_param_name, remote_address = 0x000000000000ffff, remote_network_address = 0xfffe, at_param_unpack_string = nil)
|
113
|
+
frame_id = self.next_frame_id
|
114
|
+
at_command_frame = XBee::Frame::RemoteCommandRequest.new(at_param_name, remote_address, remote_network_address, frame_id, nil, at_param_unpack_string)
|
115
|
+
puts "Sending ... [#{at_command_frame._dump(self.api_mode.in_symbol).unpack("C*").join(", ")}]"
|
116
|
+
self.xbee_serialport.write(at_command_frame._dump(self.api_mode.in_symbol))
|
117
|
+
if self.transmission_mode == :SYNC
|
118
|
+
r = XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
119
|
+
if r.kind_of?(XBee::Frame::RemoteCommandResponse) && r.status == :OK && r.frame_id == frame_id
|
120
|
+
if block_given?
|
121
|
+
yield r
|
122
|
+
else
|
123
|
+
at_param_unpack_string.nil? ? r.retrieved_value : r.retrieved_value.unpack(at_param_unpack_string).first
|
124
|
+
end
|
125
|
+
else
|
126
|
+
raise "Response did not indicate successful retrieval of that parameter: #{r.inspect}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_remote_param(at_param_name, param_value, remote_address = 0x000000000000ffff, remote_network_address = 0xfffe, at_param_unpack_string = nil)
|
132
|
+
frame_id = self.next_frame_id
|
133
|
+
at_command_frame = XBee::Frame::RemoteCommandRequest.new(at_param_name, remote_address, remote_network_address, frame_id, param_value, at_param_unpack_string)
|
134
|
+
puts "Sending ... [#{at_command_frame._dump(self.api_mode.in_symbol).unpack("C*").join(", ")}]"
|
135
|
+
self.xbee_serialport.write(at_command_frame._dump(self.api_mode.in_symbol))
|
136
|
+
if self.transmission_mode == :SYNC
|
137
|
+
r = XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
138
|
+
if r.kind_of?(XBee::Frame::RemoteCommandResponse) && r.status == :OK && r.frame_id == frame_id
|
139
|
+
if block_given?
|
140
|
+
yield r
|
141
|
+
else
|
142
|
+
at_param_unpack_string.nil? ? r.retrieved_value : r.retrieved_value.unpack(at_param_unpack_string).first
|
143
|
+
end
|
144
|
+
else
|
145
|
+
raise "Response did not indicate successful retrieval of that parameter: #{r.inspect}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Association Indication. Read information regarding last node join request:
|
152
|
+
# * 0x00 - Successful completion - Coordinator started or Router/End Device found and joined with a parent.
|
153
|
+
# * 0x21 - Scan found no PANs
|
154
|
+
# * 0x22 - Scan found no valid PANs based on current SC and ID settings
|
155
|
+
# * 0x23 - Valid Coordinator or Routers found, but they are not allowing joining (NJ expired) 0x27 - Node Joining attempt failed
|
156
|
+
# * 0x2A - Coordinator Start attempt failed‘
|
157
|
+
# * 0xFF - Scanning for a Parent
|
158
|
+
def association_indication
|
159
|
+
@association_indication ||= get_param("AI","n")
|
160
|
+
if @association_indication == nil then @association_indication = 0 end
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Retrieve XBee firmware version
|
165
|
+
def fw_rev
|
166
|
+
@fw_rev ||= get_param("VR","n")
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Retrieve XBee hardware version
|
171
|
+
def hw_rev
|
172
|
+
@hw_rev ||= get_param("HV","n")
|
173
|
+
end
|
174
|
+
|
175
|
+
##
|
176
|
+
# Neighbor node discovery. Returns an array of hashes each element of the array contains a hash
|
177
|
+
# each hash contains keys: :MY, :SH, :SL, :DB, :NI
|
178
|
+
# representing addresses source address, Serial High, Serial Low, Received signal strength,
|
179
|
+
# node identifier respectively. Aan example of the results returned (hash as seen by pp):
|
180
|
+
#
|
181
|
+
# [{:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"4008A642", :DB=>-24},
|
182
|
+
# {:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"4008A697", :DB=>-33},
|
183
|
+
# {:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"40085AD5", :DB=>-52}]
|
184
|
+
#
|
185
|
+
# Signal strength (:DB) is reported in units of -dBM.
|
186
|
+
def neighbors
|
187
|
+
frame_id = self.next_frame_id
|
188
|
+
# neighbors often takes more than 1000ms to return data
|
189
|
+
node_discover_cmd = XBee::Frame::ATCommand.new("ND",frame_id,nil)
|
190
|
+
#puts "Node discover command dump: #{node_discover_cmd._dump(self.api_mode.in_symbol).unpack("C*").join(", ")}"
|
191
|
+
tmp = @xbee_serialport.read_timeout
|
192
|
+
@xbee_serialport.read_timeout = Integer(self.node_discover_timeout.in_seconds * 1050)
|
193
|
+
@xbee_serialport.write(node_discover_cmd._dump(self.api_mode.in_symbol))
|
194
|
+
responses = []
|
195
|
+
#read_thread = Thread.new do
|
196
|
+
begin
|
197
|
+
loop do
|
198
|
+
r = XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
199
|
+
# puts "Got a response! Frame ID: #{r.frame_id}, Command: #{r.at_command}, Status: #{r.status}, Value: #{r.retrieved_value}"
|
200
|
+
if r.kind_of?(XBee::Frame::ATCommandResponse) && r.status == :OK && r.frame_id == frame_id
|
201
|
+
if r.retrieved_value.empty?
|
202
|
+
# w00t - the module is telling us it's done with the discovery process.
|
203
|
+
break
|
204
|
+
else
|
205
|
+
responses << r
|
206
|
+
end
|
207
|
+
else
|
208
|
+
raise "Unexpected response to ATND command: #{r.inspect}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
rescue Exception => e
|
212
|
+
puts "Okay, must have finally timed out on the serial read: #{e}."
|
213
|
+
end
|
214
|
+
@xbee_serialport.read_timeout = tmp
|
215
|
+
responses.map do |r|
|
216
|
+
unpacked_fields = r.retrieved_value.unpack("nNNZ20nCCnn")
|
217
|
+
return_fields = [:SH, :SL, :NI, :PARENT_NETWORK_ADDRESS, :DEVICE_TYPE, :STATUS, :PROFILE_ID, :MANUFACTURER_ID]
|
218
|
+
unpacked_fields.shift #Throw out the junk at the start of the discover packet
|
219
|
+
return_fields.inject(Hash.new) do |return_hash, field_name|
|
220
|
+
return_hash[field_name] = unpacked_fields.shift
|
221
|
+
return_hash
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
##
|
227
|
+
# Returns the low portion of the XBee device's current destination address
|
228
|
+
def destination_low
|
229
|
+
@destination_low ||= get_param("DL")
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Sets the low portion of the XBee device's destination address
|
234
|
+
# Parameter range: 0 - 0xFFFFFFFF
|
235
|
+
def destination_low!(low_addr)
|
236
|
+
@xbee_serialport.write("ATDL#{low_addr}\r")
|
237
|
+
getresponse if self.transmission_mode == :SYNC
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Returns the high portion of the XBee device's current destination address
|
242
|
+
def destination_high
|
243
|
+
@destination_high ||= get_param("DH")
|
244
|
+
end
|
245
|
+
|
246
|
+
##
|
247
|
+
# Sets the high portion of the XBee device's current destination address
|
248
|
+
# Parameter range: 0 - 0xFFFFFFFF
|
249
|
+
def destination_high!(high_addr)
|
250
|
+
self.xbee_serialport.write("ATDH#{high_addr}\r")
|
251
|
+
getresponse if self.transmission_mode == :SYNC
|
252
|
+
end
|
253
|
+
|
254
|
+
##
|
255
|
+
# Returns the low portion of the XBee device's serial number. this value is factory set.
|
256
|
+
def serial_num_low
|
257
|
+
@serial_low ||= get_param("SL","N")
|
258
|
+
end
|
259
|
+
|
260
|
+
##
|
261
|
+
# Returns the high portion of the XBee device's serial number. this value is factory set.
|
262
|
+
def serial_num_high
|
263
|
+
@serial_high ||= get_param("SH","N")
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Returns the complete serialnumber of XBee device by quering the high and low parts.
|
268
|
+
def serial_num
|
269
|
+
self.serial_num_high() << 32 | self.serial_num_low
|
270
|
+
end
|
271
|
+
|
272
|
+
##
|
273
|
+
# returns the channel number of the XBee device. this value, along with the PAN ID,
|
274
|
+
# and MY address determines the addressability of the device and what it can listen to
|
275
|
+
def channel
|
276
|
+
# channel often takes more than 1000ms to return data
|
277
|
+
tmp = @xbee_serialport.read_timeout
|
278
|
+
@xbee_serialport.read_timeout = read_timeout(:long)
|
279
|
+
@xbee_serialport.write("ATCH\r")
|
280
|
+
if self.tranmission_mode == :SYNC
|
281
|
+
response = getresponse
|
282
|
+
@xbee_serialport.read_timeout = tmp
|
283
|
+
response.strip.chomp
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
##
|
288
|
+
# sets the channel number of the device. The valid channel numbers are those of the 802.15.4 standard.
|
289
|
+
def channel!(new_channel)
|
290
|
+
# channel takes more than 1000ms to return data
|
291
|
+
tmp = @xbee_serialport.read_timeout
|
292
|
+
@xbee_serialport.read_timeout = read_timeout(:long)
|
293
|
+
@xbee_serialport.write("ATCH#{new_channel}\r")
|
294
|
+
if self.transmission_mode == :SYNC
|
295
|
+
response = getresponse
|
296
|
+
@xbee_serialport.read_timeout = tmp
|
297
|
+
response.strip.chomp
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# returns the node ID of the device. Node ID is typically a human-meaningful name
|
303
|
+
# to give to the XBee device, much like a hostname.
|
304
|
+
def node_id
|
305
|
+
@node_id ||= get_param("NI")
|
306
|
+
end
|
307
|
+
|
308
|
+
##
|
309
|
+
# sets the node ID to a user-definable text string to make it easier to
|
310
|
+
# identify the device with "human" names. This node id is reported to
|
311
|
+
# neighboring XBees so consider it "public".
|
312
|
+
def node_id!(new_id)
|
313
|
+
tmp = @xbee_serialport.read_timeout
|
314
|
+
@xbee_serialport.read_timeout = read_timeout(:long)
|
315
|
+
@xbee_serialport.write("ATNI#{new_id}\r")
|
316
|
+
if self.transmission_mode == :SYNC
|
317
|
+
response = getresponse
|
318
|
+
@xbee_serialport.read_timeout = tmp
|
319
|
+
if ( response.nil? )
|
320
|
+
return ""
|
321
|
+
else
|
322
|
+
response.strip.chomp
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
##
|
328
|
+
# returns the PAN ID of the device. PAN ID is one of the 3 main identifiers used to
|
329
|
+
# communicate with the device from other XBees. All XBees which are meant to communicate
|
330
|
+
# must have the same PAN ID and channel number. The 3rd identifier is the address of the
|
331
|
+
# device itself represented by its serial number (High and Low) and/or it's 16-bit MY
|
332
|
+
# source address.
|
333
|
+
def pan_id
|
334
|
+
@pan_id ||= get_param("ID").unpack("n")
|
335
|
+
end
|
336
|
+
|
337
|
+
##
|
338
|
+
# sets the PAN ID of the device. Modules must have the same PAN ID in order to communicate
|
339
|
+
# with each other. The PAN ID value can range from 0 - 0xffff. The default from the factory
|
340
|
+
# is set to 0x3332.
|
341
|
+
def pan_id!(new_id)
|
342
|
+
@xbee_serialport.write("ATID#{new_id}\r")
|
343
|
+
getresponse if self.transmission_mode == :SYNC
|
344
|
+
end
|
345
|
+
|
346
|
+
##
|
347
|
+
# returns the signal strength in dBm units of the last received packet. Expect a negative integer
|
348
|
+
# or 0 to be returned. If the XBee device has not received any neighboring packet data, the signal strength
|
349
|
+
# value will be 0
|
350
|
+
def received_signal_strength
|
351
|
+
-(get_param("DB").hex)
|
352
|
+
end
|
353
|
+
|
354
|
+
##
|
355
|
+
# retrieves the baud rate of the device. Generally, this will be the same as the
|
356
|
+
# rate you're currently using to talk to the device unless you've changed the device's
|
357
|
+
# baud rate and are still in the AT command mode and/or have not exited command mode explicitly for
|
358
|
+
# the new baud rate to take effect.
|
359
|
+
def baud
|
360
|
+
@xbee_serialport.write("ATBD\r")
|
361
|
+
baudcode = getresponse
|
362
|
+
@baudcodes.index( baudcode.to_i )
|
363
|
+
end
|
364
|
+
|
365
|
+
##
|
366
|
+
# sets the given baud rate into the XBee device. The baud change will not take
|
367
|
+
# effect until the AT command mode times out or the exit command mode command is given.
|
368
|
+
# acceptable baud rates are: 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
|
369
|
+
def baud!( baud_rate )
|
370
|
+
@xbee_serialport.write("ATBD#{@baudcodes[baud_rate]}\r")
|
371
|
+
getresponse if self.transmission_mode == :SYNC
|
372
|
+
end
|
373
|
+
|
374
|
+
##
|
375
|
+
# returns the parity of the device as represented by a symbol:
|
376
|
+
# :None - for 8-bit none
|
377
|
+
# :Even - for 8-bit even
|
378
|
+
# :Odd - for 8-bit odd
|
379
|
+
# :Mark - for 8-bit mark
|
380
|
+
# :Space - for 8-bit space
|
381
|
+
def parity
|
382
|
+
@xbee_serialport.write("ATNB\r")
|
383
|
+
if self.transmission_mode == :SYNC
|
384
|
+
response = getresponse().strip.chomp
|
385
|
+
@paritycodes.index( response.to_i )
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
##
|
390
|
+
# sets the parity of the device to one represented by a symbol contained in the parity_type parameter
|
391
|
+
# :None - for 8-bit none
|
392
|
+
# :Even - for 8-bit even
|
393
|
+
# :Odd - for 8-bit odd
|
394
|
+
# :Mark - for 8-bit mark
|
395
|
+
# :Space - for 8-bit space
|
396
|
+
def parity!( parity_type )
|
397
|
+
# validate symbol before writing parity param
|
398
|
+
if !@paritycodes.include?(parity_type)
|
399
|
+
return false
|
400
|
+
end
|
401
|
+
@xbee_serialport.write("ATNB#{@paritycodes[parity_type]}\r")
|
402
|
+
getresponse if self.transmission_mode == :SYNC
|
403
|
+
end
|
404
|
+
|
405
|
+
##
|
406
|
+
# reads an i/o port configuration on the XBee for analog to digital or digital input or output (GPIO)
|
407
|
+
# this method returns an I/O type symbol of:
|
408
|
+
#
|
409
|
+
# :Disabled
|
410
|
+
# :ADC
|
411
|
+
# :DI
|
412
|
+
# :DO_Low
|
413
|
+
# :DO_High
|
414
|
+
# :Associated_Indicator
|
415
|
+
# :RTS
|
416
|
+
# :CTS
|
417
|
+
# :RS485_Low
|
418
|
+
# :RS485_High
|
419
|
+
#
|
420
|
+
# Not all DIO ports are capable of every configuration listed above. This method will properly translate
|
421
|
+
# the XBee's response value to the symbol above when the same value has different meanings from port to port.
|
422
|
+
#
|
423
|
+
# The port parameter may be any symbol :D0 through :D8 representing the 8 I/O ports on an XBee
|
424
|
+
def dio( port )
|
425
|
+
at = "AT#{port.to_s}\r"
|
426
|
+
@xbee_serialport.write( at )
|
427
|
+
if self.transmission_mode == :SYNC
|
428
|
+
response = getresponse.to_i
|
429
|
+
|
430
|
+
if response == 1 # the value of 1 is overloaded based on port number
|
431
|
+
case port
|
432
|
+
when :D5
|
433
|
+
return :Associated_Indicator
|
434
|
+
when :D6
|
435
|
+
return :RTS
|
436
|
+
when :D7
|
437
|
+
return :CTS
|
438
|
+
end
|
439
|
+
else
|
440
|
+
@iotypes.index(response)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
##
|
446
|
+
# configures an i/o port on the XBee for analog to digital or digital input or output (GPIO)
|
447
|
+
#
|
448
|
+
# port parameter valid values are the symbols :D0 through :D8
|
449
|
+
#
|
450
|
+
# iotype parameter valid values are symbols:
|
451
|
+
# :Disabled
|
452
|
+
# :ADC
|
453
|
+
# :DI
|
454
|
+
# :DO_Low
|
455
|
+
# :DO_High
|
456
|
+
# :Associated_Indicator
|
457
|
+
# :RTS
|
458
|
+
# :CTS
|
459
|
+
# :RS485_Low
|
460
|
+
# :RS485_High
|
461
|
+
#
|
462
|
+
# note: not all iotypes are compatible with every port type, see the XBee manual for exceptions and semantics
|
463
|
+
#
|
464
|
+
# note: it is critical you have upgraded firmware in your XBee or DIO ports 0-4 cannot be read
|
465
|
+
# (ie: ATD0 will return ERROR - this is an XBee firmware bug that's fixed in revs later than 1083)
|
466
|
+
#
|
467
|
+
# note: tested with rev 10CD, fails with rev 1083
|
468
|
+
def dio!( port, iotype )
|
469
|
+
at = "AT#{port.to_s}#{@iotypes[iotype]}\r"
|
470
|
+
@xbee_serialport.write( at )
|
471
|
+
getresponse if self.transmission_mode == :SYNC
|
472
|
+
end
|
473
|
+
|
474
|
+
##
|
475
|
+
# reads the bitfield values for change detect monitoring. returns a bitmask indicating
|
476
|
+
# which DIO lines, 0-7 are enabled or disabled for change detect monitoring
|
477
|
+
def dio_change_detect
|
478
|
+
@xbee_serialport.write("ATIC\r")
|
479
|
+
getresponse if self.transmission_mode == :SYNC
|
480
|
+
end
|
481
|
+
|
482
|
+
##
|
483
|
+
# sets the bitfield values for change detect monitoring. The hexbitmap parameter is a bitmap
|
484
|
+
# which enables or disables the change detect monitoring for any of the DIO ports 0-7
|
485
|
+
def dio_change_detect!( hexbitmap )
|
486
|
+
@xbee_serialport.write("ATIC#{hexbitmask}\r")
|
487
|
+
getresponse if self.transmission_mode == :SYNC
|
488
|
+
end
|
489
|
+
|
490
|
+
##
|
491
|
+
# Sets the digital output levels of any DIO lines which were configured for output using the dio! method.
|
492
|
+
# The parameter, hexbitmap, is a hex value which represents the 8-bit bitmap of the i/o lines on the
|
493
|
+
# XBee.
|
494
|
+
def io_output!( hexbitmap )
|
495
|
+
@xbee_serialport.write("ATIO#{hexbitmap}\r")
|
496
|
+
getresponse if self.transmission_mode == :SYNC
|
497
|
+
end
|
498
|
+
|
499
|
+
##
|
500
|
+
# Forces a sampling of all DIO pins configured for input via dio!
|
501
|
+
# Returns a hash with the following key/value pairs:
|
502
|
+
# :NUM => number of samples
|
503
|
+
# :CM => channel mask
|
504
|
+
# :DIO => dio data if DIO lines are enabled
|
505
|
+
# :ADCn => adc sample data (one for each ADC channel enabled)
|
506
|
+
def io_input
|
507
|
+
|
508
|
+
tmp = @xbee_serialport.read_timeout
|
509
|
+
@xbee_serialport.read_timeout = read_timeout(:long)
|
510
|
+
|
511
|
+
@xbee_serialport.write("ATIS\r")
|
512
|
+
if self.transmission_mode == :SYNC
|
513
|
+
response = getresponse
|
514
|
+
linenum = 1
|
515
|
+
adc_sample = 1
|
516
|
+
samples = Hash.new
|
517
|
+
|
518
|
+
if response.match("ERROR")
|
519
|
+
samples[:ERROR] = "ERROR"
|
520
|
+
return samples
|
521
|
+
end
|
522
|
+
|
523
|
+
# otherwise parse input data
|
524
|
+
response.each_line do | line |
|
525
|
+
case linenum
|
526
|
+
when 1
|
527
|
+
samples[:NUM] = line.to_i
|
528
|
+
when 2
|
529
|
+
samples[:CM] = line.strip.chomp
|
530
|
+
when 3
|
531
|
+
samples[:DIO] = line.strip.chomp
|
532
|
+
else
|
533
|
+
sample = line.strip.chomp
|
534
|
+
if ( !sample.nil? && sample.size > 0 )
|
535
|
+
samples["ADC#{adc_sample}".to_sym] = line.strip.chomp
|
536
|
+
adc_sample += 1
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
linenum += 1
|
541
|
+
end
|
542
|
+
|
543
|
+
@xbee_serialport.read_timeout = tmp
|
544
|
+
samples
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
##
|
549
|
+
# writes the current XBee configuration to the XBee device's flash. There
|
550
|
+
# is no undo for this operation
|
551
|
+
def save!
|
552
|
+
@xbee_serialport.write("ATWR\r")
|
553
|
+
getresponse if self.transmission_mode == :SYNC
|
554
|
+
end
|
555
|
+
|
556
|
+
##
|
557
|
+
# Resets the XBee module through software and simulates a power off/on. Any configuration
|
558
|
+
# changes that have not been saved with the save! method will be lost during reset.
|
559
|
+
#
|
560
|
+
# The module responds immediately with "OK" then performs a reset ~2 seconds later.
|
561
|
+
# The reset is a required when the module's SC or ID has been changes to take into affect.
|
562
|
+
def reset!
|
563
|
+
@xbee_serialport.write("ATFR\r")
|
564
|
+
end
|
565
|
+
|
566
|
+
##
|
567
|
+
# Performs a network reset on one or more modules within a PAN. The module responds
|
568
|
+
# immediately with an "OK" and then restarts the network. All network configuration
|
569
|
+
# and routing information is lost if not saved.
|
570
|
+
#
|
571
|
+
# Parameter range: 0-1
|
572
|
+
# * 0: Resets network layer parameters on the node issuing the command.
|
573
|
+
# * 1: Sends broadcast transmission to reset network layer parameters on all nodes in the PAN.
|
574
|
+
def network_reset!(reset_range)
|
575
|
+
if reset_range == 0
|
576
|
+
@xbee_serialport.write("ATNR0\r")
|
577
|
+
elsif reset_range == 1 then
|
578
|
+
@xbee_serialport.write("ATNR1\r")
|
579
|
+
else
|
580
|
+
#### DEBUG ####
|
581
|
+
if $DEBUG then
|
582
|
+
puts "Invalid parameter provided: #{reset_range}"
|
583
|
+
end
|
584
|
+
#### DEBUG ####
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
##
|
589
|
+
# Restores all the module parameters to factory defaults
|
590
|
+
# Restore (RE) command does not reset the ID parameter.
|
591
|
+
def restore!
|
592
|
+
@xbee_serialport.write("ATRE\r")
|
593
|
+
end
|
594
|
+
|
595
|
+
##
|
596
|
+
# just a straight pass through of data to the XBee. This can be used to send
|
597
|
+
# data when not in AT command mode, or if you want to control the XBee with raw
|
598
|
+
# commands, you can send them this way.
|
599
|
+
def send!(message)
|
600
|
+
@xbee_serialport.write( message )
|
601
|
+
end
|
602
|
+
|
603
|
+
##
|
604
|
+
# exits the AT command mode - all changed parameters will take effect such as baud rate changes
|
605
|
+
# after the exit is complete. exit_command_mode does not permanently save the parameter changes
|
606
|
+
# when it exits AT command mode. In order to permanently change parameters, use the save! method
|
607
|
+
def exit_command_mode
|
608
|
+
@xbee_serialport.write("ATCN\r")
|
609
|
+
end
|
610
|
+
|
611
|
+
##
|
612
|
+
# returns the version of this class
|
613
|
+
def version
|
614
|
+
VERSION
|
615
|
+
end
|
616
|
+
|
617
|
+
##
|
618
|
+
# returns results from the XBee
|
619
|
+
def getresponse
|
620
|
+
XBee::Frame.new(self.xbee_serialport, self.api_mode.in_symbol)
|
621
|
+
end
|
622
|
+
|
623
|
+
end
|
624
|
+
|
625
|
+
class Series1APIModeInterface < BaseAPIModeInterface
|
626
|
+
##
|
627
|
+
# returns the source address of the XBee device - the MY address value
|
628
|
+
def my_src_address
|
629
|
+
@my_src_address ||= get_param("MY")
|
630
|
+
end
|
631
|
+
end # class Series1APIModeInterface
|
632
|
+
|
633
|
+
class Series2APIModeInterface < BaseAPIModeInterface
|
634
|
+
##
|
635
|
+
# Initiating the application firmware OTA upgrade for Programmable XBee modules
|
636
|
+
def init_ota_upgrade(password = nil, remote_address = 0x000000000000ffff, remote_network_address = 0xfffe)
|
637
|
+
frame_id = self.next_frame_id
|
638
|
+
command_frame = XBee::Frame::ExplicitAddressingCommand.new(frame_id, remote_address, remote_network_address, 0xE8, 0xE8, 0x1000, 0xC105, 0x00, 0x00, password)
|
639
|
+
self.xbee_serialport.write(command_frame._dump(self.api_mode.in_symbol))
|
640
|
+
end
|
641
|
+
end # class Series2APIModeInterface
|
642
|
+
end
|