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.
@@ -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