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