ruby-xbee 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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