phidgets_native 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.
- 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
|
+
|