ruxbee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,554 @@
1
+ require 'ruxbee/rfmodule'
2
+
3
+ module XBee
4
+ class BaseCommandModeInterface < RFModule
5
+
6
+ VERSION = "1.0" # Version of this class
7
+
8
+ ##
9
+ # initializes the communication link with the XBee device. These parameters must match those which
10
+ # are configured in the XBee in order to establish communication.
11
+
12
+ # xbee_usbdev_str is a path to the device used to communicate with the XBee. Typically it may
13
+ # look like: /dev/tty.usbserial-A80081sF if you're using a USB to serial converter or a device such
14
+ # as http://www.sparkfun.com/commerce/product_info.php?products_id=8687
15
+ def initialize( xbee_usbdev_str, baud, data_bits, stop_bits, parity )
16
+ # open serial port device to XBee
17
+ @xbee_serialport = SerialPort.new( xbee_usbdev_str, baud.to_i, data_bits.to_i, stop_bits.to_i, parity )
18
+ @xbee_serialport.read_timeout = self.read_timeout(:short)
19
+ @baudcodes = { 1200 => 0, 2400 => 1, 4800 => 2, 9600 => 3, 19200 => 4, 38400 => 5, 57600 => 6, 115200 => 7 }
20
+ @paritycodes = { :None => 0, :Even => 1, :Odd => 2, :Mark => 3, :Space => 4 }
21
+ @iotypes = { :Disabled => 0, :ADC => 2, :DI => 3, :DO_Low => 4, :DO_High => 5,
22
+ :Associated_Indicator => 1, :RTS => 1, :CTS => 1, :RS485_Low => 6, :RS485_High => 7 }
23
+ end
24
+
25
+
26
+ =begin rdoc
27
+ Puts the XBee into AT command mode and insures that we can bring it to attention.
28
+ The expected return value is "OK"
29
+ =end
30
+ def attention
31
+ @xbee_serialport.write("+++")
32
+ sleep 1
33
+ getresponse # flush up to +++ response if needed
34
+ # if XBee is already in command mode, there will be no response, so make an explicit
35
+ # AT call to insure an OK response
36
+ @xbee_serialport.write("AT\r")
37
+ getresponse.strip.chomp
38
+ end
39
+
40
+ =begin rdoc
41
+ Retrieve XBee firmware version
42
+ =end
43
+ def fw_rev
44
+ @xbee_serialport.write("ATVR\r")
45
+ response = getresponse
46
+ response.strip.chomp if response
47
+ end
48
+
49
+ =begin rdoc
50
+ Retrieve XBee hardware version
51
+ =end
52
+ def hw_rev
53
+ @xbee_serialport.write("ATHV\r")
54
+ response = getresponse
55
+ response.strip.chomp if response
56
+ end
57
+
58
+ =begin rdoc
59
+ Neighbor node discovery. Returns an array of hashes each element of the array contains a hash
60
+ each hash contains keys: :MY, :SH, :SL, :DB, :NI
61
+ representing addresses source address, Serial High, Serial Low, Received signal strength,
62
+ node identifier respectively. Aan example of the results returned (hash as seen by pp):
63
+
64
+ [{:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"4008A642", :DB=>-24},
65
+ {:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"4008A697", :DB=>-33},
66
+ {:NI=>" ", :MY=>"0", :SH=>"13A200", :SL=>"40085AD5", :DB=>-52}]
67
+
68
+ Signal strength (:DB) is reported in units of -dBM.
69
+ =end rdoc
70
+ def neighbors
71
+ # neighbors often takes more than 1000ms to return data
72
+ tmp = @xbee_serialport.read_timeout
73
+ @xbee_serialport.read_timeout = read_timeout(:long)
74
+ @xbee_serialport.write("ATND\r")
75
+ response = getresponse
76
+
77
+ # parse nodes and stuff an array of hashes
78
+ @neighbors = Array.new
79
+ linetype = 0
80
+ neighbor = 0
81
+
82
+ if response.nil?
83
+ return @neighbors # return an empty array
84
+ end
85
+
86
+ response.each_line do | line |
87
+
88
+ line.chomp!
89
+
90
+ if line.size > 0
91
+ case linetype
92
+ when 0 # MY
93
+ @neighbors[ neighbor ] = Hash.new
94
+ @neighbors[ neighbor ].store( :MY, line )
95
+
96
+ when 1 # SH
97
+ @neighbors[ neighbor ].store( :SH, line )
98
+
99
+ when 2 # SL
100
+ @neighbors[ neighbor ].store( :SL, line )
101
+
102
+ when 3 # DB
103
+ @neighbors[ neighbor ].store( :DB, -(line.hex) )
104
+
105
+ when 4 # NI
106
+ @neighbors[ neighbor ].store( :NI, line )
107
+
108
+ neighbor += 1
109
+ end
110
+
111
+ if linetype < 4
112
+ linetype += 1
113
+ else
114
+ linetype = 0
115
+ end
116
+ end
117
+ end
118
+
119
+ @xbee_serialport.read_timeout = tmp
120
+ @neighbors
121
+ end
122
+
123
+ =begin rdoc
124
+ returns the source address of the XBee device - the MY address value
125
+ =end
126
+ def my_src_address
127
+ @xbee_serialport.write("ATMY\r")
128
+ getresponse.strip.chomp
129
+ end
130
+
131
+ =begin rdoc
132
+ sets the 16-bit source address of the XBee device. The parameter should be a 16-bit hex value.
133
+ The factory default is 0. By setting the MY src address to 0xffff, 16-bit addressing is disabled
134
+ and the XBee will not listen for packets with 16-bit address fields
135
+ =end
136
+ def my_src_address!(new_addr)
137
+ @xbee_serialport.write("ATMY#{new_addr}\r")
138
+ getresponse
139
+ end
140
+
141
+ =begin rdoc
142
+ returns the low portion of the XBee device's current destination address
143
+ =end
144
+ def destination_low
145
+ @xbee_serialport.write("ATDL\r")
146
+ getresponse
147
+ end
148
+
149
+ =begin rdoc
150
+ sets the low portion of the XBee device's destination address
151
+ =end
152
+ def destination_low!(low_addr)
153
+ @xbee_serialport.write("ATDL#{low_addr}\r")
154
+ getresponse
155
+ end
156
+
157
+ =begin rdoc
158
+ returns the high portion of the XBee device's current destination address
159
+ =end
160
+ def destination_high
161
+ @xbee_serialport.write("ATDH\r")
162
+ getresponse
163
+ end
164
+
165
+ =begin rdoc
166
+ sets the high portion of the XBee device's current destination address
167
+ =end
168
+ def destination_high!(high_addr)
169
+ @xbee_serialport.write("ATDH#{high_addr}\r")
170
+ getresponse
171
+ end
172
+
173
+ =begin rdoc
174
+ returns the low portion of the XBee device's serial number. this value is factory set.
175
+ =end
176
+ def serial_num_low
177
+ @xbee_serialport.write("ATSL\r")
178
+ getresponse
179
+ end
180
+
181
+ =begin rdoc
182
+ returns the high portion of the XBee devices serial number. this value is factory set.
183
+ =end
184
+ def serial_num_high
185
+ @xbee_serialport.write("ATSH\r")
186
+ getresponse
187
+ end
188
+
189
+ =begin rdoc
190
+ returns the channel number of the XBee device. this value, along with the PAN ID,
191
+ and MY address determines the addressability of the device and what it can listen to
192
+ =end
193
+ def channel
194
+ # channel often takes more than 1000ms to return data
195
+ tmp = @xbee_serialport.read_timeout
196
+ @xbee_serialport.read_timeout = read_timeout(:long)
197
+ @xbee_serialport.write("ATCH\r")
198
+ response = getresponse
199
+ @xbee_serialport.read_timeout = tmp
200
+ response.strip.chomp if response
201
+ end
202
+
203
+ =begin rdoc
204
+ sets the channel number of the device. The valid channel numbers are those of the 802.15.4 standard.
205
+ =end
206
+ def channel!(new_channel)
207
+ # channel takes more than 1000ms to return data
208
+ tmp = @xbee_serialport.read_timeout
209
+ @xbee_serialport.read_timeout = read_timeout(:long)
210
+ @xbee_serialport.write("ATCH#{new_channel}\r")
211
+ response = getresponse
212
+ @xbee_serialport.read_timeout = tmp
213
+ response.strip.chomp if response
214
+ end
215
+
216
+ =begin rdoc
217
+ returns the node ID of the device. Node ID is typically a human-meaningful name
218
+ to give to the XBee device, much like a hostname.
219
+ =end
220
+ def node_id
221
+ tmp = @xbee_serialport.read_timeout
222
+ @xbee_serialport.read_timeout = read_timeout(:long)
223
+ @xbee_serialport.write("ATNI\r")
224
+ response = getresponse()
225
+ @xbee_serialport.read_timeout = tmp
226
+ if ( response.nil? )
227
+ return ""
228
+ else
229
+ response.strip.chomp
230
+ end
231
+ end
232
+
233
+ =begin rdoc
234
+ sets the node ID to a user-definable text string to make it easier to
235
+ identify the device with "human" names. This node id is reported to
236
+ neighboring XBees so consider it "public".
237
+ =end
238
+ def node_id!(new_id)
239
+ tmp = @xbee_serialport.read_timeout
240
+ @xbee_serialport.read_timeout = read_timeout(:long)
241
+ @xbee_serialport.write("ATNI#{new_id}\r")
242
+ response = getresponse
243
+ @xbee_serialport.read_timeout = tmp
244
+ if ( response.nil? )
245
+ return ""
246
+ else
247
+ response.strip.chomp
248
+ end
249
+ end
250
+ =begin rdoc
251
+ returns the PAN ID of the device. PAN ID is one of the 3 main identifiers used to
252
+ communicate with the device from other XBees. All XBees which are meant to communicate
253
+ must have the same PAN ID and channel number. The 3rd identifier is the address of the
254
+ device itself represented by its serial number (High and Low) and/or it's 16-bit MY
255
+ source address.
256
+ =end
257
+ def pan_id
258
+ @xbee_serialport.write("ATID\r")
259
+ getresponse
260
+ end
261
+
262
+ =begin rdoc
263
+ sets the PAN ID of the device. Modules must have the same PAN ID in order to communicate
264
+ with each other. The PAN ID value can range from 0 - 0xffff. The default from the factory
265
+ is set to 0x3332.
266
+ =end
267
+ def pan_id!(new_id)
268
+ @xbee_serialport.write("ATID#{new_id}\r")
269
+ getresponse
270
+ end
271
+
272
+ =begin rdoc
273
+ returns the signal strength in dBm units of the last received packet. Expect a negative integer
274
+ or 0 to be returned. If the XBee device has not received any neighboring packet data, the signal strength
275
+ value will be 0
276
+ =end
277
+ def received_signal_strength
278
+ @xbee_serialport.write("ATDB\r")
279
+ response = getresponse.strip.chomp
280
+ # this response is an absolute hex value which is in -dBm
281
+ # modify this so it returns actual - dBm value
282
+ dbm = -(response.hex) if response
283
+ end
284
+
285
+ =begin rdoc
286
+ retrieves the baud rate of the device. Generally, this will be the same as the
287
+ rate you're currently using to talk to the device unless you've changed the device's
288
+ baud rate and are still in the AT command mode and/or have not exited command mode explicitly for
289
+ the new baud rate to take effect.
290
+ =end
291
+ def baud
292
+ @xbee_serialport.write("ATBD\r")
293
+ baudcode = getresponse
294
+ @baudcodes.key( baudcode.to_i )
295
+ end
296
+
297
+ =begin rdoc
298
+ sets the given baud rate into the XBee device. The baud change will not take
299
+ effect until the AT command mode times out or the exit command mode command is given.
300
+ acceptable baud rates are: 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
301
+ end
302
+ =end
303
+ def baud!( baud_rate )
304
+ @xbee_serialport.write("ATBD#{@baudcodes[baud_rate]}\r")
305
+ getresponse
306
+ end
307
+
308
+ =begin rdoc
309
+ returns the parity of the device as represented by a symbol:
310
+ :None - for 8-bit none
311
+ :Even - for 8-bit even
312
+ :Odd - for 8-bit odd
313
+ :Mark - for 8-bit mark
314
+ :Space - for 8-bit space
315
+ =end
316
+ def parity
317
+ @xbee_serialport.write("ATNB\r")
318
+ response = getresponse().strip.chomp
319
+ @paritycodes.key( response.to_i )
320
+ end
321
+
322
+ =begin rdoc
323
+ sets the parity of the device to one represented by a symbol contained in the parity_type parameter
324
+ :None - for 8-bit none
325
+ :Even - for 8-bit even
326
+ :Odd - for 8-bit odd
327
+ :Mark - for 8-bit mark
328
+ :Space - for 8-bit space
329
+ =end
330
+ def parity!( parity_type )
331
+ # validate symbol before writing parity param
332
+ if !@paritycodes.include?(parity_type)
333
+ return false
334
+ end
335
+ @xbee_serialport.write("ATNB#{@paritycodes[parity_type]}\r")
336
+ getresponse
337
+ end
338
+
339
+ =begin rdoc
340
+ reads an i/o port configuration on the XBee for analog to digital or digital input or output (GPIO)
341
+
342
+ this method returns an I/O type symbol of:
343
+
344
+ :Disabled
345
+ :ADC
346
+ :DI
347
+ :DO_Low
348
+ :DO_High
349
+ :Associated_Indicator
350
+ :RTS
351
+ :CTS
352
+ :RS485_Low
353
+ :RS485_High
354
+
355
+ Not all DIO ports are capable of every configuration listed above. This method will properly translate
356
+ the XBee's response value to the symbol above when the same value has different meanings from port to port.
357
+
358
+ The port parameter may be any symbol :D0 through :D8 representing the 8 I/O ports on an XBee
359
+ =end
360
+
361
+ def dio( port )
362
+ at = "AT#{port.to_s}\r"
363
+ @xbee_serialport.write( at )
364
+ response = getresponse.to_i
365
+
366
+ if response == 1 # the value of 1 is overloaded based on port number
367
+ case port
368
+ when :D5
369
+ return :Associated_Indicator
370
+ when :D6
371
+ return :RTS
372
+ when :D7
373
+ return :CTS
374
+ end
375
+ else
376
+ @iotypes.key(response)
377
+ end
378
+
379
+ end
380
+
381
+ =begin rdoc
382
+ configures an i/o port on the XBee for analog to digital or digital input or output (GPIO)
383
+
384
+ port parameter valid values are the symbols :D0 through :D8
385
+
386
+ iotype parameter valid values are symbols:
387
+ :Disabled
388
+ :ADC
389
+ :DI
390
+ :DO_Low
391
+ :DO_High
392
+ :Associated_Indicator
393
+ :RTS
394
+ :CTS
395
+ :RS485_Low
396
+ :RS485_High
397
+
398
+ note: not all iotypes are compatible with every port type, see the XBee manual for exceptions and semantics
399
+
400
+ note: it is critical you have upgraded firmware in your XBee or DIO ports 0-4 cannot be read
401
+ (ie: ATD0 will return ERROR - this is an XBee firmware bug that's fixed in revs later than 1083)
402
+
403
+ note: tested with rev 10CD, fails with rev 1083
404
+ =end
405
+
406
+ def dio!( port, iotype )
407
+ at = "AT#{port.to_s}#{@iotypes[iotype]}\r"
408
+ @xbee_serialport.write( at )
409
+ getresponse
410
+ end
411
+
412
+ =begin rdoc
413
+ reads the bitfield values for change detect monitoring. returns a bitmask indicating
414
+ which DIO lines, 0-7 are enabled or disabled for change detect monitoring
415
+ =end
416
+ def dio_change_detect
417
+ @xbee_serialport.write("ATIC\r")
418
+ getresponse
419
+ end
420
+
421
+ =begin rdoc
422
+ sets the bitfield values for change detect monitoring. The hexbitmap parameter is a bitmap
423
+ which enables or disables the change detect monitoring for any of the DIO ports 0-7
424
+ =end
425
+ def dio_change_detect!( hexbitmap )
426
+ @xbee_serialport.write("ATIC#{hexbitmask}\r")
427
+ getresponse
428
+ end
429
+
430
+ =begin rdoc
431
+ Sets the digital output levels of any DIO lines which were configured for output using the dio! method.
432
+ The parameter, hexbitmap, is a hex value which represents the 8-bit bitmap of the i/o lines on the
433
+ XBee.
434
+ =end
435
+ def io_output!( hexbitmap )
436
+ @xbee_serialport.write("ATIO#{hexbitmap}\r")
437
+ getresponse
438
+ end
439
+
440
+ =begin rdoc
441
+ Forces a sampling of all DIO pins configured for input via dio!
442
+ Returns a hash with the following key/value pairs:
443
+ :NUM => number of samples
444
+ :CM => channel mask
445
+ :DIO => dio data if DIO lines are enabled
446
+ :ADCn => adc sample data (one for each ADC channel enabled)
447
+ =end
448
+ def io_input
449
+
450
+ tmp = @xbee_serialport.read_timeout
451
+ @xbee_serialport.read_timeout = read_timeout(:long)
452
+
453
+ @xbee_serialport.write("ATIS\r")
454
+ response = getresponse
455
+ linenum = 1
456
+ adc_sample = 1
457
+ samples = Hash.new
458
+
459
+ if response.match("ERROR")
460
+ samples[:ERROR] = "ERROR"
461
+ return samples
462
+ end
463
+
464
+ # otherwise parse input data
465
+ response.each_line do | line |
466
+ case linenum
467
+ when 1
468
+ samples[:NUM] = line.to_i
469
+ when 2
470
+ samples[:CM] = line.strip.chomp if line
471
+ when 3
472
+ samples[:DIO] = line.strip.chomp if line
473
+ else
474
+ sample = line.strip.chomp if line
475
+ if ( !sample.nil? && sample.size > 0 )
476
+ samples["ADC#{adc_sample}".to_sym] = line.strip.chomp if line
477
+ adc_sample += 1
478
+ end
479
+ end
480
+
481
+ linenum += 1
482
+ end
483
+
484
+ @xbee_serialport.read_timeout = tmp
485
+ samples
486
+ end
487
+
488
+ =begin rdoc
489
+ writes the current XBee configuration to the XBee device's flash. There
490
+ is no undo for this operation
491
+ =end
492
+ def save!
493
+ @xbee_serialport.write("ATWR\r")
494
+ getresponse
495
+ end
496
+
497
+ =begin rdoc
498
+ resets the XBee module through software and simulates a power off/on. Any configuration
499
+ changes that have not been saved with the save! method will be lost during reset.
500
+ =end
501
+ def reset!
502
+ @xbee_serialport.write("ATFR\r")
503
+ end
504
+
505
+ =begin rdoc
506
+ Restores all the module parameters to factory defaults
507
+ =end
508
+ def restore!
509
+ @xbee_serialport.write("ATRE\r")
510
+ end
511
+
512
+ =begin rdoc
513
+ just a straight pass through of data to the XBee. This can be used to send
514
+ data when not in AT command mode, or if you want to control the XBee with raw
515
+ commands, you can send them this way.
516
+ =end
517
+ def send!(message)
518
+ @xbee_serialport.write( message )
519
+ end
520
+
521
+
522
+ =begin rdoc
523
+ exits the AT command mode - all changed parameters will take effect such as baud rate changes
524
+ after the exit is complete. exit_command_mode does not permanently save the parameter changes
525
+ when it exits AT command mode. In order to permanently change parameters, use the save! method
526
+ =end
527
+ def exit_command_mode
528
+ @xbee_serialport.write("ATCN\r")
529
+ end
530
+
531
+ =begin rdoc
532
+ returns the version of this class
533
+ =end
534
+ def version
535
+ VERSION
536
+ end
537
+
538
+ =begin rdoc
539
+ returns results from the XBee
540
+ =end
541
+ def getresponse
542
+ getresults @xbee_serialport
543
+ end
544
+
545
+ end
546
+
547
+ class XBeeV1CommandModeInterface < BaseCommandModeInterface
548
+
549
+ end # class XBeeV1ATInterface
550
+
551
+ class XBeeV2CommandModeInterface < BaseCommandModeInterface
552
+
553
+ end # class XBeeV2ATInterface
554
+ end
data/lib/ruxbee.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "ruxbee/version"
2
+ require "ruxbee/config"
3
+ require "ruxbee/xbee_api"
4
+ require "ruxbee/xbee_cmd"
5
+
6
+ module Ruxbee
7
+
8
+ ##
9
+ # creates a new instance on Command or API mode
10
+ # mode is a Symbol, either :API_S1, :API_S2 or :CMD
11
+ def XBee.new(dev_str, baud, mode, operation_mode = :API)
12
+ # check for valid mode descriptor
13
+ unless mode.is_a? Symbol and (mode == :API_S1 or mode == :API_S2 or mode == :CMD)
14
+ raise "Not a valid mode, choose :API_S1, :API_S2 or :CMD"
15
+ end
16
+
17
+ unless operation_mode.is_a? Symbol and (operation_mode == :API or operation_mode == :AT)
18
+ raise "Not a valid operation_mode, choose :API or :AT"
19
+ end
20
+
21
+ # defaults to: data_bits = 8, parity = 0, stop_bits = 1
22
+ uart_conf = XBee::Config::XBeeUARTConfig.new(baud)
23
+
24
+ case mode
25
+ when :API_S1
26
+ XBee::Series1APIModeInterface.new(dev_str, uart_conf, operation_mode)
27
+ when :API_S2
28
+ XBee::Series2APIModeInterface.new(dev_str, uart_conf, operation_mode)
29
+ # Series2APIModeInterface.new(dev_str, uart_conf, operation_mode, transmission_mode = :SYNC)
30
+ when :CMD
31
+ XBee::BaseCommandModeInterface.new(dev_str, uart_conf.baud, uart_conf.data_bits, uart_conf.stop_bits, uart_conf.parity)
32
+ else
33
+ raise "Unknown Exception, no mode was found"
34
+ end
35
+ end
36
+
37
+ end
data/ruxbee.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruxbee/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ruxbee"
8
+ spec.version = Ruxbee::VERSION
9
+ spec.authors = ['Ricardo Carrasco-Cursach', 'Landon Cox', 'Mike Ashmore', 'Sten Feldman']
10
+ spec.email = ["rccursach@gmail.com"]
11
+ spec.licenses = ['AGPL']
12
+
13
+ spec.summary = "Ruby Gem for XBee forked from ruby-xbee"
14
+ spec.description = "A lighter XBee S1 and S2 library for ruby"
15
+ spec.homepage = "http://www.github.com/rccursach/ruxbee"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_runtime_dependency "serialport", ">= 1.3.1"
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end