phidgets_native 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/Gemfile.lock +12 -0
- data/README.rdoc +176 -0
- data/Rakefile +31 -0
- data/examples/gps.rb +25 -0
- data/examples/interface_kit.rb +61 -0
- data/examples/lib/common.rb +51 -0
- data/examples/lib/console_table.rb +38 -0
- data/examples/list_all.rb +16 -0
- data/examples/spatial.rb +53 -0
- data/ext/phidgets_native/accelerometer_ruby.c +36 -0
- data/ext/phidgets_native/advancedservo_ruby.c +33 -0
- data/ext/phidgets_native/analog_ruby.c +34 -0
- data/ext/phidgets_native/bridge_ruby.c +32 -0
- data/ext/phidgets_native/device.c +68 -0
- data/ext/phidgets_native/device_ruby.c +404 -0
- data/ext/phidgets_native/encoder_ruby.c +34 -0
- data/ext/phidgets_native/extconf.rb +18 -0
- data/ext/phidgets_native/frequencycounter_ruby.c +32 -0
- data/ext/phidgets_native/gps.c +102 -0
- data/ext/phidgets_native/gps_ruby.c +212 -0
- data/ext/phidgets_native/interfacekit.c +203 -0
- data/ext/phidgets_native/interfacekit_ruby.c +507 -0
- data/ext/phidgets_native/ir_ruby.c +33 -0
- data/ext/phidgets_native/led_ruby.c +33 -0
- data/ext/phidgets_native/motorcontrol_ruby.c +32 -0
- data/ext/phidgets_native/phidgets_native.c +197 -0
- data/ext/phidgets_native/phidgets_native.h +320 -0
- data/ext/phidgets_native/phidgets_native_ruby.c +468 -0
- data/ext/phidgets_native/phsensor_ruby.c +32 -0
- data/ext/phidgets_native/rfid_ruby.c +31 -0
- data/ext/phidgets_native/servo_ruby.c +31 -0
- data/ext/phidgets_native/spatial.c +168 -0
- data/ext/phidgets_native/spatial_ruby.c +533 -0
- data/ext/phidgets_native/stepper_ruby.c +32 -0
- data/ext/phidgets_native/temperaturesensor_ruby.c +31 -0
- data/ext/phidgets_native/textlcd_ruby.c +31 -0
- data/ext/phidgets_native/textled_ruby.c +31 -0
- data/ext/phidgets_native/weightsensor_ruby.c +32 -0
- data/phidgets_native.gemspec +21 -0
- metadata +96 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
=What is PhidgetsNative
|
2
|
+
This library is a set of classes for use with the excellent USB sensing and
|
3
|
+
controller devices available for sale on phidgets.com. If you're a ruby programmer
|
4
|
+
and need to interface your code with meat-space concerns, these devices (and this
|
5
|
+
library) are what you need.
|
6
|
+
|
7
|
+
==What's a Phidget?
|
8
|
+
Phidgets are well supported on almost any operating system, and require practically
|
9
|
+
no knowledge of electrical engineering or digital circuitry. Each device is a stand-
|
10
|
+
alone "plug and play" building block that works on it's own , or in conjunction
|
11
|
+
with other phidgets.
|
12
|
+
|
13
|
+
You can browse the phidget product catalog on {www.phidgets.com}[http://www.phidgets.com].
|
14
|
+
|
15
|
+
==Tested Environments
|
16
|
+
As of this writing, this gem is stable, and actively tested on:
|
17
|
+
* x86_64 on OS X
|
18
|
+
* x86_64 on Linux
|
19
|
+
* armv6l on Linux
|
20
|
+
|
21
|
+
Presumably most other UNIX variants will work just fine. Probably win32/win64
|
22
|
+
will not.
|
23
|
+
|
24
|
+
==Supported Devices
|
25
|
+
As of this version, we currently only support the following phidgets:
|
26
|
+
* Phidget Spatial
|
27
|
+
* Phidget GPS
|
28
|
+
* Phidget Interface Kit
|
29
|
+
There will soon be support for the "Phidget Servo" phidget. If you have a phidget
|
30
|
+
that's not on our current compatibility list, either get me a copy of the phidget
|
31
|
+
to work with at my desk, or check out the existing modules for a reference in
|
32
|
+
setting up your own class, and push your changes to my repo. Most of the difficult
|
33
|
+
work is done, and you'll find plenty of stubs to work with for nearly all the
|
34
|
+
available phidgets.
|
35
|
+
|
36
|
+
=Why not Phidgets-FFI?
|
37
|
+
Though encompassing, Phidgets-FFI is seemingly quite buggy, and a bit slow. Particularly
|
38
|
+
with Garbage collection turned on. I think that the threading model of the Phidgets
|
39
|
+
C API is simply incompatible with the design of the ruby-ffi library. Additionally,
|
40
|
+
running the ffi gem on arm environments is outright unusable.
|
41
|
+
|
42
|
+
Caveats aside, the Phidgets-FFI library interfaces are elegant and well thought-out,
|
43
|
+
and this library's interfaces (and even this README) are heavily influenced by
|
44
|
+
them. Converting your existing code base to use this library shouldn't be too
|
45
|
+
difficult.
|
46
|
+
|
47
|
+
==Differences with Phidgets-FFI
|
48
|
+
The Phidgets-FFI library has a number of methods which accept blocks. This library
|
49
|
+
has none. Maybe that will change in the future.
|
50
|
+
|
51
|
+
There are currently no plans to support event-driven interfaces. Though this was
|
52
|
+
an excellent feature of the ffi library, it adds a significant degree of complexity
|
53
|
+
to a stable implementation of this library. Indeed, most of the stability issues
|
54
|
+
arise when attempting to use these features in the ffi implementation.
|
55
|
+
|
56
|
+
Additionally, the phidgets-ffi implementation is a little strange with it's support
|
57
|
+
of device disconnects and reconnects. Here in the 'native' implementation, once
|
58
|
+
a device object is created, it stays 'active' regardless of whether the device
|
59
|
+
is attached. If the device is disconnected and reconnected, your phidget object
|
60
|
+
will automatically re-register its handlers with the device, and continue to
|
61
|
+
function as if the device were never disconnected to begin with. Keep in mind that
|
62
|
+
any attributes relating to the device's capabilities (mostly those in the
|
63
|
+
Phidget::Device class, though there are things like the axial extents in the
|
64
|
+
spatial object) will be 'cached' from the previous connection. "State" attributes
|
65
|
+
(such as the spatial's accelerometer output) will return nil or 0.
|
66
|
+
|
67
|
+
In practice, if you need an event-driven model for your code, you can almost certainly
|
68
|
+
get by using a ruby thread with a polling loop, like so:
|
69
|
+
|
70
|
+
is_fixed_last = false
|
71
|
+
@poller = Thread.new(Phidget::GPS(12345)) do |gps|
|
72
|
+
gps.wait_for_attachment(10000)
|
73
|
+
|
74
|
+
begin
|
75
|
+
on_fixed_change(gps.is_fixed) if is_fixed_last != gps.is_fixed
|
76
|
+
is_fixed_last = gps.is_fixed?
|
77
|
+
end while sleep(0.1)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Carry on with the rest of your code here
|
81
|
+
|
82
|
+
I'm fairly certain that until ruby supports actual kernel-based threads, this is
|
83
|
+
the best you can reasonably do. Maybe we'll emulate the ffi library in this capacity
|
84
|
+
at some point in the future, if there's a demand to do so.
|
85
|
+
|
86
|
+
=Getting Started
|
87
|
+
First, we need to set up the proper environment and get the necessary files off
|
88
|
+
the Phidgets website. Visit the drivers section at www.phidgets.com and get the
|
89
|
+
latest Phidget driver for your system.
|
90
|
+
|
91
|
+
We also recommend that you read the following reference materials:
|
92
|
+
* {General Phidget Programming}[http://www.phidgets.com/docs/General_Phidget_Programming]
|
93
|
+
* The {User Guide}[http://www.phidgets.com/docs/Category:UserGuide] for your device
|
94
|
+
* {RubyDoc API Documentation}[http://rubydoc.info/gems/phidgets_native/frames]
|
95
|
+
* {Ruby code samples}[https://github.com/kreynolds/phidgets_native/tree/master/examples]
|
96
|
+
|
97
|
+
The RubyDoc API manual contains calls and events for every type of Phidget and
|
98
|
+
can be used as a reference. You can find a high level discussion about programming
|
99
|
+
with Phidgets in general on the General Phidget Programming page.
|
100
|
+
The user guide for your device also contains an API section that describes
|
101
|
+
limitations, defaults, and implementation details specific to your Phidget.
|
102
|
+
|
103
|
+
==Installing the phidgets_native gem
|
104
|
+
To install:
|
105
|
+
gem install phidgets_native
|
106
|
+
|
107
|
+
phidgets_native is very self contained. There's no dependencies on other ruby
|
108
|
+
gems or non-standard libraries. However, in order to compile this gem, you'll
|
109
|
+
need a suitable build environment for your system (clang on OSX or gcc on Linux),
|
110
|
+
and the aforementioned phidgets driver.
|
111
|
+
|
112
|
+
==Coding for your Phidget
|
113
|
+
Before you can use the Phidget, you must include a reference to the phidgets_native
|
114
|
+
gem:
|
115
|
+
require "rubygems"
|
116
|
+
require "phidgets_native"
|
117
|
+
|
118
|
+
Afterwards, Phidgets can be instantiated by creating the appropriate device class
|
119
|
+
object, with the device serial number passed to its constructor. At the moment,
|
120
|
+
only the 'local' devices are supported. If there's enough interest (or contributors)
|
121
|
+
I may add support for the 'remote' protocols which allow you to open a device
|
122
|
+
via its computer's IP address.
|
123
|
+
|
124
|
+
spatial = PhidgetsNative::Spatial.new 54321
|
125
|
+
|
126
|
+
The object name for any type of Phidget is listed in the API manual. Every type
|
127
|
+
of Phidget also inherits functionality from the Phidget base class (Which cannot
|
128
|
+
be instantiated by itself directly).
|
129
|
+
|
130
|
+
If you don't know the serial number of the device you're looking for, you can
|
131
|
+
use the Phidget.all method to return an array of the currently connected Phidgets
|
132
|
+
and/or you can simply run the included list_all.rb example.
|
133
|
+
|
134
|
+
One important thing to remember is that when working with Phidgets, a local connection
|
135
|
+
will reserve the device until closed. This prevents any other instances from
|
136
|
+
retrieving data from the Phidget, including other programs.
|
137
|
+
|
138
|
+
==Standard accessors
|
139
|
+
All devices support the accessors defined in the Phidget::Device class from which
|
140
|
+
they inherit.
|
141
|
+
|
142
|
+
==A note about device availability
|
143
|
+
Simply calling the constructor does not guarantee you can use the Phidget
|
144
|
+
immediately. The constructor merely sets up the Phidget handlers and event hooks,
|
145
|
+
but does not block the interpreter while it waits for the device to register.
|
146
|
+
For most people, you'll want immediate access to the phidget after the class has
|
147
|
+
been instantiated. As such, you'll need to call the wait_for_attachment method
|
148
|
+
on your new instance in order to start accessing the device properties.
|
149
|
+
|
150
|
+
The wait_for_attachment method will block until a connection is made to the
|
151
|
+
Phidget or until the provided timeout is exceeded.
|
152
|
+
|
153
|
+
ifkit = PhidgetsNative::InterfaceKit.new 24680
|
154
|
+
# halt the program for up 20000 microseconds or until the Phidget is connected:
|
155
|
+
ifkit.wait_for_attachment 20000
|
156
|
+
|
157
|
+
Though optional, it's recommended that you call close when you're done using your
|
158
|
+
phidget or when quitting your program.
|
159
|
+
|
160
|
+
ifkit.close
|
161
|
+
|
162
|
+
==Working with Multiple Phidgets
|
163
|
+
Multiple Phidgets of the same or different types can easily be run inside the
|
164
|
+
same program. However, there is seemingly a six-device limit, which is imposed
|
165
|
+
by the Phidget API and/or hardware.
|
166
|
+
|
167
|
+
==Logging
|
168
|
+
The phidget api has built in debug logging which can be enabled on a global basis
|
169
|
+
for all devices. By default, logs are sent to STDOUT, but you can optionally
|
170
|
+
pass a path to a text file where output can alternatively be redirected. You can
|
171
|
+
also send your own messages to the logger, if you think you have something you
|
172
|
+
need to add.
|
173
|
+
|
174
|
+
PhidgetsNative.enable_logging!(:verbose)
|
175
|
+
PhidgetsNative.log :info, "My favorite color is chartreuse"
|
176
|
+
PhidgetsNative.disable_logging!
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# File: Rakefile
|
2
|
+
|
3
|
+
require 'rake/extensiontask'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'rdoc/task'
|
6
|
+
|
7
|
+
spec = Gem::Specification.load('phidgets_native.gemspec')
|
8
|
+
|
9
|
+
Rake::ExtensionTask.new 'phidgets_native', spec
|
10
|
+
|
11
|
+
Gem::PackageTask.new(spec) do |pkg|
|
12
|
+
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
RDOC_FILES = FileList["README.rdoc", "ext/phidgets_native/phidgets_native_ruby.c",
|
17
|
+
"ext/phidgets_native/*_ruby.c"]
|
18
|
+
|
19
|
+
Rake::RDocTask.new do |rd|
|
20
|
+
rd.main = "README.rdoc"
|
21
|
+
rd.rdoc_dir = "doc/site/api"
|
22
|
+
rd.rdoc_files.include(RDOC_FILES)
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::RDocTask.new(:ri) do |rd|
|
26
|
+
rd.main = "README.rdoc"
|
27
|
+
rd.rdoc_dir = "doc/ri"
|
28
|
+
rd.options << "--ri-system"
|
29
|
+
rd.rdoc_files.include(RDOC_FILES)
|
30
|
+
end
|
31
|
+
|
data/examples/gps.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require '%s/lib/common' % File.dirname(__FILE__)
|
5
|
+
|
6
|
+
phidgets_example_for(PhidgetsNative::GPS) do |gps|
|
7
|
+
puts "\nPolled Values:"
|
8
|
+
|
9
|
+
i = 0
|
10
|
+
ConsoleTable.new( [
|
11
|
+
'Sample Rate',
|
12
|
+
'Is Fixed',
|
13
|
+
'%-18s' % 'Latitude',
|
14
|
+
'%-18s' % 'Longitude',
|
15
|
+
'%-18s' % 'Altitude',
|
16
|
+
'Heading',
|
17
|
+
'%-18s' % 'Velocity',
|
18
|
+
'%-23s' % 'Time (UTC)'
|
19
|
+
] ).output(:header => (i == 0), :separator => false) do |columns|
|
20
|
+
i+=1
|
21
|
+
[ [ '%s Hz' % gps.sample_rate ] + [gps.is_fixed?, gps.latitude,
|
22
|
+
gps.longitude, gps.altitude, gps.heading, gps.velocity].collect(&:inspect)+[
|
23
|
+
(gps.now_at_utc) ? gps.now_at_utc.strftime("%Y-%m-%d %H:%M:%S.%3N") : nil.inspect ] ]
|
24
|
+
end while sleep(3)
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require '%s/lib/common' % File.dirname(__FILE__)
|
5
|
+
|
6
|
+
#PhidgetsNative.enable_logging! :verbose
|
7
|
+
|
8
|
+
additional_attribs = [
|
9
|
+
%w(Digital\ Inputs input_count),
|
10
|
+
%w(Digital\ Outputs output_count),
|
11
|
+
%w(Analog\ Inputs sensor_count),
|
12
|
+
%w(Change\ Triggers change_triggers),
|
13
|
+
%w(Data\ Rates data_rates),
|
14
|
+
%w(Data\ Rates\ Min data_rates_min),
|
15
|
+
%w(Data\ Rates\ Max data_rates_max)
|
16
|
+
]
|
17
|
+
|
18
|
+
phidgets_example_for(PhidgetsNative::InterfaceKit, additional_attribs) do |ifkit|
|
19
|
+
# Here's how you set digital outputs:
|
20
|
+
(0...ifkit.output_count).each{ |i| ifkit.output i, i.even? }
|
21
|
+
|
22
|
+
# Let's adjust the data rates on each input a bit:
|
23
|
+
(0...ifkit.sensor_count).each do |i|
|
24
|
+
case (i % 4)
|
25
|
+
when 0
|
26
|
+
when 1
|
27
|
+
ifkit.data_rate i, ifkit.data_rates_max[i]
|
28
|
+
when 2
|
29
|
+
ifkit.change_trigger i, 1
|
30
|
+
when 3
|
31
|
+
ifkit.data_rate i, ifkit.data_rates_min[i]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Test sensor_raw
|
36
|
+
puts "Raw Analog sensor values:"
|
37
|
+
ConsoleTable.new((0...ifkit.sensor_count).collect{|i| "Sensor #{i}"}).output do
|
38
|
+
[(0...ifkit.sensor_count).collect{|i| ifkit.sensor_raw(i).inspect } ]
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "\nPolled Values:"
|
42
|
+
i = 0
|
43
|
+
ConsoleTable.new([
|
44
|
+
'Input Sample Rates',
|
45
|
+
'Sensor Sample Rates',
|
46
|
+
'Ratiometric?',
|
47
|
+
'%-40s' % 'sensors',
|
48
|
+
'%-20s' % 'inputs',
|
49
|
+
'%-20s' % 'outputs'
|
50
|
+
]).output(:header => (i == 0), :separator => false) do |columns|
|
51
|
+
i+=1
|
52
|
+
|
53
|
+
#TODO Test the ratiometric set at some point
|
54
|
+
|
55
|
+
[ [ifkit.input_sample_rates, ifkit.sensor_sample_rates, ifkit.ratiometric?.inspect,
|
56
|
+
ifkit.sensors.inspect]+[ifkit.inputs, ifkit.outputs].collect{ |bools|
|
57
|
+
(bools.kind_of? Array) ?
|
58
|
+
'[%s]' % bools.collect{|b| (b) ? '1' : '0' }.join(', ') : bools.inspect}
|
59
|
+
]
|
60
|
+
end while sleep(3)
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
$:.push *['%s/../../lib/', '%s'].collect{|p| p % File.dirname(__FILE__) }
|
4
|
+
|
5
|
+
require 'console_table'
|
6
|
+
require 'phidgets_native'
|
7
|
+
|
8
|
+
# To keep things DRY, I went ahead and put this here:
|
9
|
+
def phidgets_example_for(device_klass, extended_attribs = [], &block)
|
10
|
+
|
11
|
+
serial_number = $1.to_i if ARGV.length == 1 && /\A([\d]+)\Z/.match(ARGV[0])
|
12
|
+
|
13
|
+
unless serial_number
|
14
|
+
puts "Invalid or non-existant device serial number. This is a required parameter"
|
15
|
+
puts
|
16
|
+
puts "Usage: %s [device_serial]" % File.basename($PROGRAM_NAME)
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
device = device_klass.new serial_number
|
21
|
+
|
22
|
+
trap("SIGINT"){ device.close; exit }
|
23
|
+
|
24
|
+
begin
|
25
|
+
device.wait_for_attachment 10000
|
26
|
+
rescue PhidgetsNative::TimeoutError
|
27
|
+
puts "Unable to enumerate the phidget of type %s with the serial number %d." % [
|
28
|
+
device.class.to_s, device.serial_number]
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
puts "Using Library version: "+PhidgetsNative::LIBRARY_VERSION
|
33
|
+
|
34
|
+
puts "\nDevice Attributes:"
|
35
|
+
|
36
|
+
|
37
|
+
ConsoleTable.new(%w(Attribute Value)).output do
|
38
|
+
[ ["Type", device.type.inspect],
|
39
|
+
["Name", device.name.inspect],
|
40
|
+
["Label", device.label.inspect],
|
41
|
+
["Serial", device.serial_number.inspect],
|
42
|
+
["Version", device.version.inspect],
|
43
|
+
["Device class", device.device_class.inspect],
|
44
|
+
["Device id", device.device_id.inspect] ]+extended_attribs.collect{|pairs|
|
45
|
+
label, attr = pairs
|
46
|
+
[label, device.send(attr.to_sym)]
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
block.call(device)
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Just a quickie hack-class I made to make the test scripts easier to understand
|
4
|
+
# and DRY
|
5
|
+
class ConsoleTable
|
6
|
+
ERR_ROW_LENGTH = "All Rows must have the same number of columns"
|
7
|
+
|
8
|
+
def initialize(column_labels)
|
9
|
+
@columns = column_labels
|
10
|
+
end
|
11
|
+
|
12
|
+
def output(options = {}, &block)
|
13
|
+
rows = block.call(@columns)
|
14
|
+
if rows.length > 0
|
15
|
+
raise StandardError, ERR_ROW_LENGTH if rows.any?{|r| r.length != @columns.length}
|
16
|
+
|
17
|
+
# Find the widest cell widths:
|
18
|
+
widths = ([@columns]+rows).inject(Array.new(@columns.length,0)){|ret, row|
|
19
|
+
(0...row.length).collect{|i| (ret[i] >= row[i].to_s.length) ? ret[i] : row[i].to_s.length }
|
20
|
+
}
|
21
|
+
|
22
|
+
# Construct the separator and end_cap rows:
|
23
|
+
end_cap, separator = %w(+%s+ |%s|).collect{|fmt|
|
24
|
+
fmt % widths.collect{|width| "-" * (width+4) }.join('|')
|
25
|
+
}
|
26
|
+
|
27
|
+
row_fmt = '| %s |' % widths.collect{|width| "%-#{width}s"}.join(' | ')
|
28
|
+
|
29
|
+
puts [
|
30
|
+
(options[:header] == false) ? nil : [ end_cap, row_fmt % @columns, separator],
|
31
|
+
rows.to_enum(:each_with_index).collect{ |row,i |
|
32
|
+
[ (options[:separator] == false || i == 0) ? nil : separator, row_fmt % row ] },
|
33
|
+
(options[:footer] == false) ? nil : end_cap
|
34
|
+
].flatten.compact.join("\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$:.push *['%s/../lib/', '%s/lib/'].collect{|p| p % File.dirname(__FILE__) }
|
5
|
+
require 'console_table'
|
6
|
+
require 'phidgets_native'
|
7
|
+
|
8
|
+
PhidgetsNative.enable_logging! :verbose
|
9
|
+
|
10
|
+
puts "Using Library version: "+PhidgetsNative::LIBRARY_VERSION
|
11
|
+
|
12
|
+
ConsoleTable.new(%w(Serial\ No. Type Class Name Version)).output do
|
13
|
+
PhidgetsNative.all.enum_for(:each_with_index).collect{ |p,i|
|
14
|
+
%w(serial_number type device_class name version).collect{|attr| p.send attr}
|
15
|
+
}
|
16
|
+
end
|
data/examples/spatial.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require '%s/lib/common' % File.dirname(__FILE__)
|
5
|
+
|
6
|
+
additional_attribs = [
|
7
|
+
%w(Compass\ Correction compass_correction),
|
8
|
+
%w(Data\ Rate data_rate),
|
9
|
+
%w(Data\ Rate\ Max data_rate_max),
|
10
|
+
%w(Data\ Rate\ Min data_rate_min),
|
11
|
+
%w(Accelerometer\ Axes accelerometer_axes),
|
12
|
+
%w(Accelerometer\ Min accelerometer_min),
|
13
|
+
%w(Accelerometer\ Max accelerometer_max),
|
14
|
+
%w(Gyroscope\ Axes gyro_axes),
|
15
|
+
%w(Gyroscope\ Min gyro_min),
|
16
|
+
%w(Gyroscope\ Max gyro_max),
|
17
|
+
%w(Compass\ Axes compass_axes),
|
18
|
+
%w(Compass\ Min compass_min),
|
19
|
+
%w(Compass\ Max compass_max)
|
20
|
+
]
|
21
|
+
|
22
|
+
phidgets_example_for( PhidgetsNative::Spatial, additional_attribs ) do |spatial|
|
23
|
+
# This is worth doing before you start to use a gyro:
|
24
|
+
spatial.zero_gyro!
|
25
|
+
|
26
|
+
# This is worth doing as well:
|
27
|
+
spatial.compass_correction = [ 0.441604, 0.045493, 0.176548, 0.002767, 1.994358,
|
28
|
+
2.075937, 2.723117, -0.019360, -0.008005, -0.020036, 0.007017, -0.010891, 0.009283 ]
|
29
|
+
|
30
|
+
# This is almost never worth doing. I just put it in here for demonstration
|
31
|
+
# and test purposes
|
32
|
+
spatial.reset_compass_correction!
|
33
|
+
|
34
|
+
# Probably you'll never need to do this either:
|
35
|
+
spatial.data_rate = 16
|
36
|
+
|
37
|
+
puts "\nPolled Values:"
|
38
|
+
|
39
|
+
i = 0
|
40
|
+
ConsoleTable.new([
|
41
|
+
'Sample Rate',
|
42
|
+
'%-40s' % 'Accelerometer',
|
43
|
+
'%-40s' % 'Gyroscope',
|
44
|
+
'%-40s' % 'Compass'
|
45
|
+
]).output(:header => (i == 0), :separator => false) do |columns|
|
46
|
+
i+=1
|
47
|
+
[ ['%d Hz' % spatial.sample_rate]+[
|
48
|
+
spatial.accelerometer, spatial.gyro, spatial.compass ].collect{ |axes|
|
49
|
+
(axes.kind_of? Array) ?
|
50
|
+
'[%s]' % axes.collect{|a| '%0.6f' % a}.join(', ') : axes.inspect
|
51
|
+
} ]
|
52
|
+
end while sleep(3)
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#include "phidgets_native.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Document-class: PhidgetsNative::Accelerometer < PhidgetsNative::Device
|
5
|
+
*
|
6
|
+
* This class is a stub, and is currently in need of an actual implementation.
|
7
|
+
* Nonetheless, all of the methods from its parent class PhidgetsNative::Device are
|
8
|
+
* available.
|
9
|
+
*/
|
10
|
+
|
11
|
+
void Init_phidgets_native_accelerometer(VALUE m_Phidget) {
|
12
|
+
VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
|
13
|
+
|
14
|
+
VALUE c_Accelerometer = rb_define_class_under(m_Phidget, "Accelerometer", c_Device);
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Document-method: new
|
18
|
+
* call-seq:
|
19
|
+
* new(serial_number)
|
20
|
+
*
|
21
|
+
* All phidget objects are created from the device serial number. Serial numbers
|
22
|
+
* are required to be Fixnums (aka "unsigned integers").
|
23
|
+
*/
|
24
|
+
rb_define_method(c_Accelerometer, "initialize", accelerometer_initialize, 1);
|
25
|
+
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE accelerometer_initialize(VALUE self, VALUE serial) {
|
29
|
+
PhidgetInfo *info = device_info(self);
|
30
|
+
|
31
|
+
CPhidgetAccelerometerHandle accelerometer = 0;
|
32
|
+
ensure(CPhidgetAccelerometer_create(&accelerometer));
|
33
|
+
|
34
|
+
info->handle = (CPhidgetHandle)accelerometer;
|
35
|
+
return rb_call_super(1, &serial);
|
36
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#include "phidgets_native.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Document-class: PhidgetsNative::AdvancedServo < PhidgetsNative::Device
|
5
|
+
*
|
6
|
+
* This class is a stub, and is currently in need of an actual implementation.
|
7
|
+
* Nonetheless, all of the methods from its parent class PhidgetsNative::Device are
|
8
|
+
* available.
|
9
|
+
*/
|
10
|
+
|
11
|
+
void Init_phidgets_native_advancedservo(VALUE m_Phidget) {
|
12
|
+
VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
|
13
|
+
|
14
|
+
VALUE c_AdvancedServo = rb_define_class_under(m_Phidget, "AdvancedServo", c_Device);
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Document-method: new
|
18
|
+
* call-seq:
|
19
|
+
* new(serial_number)
|
20
|
+
*
|
21
|
+
* All phidget objects are created from the device serial number. Serial numbers
|
22
|
+
* are required to be Fixnums (aka "unsigned integers").
|
23
|
+
*/
|
24
|
+
rb_define_method(c_AdvancedServo, "initialize", advancedservo_initialize, 1);
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE advancedservo_initialize(VALUE self, VALUE serial) {
|
28
|
+
PhidgetInfo *info = device_info(self);
|
29
|
+
CPhidgetAdvancedServoHandle advancedservo = 0;
|
30
|
+
ensure(CPhidgetAdvancedServo_create(&advancedservo));
|
31
|
+
info->handle = (CPhidgetHandle)advancedservo;
|
32
|
+
return rb_call_super(1, &serial);
|
33
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#include "phidgets_native.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Document-class: PhidgetsNative::Analog < PhidgetsNative::Device
|
5
|
+
*
|
6
|
+
* This class is a stub, and is currently in need of an actual implementation.
|
7
|
+
* Nonetheless, all of the methods from its parent class PhidgetsNative::Device are
|
8
|
+
* available.
|
9
|
+
*/
|
10
|
+
|
11
|
+
void Init_phidgets_native_analog(VALUE m_Phidget) {
|
12
|
+
VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
|
13
|
+
|
14
|
+
VALUE c_Analog = rb_define_class_under(m_Phidget, "Analog", c_Device);
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Document-method: new
|
18
|
+
* call-seq:
|
19
|
+
* new(serial_number)
|
20
|
+
*
|
21
|
+
* All phidget objects are created from the device serial number. Serial numbers
|
22
|
+
* are required to be Fixnums (aka "unsigned integers").
|
23
|
+
*/
|
24
|
+
rb_define_method(c_Analog, "initialize", analog_initialize, 1);
|
25
|
+
}
|
26
|
+
|
27
|
+
|
28
|
+
VALUE analog_initialize(VALUE self, VALUE serial) {
|
29
|
+
PhidgetInfo *info = device_info(self);
|
30
|
+
CPhidgetAnalogHandle analog = 0;
|
31
|
+
ensure(CPhidgetAnalog_create(&analog));
|
32
|
+
info->handle = (CPhidgetHandle)analog;
|
33
|
+
return rb_call_super(1, &serial);
|
34
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#include "phidgets_native.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Document-class: PhidgetsNative::Bridge < PhidgetsNative::Device
|
5
|
+
*
|
6
|
+
* This class is a stub, and is currently in need of an actual implementation.
|
7
|
+
* Nonetheless, all of the methods from its parent class PhidgetsNative::Device are
|
8
|
+
* available.
|
9
|
+
*/
|
10
|
+
void Init_phidgets_native_bridge(VALUE m_Phidget) {
|
11
|
+
VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
|
12
|
+
|
13
|
+
VALUE c_Bridge = rb_define_class_under(m_Phidget, "Bridge", c_Device);
|
14
|
+
|
15
|
+
/*
|
16
|
+
* Document-method: new
|
17
|
+
* call-seq:
|
18
|
+
* new(serial_number)
|
19
|
+
*
|
20
|
+
* All phidget objects are created from the device serial number. Serial numbers
|
21
|
+
* are required to be Fixnums (aka "unsigned integers").
|
22
|
+
*/
|
23
|
+
rb_define_method(c_Bridge, "initialize", bridge_initialize, 1);
|
24
|
+
}
|
25
|
+
|
26
|
+
VALUE bridge_initialize(VALUE self, VALUE serial) {
|
27
|
+
PhidgetInfo *info = device_info(self);
|
28
|
+
CPhidgetBridgeHandle bridge = 0;
|
29
|
+
ensure(CPhidgetBridge_create(&bridge));
|
30
|
+
info->handle = (CPhidgetHandle)bridge;
|
31
|
+
return rb_call_super(1, &serial);
|
32
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#include "phidgets_native.h"
|
2
|
+
|
3
|
+
PhidgetInfo *device_info(VALUE self) {
|
4
|
+
PhidgetInfo *info;
|
5
|
+
Data_Get_Struct( self, PhidgetInfo, info );
|
6
|
+
|
7
|
+
return info;
|
8
|
+
}
|
9
|
+
|
10
|
+
void *device_type_info(VALUE self) {
|
11
|
+
PhidgetInfo *info;
|
12
|
+
Data_Get_Struct( self, PhidgetInfo, info );
|
13
|
+
|
14
|
+
return info->type_info;
|
15
|
+
}
|
16
|
+
|
17
|
+
int CCONV device_on_attach(CPhidgetHandle phid, void *userptr)
|
18
|
+
{
|
19
|
+
int serialNo;
|
20
|
+
report(CPhidget_getSerialNumber(phid, &serialNo));
|
21
|
+
|
22
|
+
// Populate our data structures with what we know about this device:
|
23
|
+
PhidgetInfo *info = userptr;
|
24
|
+
info->is_attached = true;
|
25
|
+
|
26
|
+
gettimeofday(&info->attached_at, &info->attached_at_tz);
|
27
|
+
|
28
|
+
// Phidget Attributes:
|
29
|
+
report(CPhidget_getDeviceType(phid, &info->type));
|
30
|
+
report(CPhidget_getDeviceVersion(phid, &info->version));
|
31
|
+
report(CPhidget_getDeviceClass(phid, &info->device_class));
|
32
|
+
report(CPhidget_getDeviceID(phid, &info->device_id));
|
33
|
+
report(CPhidget_getDeviceLabel(phid, &info->label));
|
34
|
+
report(CPhidget_getDeviceName(phid, &info->name));
|
35
|
+
|
36
|
+
return (info->on_type_attach) ? (*info->on_type_attach)(phid, info) : 0;
|
37
|
+
}
|
38
|
+
|
39
|
+
int CCONV device_on_detach(CPhidgetHandle phid, void *userptr) {
|
40
|
+
int serialNo;
|
41
|
+
report(CPhidget_getSerialNumber(phid, &serialNo));
|
42
|
+
|
43
|
+
PhidgetInfo *info = userptr;
|
44
|
+
info->is_attached = false;
|
45
|
+
|
46
|
+
return (info->on_type_detach) ? (*info->on_type_detach)(phid, info) : 0;
|
47
|
+
}
|
48
|
+
|
49
|
+
int CCONV device_on_error(CPhidgetHandle phid, void *userptr, int ErrorCode, const char *unknown) {
|
50
|
+
CPhidget_log(PHIDGET_LOG_ERROR, "N/A", "PhidgetNative OnError: %s", unknown);
|
51
|
+
return 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
void device_free(PhidgetInfo *info) {
|
55
|
+
if (info) {
|
56
|
+
if (info->handle) {
|
57
|
+
report(CPhidget_close((CPhidgetHandle)info->handle));
|
58
|
+
report(CPhidget_delete((CPhidgetHandle)info->handle));
|
59
|
+
}
|
60
|
+
|
61
|
+
if (info->on_type_free)
|
62
|
+
(*info->on_type_free)(info->type_info);
|
63
|
+
|
64
|
+
if (info)
|
65
|
+
xfree(info);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|