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.
Files changed (41) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +12 -0
  3. data/README.rdoc +176 -0
  4. data/Rakefile +31 -0
  5. data/examples/gps.rb +25 -0
  6. data/examples/interface_kit.rb +61 -0
  7. data/examples/lib/common.rb +51 -0
  8. data/examples/lib/console_table.rb +38 -0
  9. data/examples/list_all.rb +16 -0
  10. data/examples/spatial.rb +53 -0
  11. data/ext/phidgets_native/accelerometer_ruby.c +36 -0
  12. data/ext/phidgets_native/advancedservo_ruby.c +33 -0
  13. data/ext/phidgets_native/analog_ruby.c +34 -0
  14. data/ext/phidgets_native/bridge_ruby.c +32 -0
  15. data/ext/phidgets_native/device.c +68 -0
  16. data/ext/phidgets_native/device_ruby.c +404 -0
  17. data/ext/phidgets_native/encoder_ruby.c +34 -0
  18. data/ext/phidgets_native/extconf.rb +18 -0
  19. data/ext/phidgets_native/frequencycounter_ruby.c +32 -0
  20. data/ext/phidgets_native/gps.c +102 -0
  21. data/ext/phidgets_native/gps_ruby.c +212 -0
  22. data/ext/phidgets_native/interfacekit.c +203 -0
  23. data/ext/phidgets_native/interfacekit_ruby.c +507 -0
  24. data/ext/phidgets_native/ir_ruby.c +33 -0
  25. data/ext/phidgets_native/led_ruby.c +33 -0
  26. data/ext/phidgets_native/motorcontrol_ruby.c +32 -0
  27. data/ext/phidgets_native/phidgets_native.c +197 -0
  28. data/ext/phidgets_native/phidgets_native.h +320 -0
  29. data/ext/phidgets_native/phidgets_native_ruby.c +468 -0
  30. data/ext/phidgets_native/phsensor_ruby.c +32 -0
  31. data/ext/phidgets_native/rfid_ruby.c +31 -0
  32. data/ext/phidgets_native/servo_ruby.c +31 -0
  33. data/ext/phidgets_native/spatial.c +168 -0
  34. data/ext/phidgets_native/spatial_ruby.c +533 -0
  35. data/ext/phidgets_native/stepper_ruby.c +32 -0
  36. data/ext/phidgets_native/temperaturesensor_ruby.c +31 -0
  37. data/ext/phidgets_native/textlcd_ruby.c +31 -0
  38. data/ext/phidgets_native/textled_ruby.c +31 -0
  39. data/ext/phidgets_native/weightsensor_ruby.c +32 -0
  40. data/phidgets_native.gemspec +21 -0
  41. metadata +96 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake-compiler'
data/Gemfile.lock ADDED
@@ -0,0 +1,12 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ rake (10.1.0)
5
+ rake-compiler (0.8.3)
6
+ rake
7
+
8
+ PLATFORMS
9
+ ruby
10
+
11
+ DEPENDENCIES
12
+ rake-compiler
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
@@ -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
+