phidgets-ffi 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +3 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +92 -42
  4. data/examples/accelerometer.rb +39 -0
  5. data/examples/advanced_servo.rb +94 -0
  6. data/examples/analog.rb +43 -0
  7. data/examples/bridge.rb +57 -0
  8. data/examples/dictionary.rb +46 -31
  9. data/examples/encoder.rb +59 -0
  10. data/examples/frequency_counter.rb +63 -0
  11. data/examples/gps.rb +91 -0
  12. data/examples/interface_kit_with_block.rb +68 -0
  13. data/examples/interface_kit_without_block.rb +60 -0
  14. data/examples/ir.rb +157 -0
  15. data/examples/led.rb +36 -0
  16. data/examples/manager.rb +16 -10
  17. data/examples/motor_control.rb +108 -0
  18. data/examples/{ffi → raw-ffi}/dictionary.rb +11 -1
  19. data/examples/{ffi → raw-ffi}/interface_kit.rb +19 -2
  20. data/examples/{ffi → raw-ffi}/library_version.rb +0 -0
  21. data/examples/{ffi → raw-ffi}/log.rb +0 -0
  22. data/examples/{ffi → raw-ffi}/manager.rb +6 -3
  23. data/examples/rfid.rb +63 -0
  24. data/examples/servo.rb +45 -30
  25. data/examples/spatial.rb +75 -0
  26. data/examples/stepper.rb +87 -0
  27. data/examples/temperature_sensor.rb +49 -0
  28. data/examples/text_lcd.rb +101 -0
  29. data/lib/phidgets-ffi.rb +34 -3
  30. data/lib/phidgets-ffi/accelerometer.rb +122 -0
  31. data/lib/phidgets-ffi/advanced_servo.rb +304 -0
  32. data/lib/phidgets-ffi/analog.rb +111 -0
  33. data/lib/phidgets-ffi/bridge.rb +167 -0
  34. data/lib/phidgets-ffi/common.rb +506 -103
  35. data/lib/phidgets-ffi/dictionary.rb +136 -23
  36. data/lib/phidgets-ffi/encoder.rb +196 -0
  37. data/lib/phidgets-ffi/error.rb +8 -3
  38. data/lib/phidgets-ffi/ffi/accelerometer.rb +30 -0
  39. data/lib/phidgets-ffi/ffi/advanced_servo.rb +73 -0
  40. data/lib/phidgets-ffi/ffi/analog.rb +29 -0
  41. data/lib/phidgets-ffi/ffi/bridge.rb +44 -0
  42. data/lib/phidgets-ffi/ffi/common.rb +51 -34
  43. data/lib/phidgets-ffi/ffi/constants.rb +3 -1
  44. data/lib/phidgets-ffi/ffi/dictionary.rb +25 -20
  45. data/lib/phidgets-ffi/ffi/encoder.rb +32 -0
  46. data/lib/phidgets-ffi/ffi/frequency_counter.rb +38 -0
  47. data/lib/phidgets-ffi/ffi/gps.rb +32 -0
  48. data/lib/phidgets-ffi/ffi/interface_kit.rb +26 -23
  49. data/lib/phidgets-ffi/ffi/ir.rb +50 -0
  50. data/lib/phidgets-ffi/ffi/led.rb +40 -0
  51. data/lib/phidgets-ffi/ffi/log.rb +7 -6
  52. data/lib/phidgets-ffi/ffi/manager.rb +35 -20
  53. data/lib/phidgets-ffi/ffi/motor_control.rb +66 -0
  54. data/lib/phidgets-ffi/ffi/rfid.rb +36 -0
  55. data/lib/phidgets-ffi/ffi/servo.rb +16 -15
  56. data/lib/phidgets-ffi/ffi/spatial.rb +40 -0
  57. data/lib/phidgets-ffi/ffi/stepper.rb +56 -0
  58. data/lib/phidgets-ffi/ffi/temperature_sensor.rb +42 -0
  59. data/lib/phidgets-ffi/ffi/text_lcd.rb +55 -0
  60. data/lib/phidgets-ffi/frequency_counter.rb +148 -0
  61. data/lib/phidgets-ffi/gps.rb +181 -0
  62. data/lib/phidgets-ffi/interface_kit.rb +205 -92
  63. data/lib/phidgets-ffi/ir.rb +290 -0
  64. data/lib/phidgets-ffi/led.rb +112 -0
  65. data/lib/phidgets-ffi/log.rb +14 -2
  66. data/lib/phidgets-ffi/manager.rb +143 -26
  67. data/lib/phidgets-ffi/motor_control.rb +497 -0
  68. data/lib/phidgets-ffi/phidgets-ffi.rb +15 -2
  69. data/lib/phidgets-ffi/rfid.rb +220 -0
  70. data/lib/phidgets-ffi/servo.rb +103 -61
  71. data/lib/phidgets-ffi/spatial.rb +306 -0
  72. data/lib/phidgets-ffi/stepper.rb +370 -0
  73. data/lib/phidgets-ffi/temperature_sensor.rb +157 -0
  74. data/lib/phidgets-ffi/text_lcd.rb +298 -0
  75. data/lib/phidgets-ffi/version.rb +1 -1
  76. data/phidgets-ffi.gemspec +2 -2
  77. metadata +89 -76
  78. data/examples/ffi/servo.rb +0 -67
  79. data/examples/interface_kit.rb +0 -20
@@ -0,0 +1,112 @@
1
+ module Phidgets
2
+
3
+ # This class represents a PhidgetLED.
4
+ class LED
5
+
6
+ Klass = Phidgets::FFI::CPhidgetLED
7
+ include Phidgets::Common
8
+
9
+ # Collection of LEDs
10
+ # @return [LEDOuputs]
11
+ attr_reader :leds
12
+
13
+ attr_reader :attributes
14
+
15
+ # The attributes of a PhidgetLED
16
+ def attributes
17
+ super.merge({
18
+ :leds => leds.size,
19
+ })
20
+ end
21
+
22
+ # @return [Phidgets::FFI::LEDCurrentLimit] returns the board current limit for all LEDs, or raises an error. Not supported on all PhidgetLEDs.
23
+ def current_limit
24
+ ptr = ::FFI::MemoryPointer.new(:int)
25
+ Klass.getCurrentLimit(@handle, ptr)
26
+ Phidgets::FFI::LEDCurrentLimit[ptr.get_int(0)]
27
+ end
28
+
29
+ # Sets the board current limit for all LEDs, or raises an error. Not supported on all PhidgetLEDs.
30
+ # @param [Phidgets::FFI::LEDCurrentLimit] new_current_limit new current limit
31
+ # @return [Phidgets::FFI::LEDCurrentLimit] returns the board current limit, or raises an error.
32
+ def current_limit=(new_current_limit)
33
+ ptr = ::FFI::MemoryPointer.new(:int)
34
+ Klass.setCurrentLimit(@handle, Phidgets::FFI::LEDCurrentLimit[new_current_limit])
35
+ new_current_limit
36
+ end
37
+
38
+ # @return [Phidgets::FFI::LEDVoltage] returns the voltage level for all LEDs, or raises an error. Not supported on all PhidgetLEDs.
39
+ def voltage
40
+ ptr = ::FFI::MemoryPointer.new(:int)
41
+ Klass.getVoltage(@handle, ptr)
42
+ Phidgets::FFI::LEDVoltage[ptr.get_int(0)]
43
+ end
44
+
45
+ # Sets the voltage level for all LEDs, or raises an error. Not supported on all PhidgetLEDs.
46
+ # @param [Phidgets::FFI::LEDVoltage] new_voltage new voltage
47
+ # @return [Phidgets::FFI::LEDVoltage] returns the voltage level, or raises an error.
48
+ def voltage=(new_voltage)
49
+ ptr = ::FFI::MemoryPointer.new(:int)
50
+ Klass.setVoltage(@handle, Phidgets::FFI::LEDVoltage[new_voltage])
51
+ new_voltage
52
+ end
53
+
54
+ # This class represents an led for a PhidgetLED. All the properties of an led are stored and modified in this class.
55
+ class LEDOuputs
56
+ Klass = Phidgets::FFI::CPhidgetLED
57
+
58
+ private
59
+ def initialize(handle, index)
60
+ @handle, @index = handle, index.to_i
61
+ end
62
+
63
+ public
64
+ # Displays data for an led.
65
+ def inspect
66
+ "#<#{self.class} @index=#{index}, @brightness=#{brightness}>"
67
+ end
68
+
69
+ # @return [Integer] returns the index of the servo motor, or raises an error.
70
+ def index
71
+ @index
72
+ end
73
+
74
+ # @return [Integer] returns the brightness level of an LED, or raises an error.
75
+ def brightness
76
+ ptr = ::FFI::MemoryPointer.new(:int)
77
+ Klass.getDiscreteLED(@handle, @index, ptr)
78
+ ptr.get_int(0)
79
+ end
80
+
81
+ # Sets the brightness level of an LED, or raises an error. Brightness levels range from 0-100
82
+ # @param [Integer] new_brightness new brightness
83
+ # @return [Integer] returns the brightness of an LED, or raises an error.
84
+ def brightness=(new_brightness)
85
+ Klass.setDiscreteLED(@handle, @index, new_brightness.to_i)
86
+ new_brightness.to_i
87
+ end
88
+
89
+ end #LEDOutputs
90
+
91
+ private
92
+
93
+ def load_device_attributes
94
+ load_leds
95
+ end
96
+
97
+ def load_leds
98
+ ptr = ::FFI::MemoryPointer.new(:int)
99
+ Klass.getLEDCount(@handle, ptr)
100
+ @leds = []
101
+ ptr.get_int(0).times do |i|
102
+ @leds << LEDOuputs.new(@handle, i)
103
+ end
104
+
105
+ end
106
+
107
+ def remove_specific_event_handlers
108
+
109
+ end
110
+ end
111
+
112
+ end
@@ -2,26 +2,38 @@ module Phidgets
2
2
  class Log
3
3
  Klass = Phidgets::FFI::Log
4
4
 
5
+ # Enables logging, or raises an error.
6
+ # @param [Phidgets::FFI::LogLevel] level The highest level of logging to output. All lower levels will also be output.
7
+ # @param [String] output_file File to output log to. This should be a full pathname, not a relative pathname. Optional. If no output file is specified, the output will print to console.
8
+ # @return [Boolean] returns true, or raises an error.
5
9
  def self.enable(loglevel=:warning, filename=nil)
6
10
  Klass.enableLogging(loglevel, filename.to_s)
7
11
  true
8
12
  end
9
13
 
14
+ # Disables logging, or raises an error.
15
+ # @return [Boolean] returns true, or raises an error.
10
16
  def self.disable
11
17
  Klass.disableLogging
12
18
  true
13
19
  end
14
20
 
21
+ # Appends a message to the log, or raises an error.
22
+ # @param [Phidgets::FFI::LogLevel] level the level at which to log the message.
23
+ # @param [String] output_file File to output log to. This should be a full pathname, not a relative pathname. Optional. If no output file is specified, the output will print to console.
24
+ # @param [String] message the message
25
+ # @return [Boolean] returns true, or raises an error.
15
26
  def self.log(loglevel, identifier, message, *args)
16
27
  Klass.log(loglevel, identifier, message, *args)
17
28
  end
18
29
 
30
+ private
19
31
  def self.method_missing(method, *args, &block)
20
- if Phidgets::FFI::LogLevel.symbols.include?(method)
32
+ if Phidgets::FFI::LogLevel.symbols.include?(method)
21
33
  log(method, *args)
22
34
  true
23
35
  else
24
- super(method, *args, &block)
36
+ super(method, *args, &block)
25
37
  end
26
38
  end
27
39
  end
@@ -1,55 +1,105 @@
1
1
  module Phidgets
2
- class Manager
2
+
3
+ # This class represents a PhidgetManager.
4
+ class Manager
3
5
  Klass = Phidgets::FFI::CPhidgetManager
4
6
  include Utility
5
7
 
6
- def initialize(&block)
8
+ # Initializes a PhidgetManager. There are two methods that you can use to program the PhidgetManager.
9
+ #
10
+ # @param [String] options Information required to connect to the WebService. This is optional. If no option is specified, it is assumed that the address is localhost and port is 5001
11
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
12
+ #
13
+ # @return [Object]
14
+ #
15
+ # <b>First Method:</b> You can program with a block.
16
+ # options = {:address => 'localhost', :port => 5001, :server_id => nil, :password => nil}
17
+ # Phidgets::Manager.new(options) do |man|
18
+ # ...
19
+ # end
20
+ #
21
+ # <b>Second Method:</b> You can program without a block
22
+ # man = Phidgets::Manager.new
23
+ def initialize(options={}, &block)
24
+ create
25
+
26
+ password = (options[:password].nil? ? nil : options[:password].to_s)
27
+ if !options[:server_id].nil? or !options[:address].nil?
28
+ if !options[:server_id].nil?
29
+ open_remote(options, password)
30
+ else
31
+ open_remote_ip(options, password)
32
+ end
33
+ sleep 3
34
+ else
35
+ open
36
+ end
7
37
  if block_given?
8
- create
9
- open
10
38
  yield self
11
39
  close
12
- delete
13
40
  end
14
41
  end
15
42
 
16
- def create
43
+ private
44
+ def create
17
45
  ptr = ::FFI::MemoryPointer.new(:pointer, 1)
18
46
  Klass.create(ptr)
19
47
  @handle = ptr.get_pointer(0)
20
48
  true
21
49
  end
22
50
 
23
- def open
51
+ def open
24
52
  Klass.open(@handle)
25
- # There is no waiting for attachments in the manager, the check is instant so we sleep for a second to give it a chance to register things
53
+
26
54
  sleep 1
27
55
  true
28
56
  end
29
57
 
30
- def close
31
- Klass.close(@handle)
58
+ def open_remote(options, password)
59
+ Klass.openRemote(@handle, options[:server_id].to_s, password)
60
+ sleep 2
32
61
  true
33
62
  end
34
-
35
- def delete
36
- Klass.delete(@handle)
63
+
64
+ def open_remote_ip(options, password)
65
+ Klass.openRemoteIP(@handle, options[:address].to_s, options[:port].to_i, password)
66
+ sleep 2
37
67
  true
38
68
  end
69
+
70
+ public
71
+
72
+ # Closes and frees a PhidgetManager
73
+ #
74
+ # @return [Boolean] returns true or raises an error
75
+ def close
76
+ remove_specific_event_handlers
77
+ sleep 0.2
78
+ Klass.close(@handle)
79
+ Klass.delete(@handle)
80
+ true
81
+ end
39
82
 
40
- def devices(timeout=5000)
41
- devices_ptr, count = ::FFI::MemoryPointer.new(:pointer, 1), ::FFI::MemoryPointer.new(:int)
42
- Klass.getAttachedDevices(@handle, devices_ptr, count)
43
- devices = devices_ptr.get_array_of_pointer(0, count.get_int(0))
44
- device_arr = devices.map do |device|
45
- device = device.get_pointer(0)
46
- Common.attributes(device)
47
- end
48
- Klass.freeAttachedDevicesArray(devices_ptr)
83
+ # @return [Array] returns a list of the handles of all currently attached Phidgets, or raises an error. You can use the handles with the Phidgets::Common class methods; See the example for more details.
84
+ def devices
85
+ devices_ptr, count = ::FFI::MemoryPointer.new(:pointer, 300), ::FFI::MemoryPointer.new(:int)
86
+ Klass.getAttachedDevices(@handle, devices_ptr, count)
87
+
88
+ devices = devices_ptr.get_array_of_pointer(0, count.get_int(0))
89
+
90
+ device_array = []
91
+ count.get_int(0).times do |i|
92
+ device_array[i] = devices[0].get_pointer(i*Phidgets::FFI::FFI_POINTER_SIZE)
93
+
94
+ end
95
+
96
+ #Klass.freeAttachedDevicesArray(devices_ptr) #error
49
97
 
50
- device_arr
98
+ device_array
99
+
51
100
  end
52
101
 
102
+ # @return [String] returns the server id of a remotely opened PhidgetManager, or raises an error. This will fail if the manager was opened locally.
53
103
  def server_id
54
104
  ptr = ::FFI::MemoryPointer.new(:string)
55
105
  Phidgets::FFI::Common.getServerID(@handle, ptr)
@@ -57,6 +107,7 @@ module Phidgets
57
107
  strPtr.null? ? nil : strPtr.read_string
58
108
  end
59
109
 
110
+ # @return [String] returns the address and port of a remotely opened PhidgetManager, or raises an error. This will fail if the manager was opened locally.
60
111
  def server_address
61
112
  str_ptr, int_ptr = ::FFI::MemoryPointer.new(:string), ::FFI::MemoryPointer.new(:int)
62
113
  Phidgets::FFI::Common.getServerID(@handle, str_ptr, int_ptr)
@@ -65,23 +116,60 @@ module Phidgets
65
116
  port = int_ptr.get_int(0)
66
117
  [address, port]
67
118
  end
68
-
119
+
120
+ # @return [String] returns the connected to server status, or raises an error
121
+ def status
122
+ ptr = ::FFI::MemoryPointer.new(:int)
123
+ Klass.getServerStatus(@handle, ptr)
124
+ Phidgets::FFI::ServerStatus[ptr.get_int(0)]
125
+ end
126
+
127
+ # Sets an attach handler callback function. This is called when a Phidget is plugged into the system.
128
+ #
129
+ # @param [String] obj Object to pass to the callback function. This is optional.
130
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
131
+ # @example
132
+ # manager.on_attach do |device_ptr, obj|
133
+ # puts "Attaching #{Phidgets::Common.name(device_ptr)}"
134
+ # end
135
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
136
+ # @return [Boolean] returns true or raises an error
69
137
  def on_attach(obj=nil, &block)
70
138
  @on_attach_obj = obj
71
139
  @on_attach = Proc.new { |handle, obj_ptr|
72
- yield object_for(obj_ptr)
140
+ yield handle, object_for(obj_ptr)
73
141
  }
74
142
  Klass.set_OnAttach_Handler(@handle, @on_attach, pointer_for(obj))
75
143
  end
76
144
 
145
+ # Sets a detach handler callback function. This is called when a Phidget is unplugged from the system.
146
+ #
147
+ # @param [String] obj Object to pass to the callback function. This is optional.
148
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
149
+ # @example
150
+ # manager.on_detach do |device_ptr, obj|
151
+ # puts "Detaching #{Phidgets::Common.name(device_ptr)}"
152
+ # end
153
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
154
+ # @return [Boolean] returns true or raises an error
77
155
  def on_detach(obj=nil, &block)
78
156
  @on_detach_obj = obj
79
157
  @on_detach = Proc.new { |handle, obj_ptr|
80
- yield object_for(obj_ptr)
158
+ yield handle, object_for(obj_ptr)
81
159
  }
82
160
  Klass.set_OnDetach_Handler(@handle, @on_detach, pointer_for(obj))
83
161
  end
84
162
 
163
+ # Sets a server connect handler callback function. This is used for opening the PhidgetManager remotely, and is called when a connection to the server has been made.
164
+ #
165
+ # @param [String] obj Object to pass to the callback function. This is optional.
166
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
167
+ # @example
168
+ # manager.on_server_connect do |obj|
169
+ # puts 'Connected'
170
+ # end
171
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
172
+ # @return [Boolean] returns true or raises an error
85
173
  def on_server_connect(obj=nil, &block)
86
174
  @on_server_connect_obj = obj
87
175
  @on_server_connect = Proc.new { |handle, obj_ptr|
@@ -90,6 +178,16 @@ module Phidgets
90
178
  Klass.set_OnServerConnect_Handler(@handle, @on_server_connect, pointer_for(obj))
91
179
  end
92
180
 
181
+ # Sets a server disconnect handler callback function. This is used for opening the PhidgetManager remotely, and is called when a connection to the server has been lost
182
+ #
183
+ # @param [String] obj Object to pass to the callback function. This is optional.
184
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
185
+ # @example
186
+ # manager.on_server_disconnect do |obj|
187
+ # puts 'Disconnected'
188
+ # end
189
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
190
+ # @return [Boolean] returns true or raises an error
93
191
  def on_server_disconnect(obj=nil, &block)
94
192
  @on_server_disconnect_obj = obj
95
193
  @on_server_disconnect = Proc.new { |handle, obj_ptr|
@@ -98,6 +196,16 @@ module Phidgets
98
196
  Klass.set_OnServerDisconnect_Handler(@handle, @on_server_disconnect, pointer_for(obj))
99
197
  end
100
198
 
199
+ # Sets a error handler callback function. This is called when an asynchronous error occurs.
200
+ #
201
+ # @param [String] obj Object to pass to the callback function. This is optional.
202
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
203
+ # @example
204
+ # manager.on_error do |obj|
205
+ # puts "Error (#{code}): #{reason}"
206
+ # end
207
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
208
+ # @return [Boolean] returns true or raises an error
101
209
  def on_error(obj=nil, &block)
102
210
  @on_error_obj = obj
103
211
  @on_error = Proc.new { |handle, obj_ptr, code, description|
@@ -105,5 +213,14 @@ module Phidgets
105
213
  }
106
214
  Klass.set_OnError_Handler(@handle, @on_error, pointer_for(obj))
107
215
  end
216
+
217
+ private
218
+
219
+ def remove_specific_event_handlers
220
+ Klass.set_OnAttach_Handler(@handle, nil, nil)
221
+ Klass.set_OnDetach_Handler(@handle, nil, nil)
222
+ Klass.set_OnServerConnect_Handler(@handle, nil, nil)
223
+ Klass.set_OnServerDisconnect_Handler(@handle, nil, nil)
224
+ end
108
225
  end
109
226
  end
@@ -0,0 +1,497 @@
1
+ module Phidgets
2
+
3
+ # This class represents a PhidgetMotorControl.
4
+ class MotorControl
5
+
6
+ Klass = Phidgets::FFI::CPhidgetMotorControl
7
+ include Phidgets::Common
8
+
9
+ # Collection of motors
10
+ # @return [MotorControlMotors]
11
+ attr_reader :motors
12
+
13
+ # Collection of encoders
14
+ # @return [MotorControlEncoders]
15
+ attr_reader :encoders
16
+
17
+ # Collection of digital inputs
18
+ # @return [MotorControlDigitalInputs]
19
+ attr_reader :inputs
20
+
21
+ # Collection of analog sensors
22
+ # @return [MotorControlAnalogSensors]
23
+ attr_reader :sensors
24
+
25
+ attr_reader :attributes
26
+
27
+ # The attributes of a PhidgetMotorControl
28
+ def attributes
29
+ super.merge({
30
+ :motors => motors.size,
31
+ :encoders => encoders.size,
32
+ :inputs => inputs.size,
33
+ :sensors => sensors.size,
34
+ :ratiometric => ratiometric
35
+ })
36
+ end
37
+
38
+ # Sets a velocity change handler callback function. This is called when the velocity of a motor changes.
39
+ #
40
+ # @param [String] obj Object to pass to the callback function. This is optional.
41
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
42
+ # @example
43
+ # mc.on_velocity_change do |device, motor, velocity|
44
+ # puts "Motor #{motor.index}'s velocity changed to #{velocity}"
45
+ # end
46
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
47
+ # @return [Boolean] returns true or raises an error
48
+ def on_velocity_change(obj=nil, &block)
49
+
50
+ @on_velocity_change_obj = obj
51
+ @on_velocity_change = Proc.new { |device, obj_ptr, motor, velocity|
52
+ yield self, @motors[motor], velocity, object_for(obj_ptr)
53
+
54
+ }
55
+ Klass.set_OnVelocityChange_Handler(@handle, @on_velocity_change, pointer_for(obj))
56
+ end
57
+
58
+ # Sets a current change handler callback function. This is called when the current consumed by a motor changes.
59
+ #
60
+ # @param [String] obj Object to pass to the callback function. This is optional.
61
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
62
+ # @example
63
+ # mc.on_current_change do |device, motor, current|
64
+ # puts "Motor #{motor.index}'s current changed to #{current}"
65
+ # end
66
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
67
+ # @return [Boolean] returns true or raises an error
68
+ def on_current_change(obj=nil, &block)
69
+
70
+ @on_current_change_obj = obj
71
+ @on_current_change = Proc.new { |device, obj_ptr, motor, current|
72
+ yield self, @motors[motor], current, object_for(obj_ptr)
73
+
74
+ }
75
+ Klass.set_OnCurrentChange_Handler(@handle, @on_current_change, pointer_for(obj))
76
+ end
77
+
78
+ # Sets a current update handler callback function. This is called when the current consumed by a motor changes.
79
+ #
80
+ # @param [String] obj Object to pass to the callback function. This is optional.
81
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
82
+ # @example
83
+ # mc.on_current_update do |device, motor, current|
84
+ # puts "Motor #{motor.index}'s current is #{current}"
85
+ # end
86
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
87
+ # @return [Boolean] returns true or raises an error
88
+ def on_current_update(obj=nil, &block)
89
+
90
+ @on_current_update_obj = obj
91
+ @on_current_update = Proc.new { |device, obj_ptr, motor, current|
92
+ yield self, @motors[motor], current, object_for(obj_ptr)
93
+
94
+ }
95
+ Klass.set_OnCurrentChange_Handler(@handle, @on_current_update, pointer_for(obj))
96
+ end
97
+
98
+ # Sets an input change handler callback function. This is called when a digital input on the PhidgetMotorControl board has changed.
99
+ #
100
+ # @param [String] obj Object to pass to the callback function. This is optional.
101
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
102
+ # @example
103
+ # mc.on_input_change do |device, input, state, obj|
104
+ # puts "Digital Input #{input.index}, changed to #{state}"
105
+ # end
106
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
107
+ # @return [Boolean] returns true or raises an error
108
+ def on_input_change(obj=nil, &block)
109
+ @on_input_change_obj = obj
110
+ @on_input_change = Proc.new { |device, obj_ptr, index, state|
111
+ yield self, @inputs[index], (state == 0 ? false : true), object_for(obj_ptr)
112
+ }
113
+ Klass.set_OnInputChange_Handler(@handle, @on_input_change, pointer_for(obj))
114
+ end
115
+
116
+ # Sets a Back EMF update handler callback function. This is called at a steady rate of 16ms, when BackEMF sensing is enabled.
117
+ #
118
+ # @param [String] obj Object to pass to the callback function. This is optional.
119
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
120
+ # @example
121
+ # mc.on_back_emf_update do |device, motor, voltage|
122
+ # puts "Motor #{motor.index}'s back EMF is #{voltage}"
123
+ # end
124
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
125
+ # @return [Boolean] returns true or raises an error
126
+ def on_back_emf_update(obj=nil, &block)
127
+ @on_back_emf_update_obj = obj
128
+ @on_back_emf_update = Proc.new { |device, obj_ptr, motor, voltage|
129
+ yield self, @motors[motor], voltage, object_for(obj_ptr)
130
+ }
131
+ Klass.set_OnBackEMFUpdate_Handler(@handle, @on_back_emf_update, pointer_for(obj))
132
+ end
133
+
134
+ # Sets a position change handler callback function. This event provides data about how many ticks have occured, and how much time has passed since the last position change event, but does not contain an absolute position. This be be obtained from {Phidgets::MotorControl::MotorControlEncoders#position}
135
+ #
136
+ # @param [String] obj Object to pass to the callback function. This is optional.
137
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
138
+ # @example
139
+ # mc.on_position_change do |device, encoder, time, position|
140
+ # puts "Encoder #{encoder.index}'s position changed to #{position} in #{time}"
141
+ # end
142
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
143
+ # @return [Boolean] returns true or raises an error
144
+ def on_position_change(obj=nil, &block)
145
+
146
+ @on_position_change_obj = obj
147
+ @on_position_change = Proc.new { |device, obj_ptr, encoder, time, position|
148
+ yield self, @encoders[encoder], time, position, object_for(obj_ptr)
149
+
150
+ }
151
+ Klass.set_OnEncoderPositionChange_Handler(@handle, @on_position_change, pointer_for(obj))
152
+ end
153
+
154
+ # Sets a position update handler callback function. This event provides data about how many ticks have occured since the last update event. It is called at a steady rate of 8ms.
155
+ #
156
+ # @param [String] obj Object to pass to the callback function. This is optional.
157
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
158
+ # @example
159
+ # mc.on_position_update do |device, encoder, position|
160
+ # puts "Encoder #{encoder.index}'s position is #{position}"
161
+ # end
162
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
163
+ # @return [Boolean] returns true or raises an error
164
+ def on_position_update(obj=nil, &block)
165
+
166
+ @on_position_update_obj = obj
167
+ @on_position_update = Proc.new { |device, obj_ptr, encoder, position|
168
+ yield self, @encoders[encoder], position, object_for(obj_ptr)
169
+
170
+ }
171
+ Klass.set_OnEncoderPositionUpdate_Handler(@handle, @on_position_update, pointer_for(obj))
172
+ end
173
+
174
+ # Sets a sensor update handler callback function. This is called at a steady rate of 8ms.
175
+ #
176
+ # @param [String] obj Object to pass to the callback function. This is optional.
177
+ # @param [Proc] Block When the callback is executed, the device and object are yielded to this block.
178
+ # @example
179
+ # mc.on_sensor_update do |device, sensor, value|
180
+ # puts "Analog Sensor #{sensor.index}'s value is #{value}"
181
+ # end
182
+ # As this runs in it's own thread, be sure that all errors are properly handled or the thread will halt and not fire any more.
183
+ # @return [Boolean] returns true or raises an error
184
+ def on_sensor_update(obj=nil, &block)
185
+ @on_sensor_update_obj = obj
186
+ @on_sensor_update = Proc.new { |device, obj_ptr, index, value|
187
+ yield self, @sensors[index], value, object_for(obj_ptr)
188
+ }
189
+ Klass.set_OnSensorUpdate_Handler(@handle, @on_sensor_update, pointer_for(obj))
190
+ end
191
+
192
+ # Returns the ratiometric state of the board
193
+ #
194
+ # @return [Boolean] returns the ratiometric state or raises an error
195
+ def ratiometric
196
+ ptr = ::FFI::MemoryPointer.new(:int)
197
+ Klass.getRatiometric(@handle, ptr)
198
+ (ptr.get_int(0) == 0) ? false : true
199
+ end
200
+ alias_method :ratiometric?, :ratiometric
201
+
202
+ # Sets the ratiometric state of the board.
203
+ # @param [Boolean] new_state new ratiometric state
204
+ # @return [Boolean] returns the ratiometric state or raises an error
205
+ def ratiometric=(new_state)
206
+ tmp = new_state ? 1 : 0
207
+ Klass.setRatiometric(@handle, tmp)
208
+ new_state
209
+ end
210
+
211
+ # This class represents a motor for a PhidgetMotorControl. All the properties of a motor are stored and modified in this class.
212
+ class MotorControlMotors
213
+ Klass = Phidgets::FFI::CPhidgetMotorControl
214
+
215
+ private
216
+ def initialize(handle, index)
217
+ @handle, @index = handle, index.to_i
218
+ end
219
+
220
+ public
221
+ # Displays data for the motor.
222
+ def inspect
223
+ "#<#{self.class} @index=#{index}, @acceleration=#{acceleration}, @acceleration_min=#{acceleration_min}, @acceleration_max=#{acceleration_max}, @velocity=#{velocity}>"
224
+ end
225
+
226
+ # @return [Integer] returns the index of the motor, or raises an error.
227
+ def index
228
+ @index
229
+ end
230
+
231
+ # @return [Float] returns the acceleration of a motor, or raises an error.
232
+ def acceleration
233
+ ptr = ::FFI::MemoryPointer.new(:double)
234
+ Klass.getAcceleration(@handle, @index, ptr)
235
+ ptr.get_double(0)
236
+ end
237
+
238
+ # Sets the acceleration of a motor, or raises an error.
239
+ # @param [Integer] new_acceleration new acceleration
240
+ # @return [Float] returns acceleration of a motor, or raises an error.
241
+ def acceleration=(new_acceleration)
242
+ Klass.setAcceleration(@handle, @index, new_acceleration.to_f)
243
+ new_acceleration
244
+ end
245
+
246
+ # @return [Float] returns the largest acceleration value that the motor will accept, or raises an error.
247
+ def acceleration_max
248
+ ptr = ::FFI::MemoryPointer.new(:double)
249
+ Klass.getAccelerationMax(@handle, @index, ptr)
250
+ ptr.get_double(0)
251
+ end
252
+
253
+ # @return [Float] returns the smallest acceleration value that the motor will accept, or raises an error.
254
+ def acceleration_min
255
+ ptr = ::FFI::MemoryPointer.new(:double)
256
+ Klass.getAccelerationMin(@handle, @index, ptr)
257
+ ptr.get_double(0)
258
+ end
259
+
260
+ # @return [Float] returns the current consumption of a motor, in Amps, or raises an error.
261
+ def current
262
+ ptr = ::FFI::MemoryPointer.new(:double)
263
+ Klass.getCurrent(@handle, @index, ptr)
264
+ ptr.get_double(0)
265
+ end
266
+
267
+ # Sets the back EMF sensing state of a motor, or raises an error.
268
+ # @param [Boolean] new_back_emf_sensing new back EMf sensing state
269
+ # @return [Boolean] sets the back EMF sensing state of a motor, or raises an error.
270
+ def back_emf_sensing=(new_back_emf_sensing)
271
+ tmp = new_back_emf_sensing ? 1 : 0
272
+ Klass.setBackEMFSensingState(@handle, @index, tmp)
273
+ new_back_emf_sensing
274
+ end
275
+
276
+ # @return [Boolean] returns the back EMF sensing state of a motor, or raises an error.
277
+ def back_emf_sensing
278
+ ptr = ::FFI::MemoryPointer.new(:int)
279
+ Klass.getBackEMFSensingState(@handle, @index, ptr)
280
+ (ptr.get_int(0) == 0) ? false : true
281
+ end
282
+
283
+ # @return [Float] returns the back EMF value of a motor, in volts, or raises an error.
284
+ def back_emf
285
+ ptr = ::FFI::MemoryPointer.new(:double)
286
+ Klass.getBackEMF(@handle, @index, ptr)
287
+ ptr.get_double(0)
288
+ end
289
+
290
+ # @return [Float] returns the velocity of a motor, or raises an error.
291
+ def velocity
292
+ ptr = ::FFI::MemoryPointer.new(:double)
293
+ Klass.getVelocity(@handle, @index, ptr)
294
+ ptr.get_double(0)
295
+ end
296
+
297
+ # Sets the velocity of a motor, or raises an error.
298
+ # @param [Integer] new_velocity new velocity
299
+ # @return [Float] returns the velocity of a motor, or raises an error.
300
+ def velocity=(new_velocity)
301
+ Klass.setVelocity(@handle, @index, new_velocity.to_f)
302
+ new_velocity
303
+ end
304
+
305
+ # @return [Float] returns the braking value of a motor, or raises an error.
306
+ def braking
307
+ ptr = ::FFI::MemoryPointer.new(:double)
308
+ Klass.getBraking(@handle, @index, ptr)
309
+ ptr.get_double(0)
310
+ end
311
+
312
+ # Sets the braking value of a motor, or raises an error. The value can be between 0-100%
313
+ # @param [Integer] new_braking new braking
314
+ # @return [Float] returns the braking value of a motor, or raises an error.
315
+ def braking=(new_braking)
316
+ Klass.setBraking(@handle, @index, new_braking.to_f)
317
+ new_braking
318
+ end
319
+
320
+ end #MotorControlMotors
321
+
322
+ # This class represents an analog sensor for a PhidgetMotorControl. All the properties of an analog sensor are stored and modified in this class.
323
+ class MotorControlAnalogSensors
324
+ Klass = Phidgets::FFI::CPhidgetMotorControl
325
+
326
+ private
327
+ def initialize(handle, index)
328
+ @handle, @index = handle, index.to_i
329
+ end
330
+
331
+ public
332
+
333
+ # Displays data for the analog sensor
334
+ def inspect
335
+ "#<#{self.class} @value=#{value}, @raw_value=#{raw_value}>"
336
+ end
337
+
338
+ # @return [Integer] returns index of the analog input, or raises an error.
339
+ def index
340
+ @index
341
+ end
342
+
343
+ # @return [Integer] returns value of the analog input, or raises an error.
344
+ def value
345
+ ptr = ::FFI::MemoryPointer.new(:int)
346
+ Klass.getSensorValue(@handle, @index, ptr)
347
+ ptr.get_int(0)
348
+ end
349
+ alias_method :to_i, :value
350
+
351
+ # @return [Integer] returns raw value of the analog input, or raises an error.
352
+ def raw_value
353
+ ptr = ::FFI::MemoryPointer.new(:int)
354
+ Klass.getSensorRawValue(@handle, @index, ptr)
355
+ ptr.get_int(0)
356
+ end
357
+
358
+ end #MotorControlAnalogSensors
359
+
360
+ # This class represents a digital input for a PhidgetMotorControl. All the properties of an digital input are stored and modified in this class.
361
+ class MotorControlDigitalInputs
362
+ Klass = Phidgets::FFI::CPhidgetMotorControl
363
+
364
+ private
365
+ def initialize(handle, index)
366
+ @handle, @index = handle, index.to_i
367
+ end
368
+
369
+ public
370
+
371
+ # Displays data for the digital input
372
+ def inspect
373
+ "#<#{self.class} @index=#{index}, @state=#{state}>"
374
+ end
375
+
376
+ # @return [Integer] returns index of the digital input, or raises an error.
377
+ def index
378
+ @index
379
+ end
380
+
381
+ # @return [Boolean] returns state of the digital input, or raises an error.
382
+ def state
383
+ ptr = ::FFI::MemoryPointer.new(:int)
384
+ Klass.getInputState(@handle, @index, ptr)
385
+ (ptr.get_int(0) == 0) ? false : true
386
+ end
387
+
388
+ # @return [Boolean] returns true if the state is true.
389
+ def on
390
+ state == true
391
+ end
392
+ alias_method :on?, :on
393
+
394
+ # @return [Boolean] returns true if the state is off.
395
+ def off
396
+ !on
397
+ end
398
+ alias_method :off?, :off
399
+
400
+ end #MotorControlDigitalInputs
401
+
402
+ # This class represents an encoder for a PhidgetMotorControl. All the properties of an encoder are stored and modified in this class.
403
+ class MotorControlEncoders
404
+ Klass = Phidgets::FFI::CPhidgetMotorControl
405
+
406
+ private
407
+ def initialize(handle, index)
408
+ @handle, @index = handle, index.to_i
409
+ end
410
+
411
+ public
412
+
413
+ # Displays data for the encoder
414
+ def inspect
415
+ "#<#{self.class} @index=#{index}, @position=#{position}>"
416
+ end
417
+
418
+ # @return [Integer] returns index of the digital input, or raises an error.
419
+ def index
420
+ @index
421
+ end
422
+
423
+ # @return [Integer] returns the position of an encoder, or raises an error.
424
+ def position
425
+ ptr = ::FFI::MemoryPointer.new(:int)
426
+ Klass.getEncoderPosition(@handle, @index, ptr)
427
+ ptr.get_int(0)
428
+ end
429
+
430
+ # Sets the position of an encoder, or raises an error.
431
+ # @param [Integer] new_position new position
432
+ # @return [Integer] returns the position of an encoder, or raises an error.
433
+ def position=(new_position)
434
+ Klass.setEncoderPosition(@handle, @index, new_position.to_i)
435
+ new_position
436
+ end
437
+
438
+ end #MotorControlEncoders
439
+
440
+ private
441
+
442
+ def load_device_attributes
443
+ load_analog_sensors
444
+ load_inputs
445
+ load_encoders
446
+ load_motors
447
+ end
448
+
449
+ def load_analog_sensors
450
+ ptr = ::FFI::MemoryPointer.new(:int)
451
+ Klass.getSensorCount(@handle, ptr)
452
+ @sensors = []
453
+ ptr.get_int(0).times do |i|
454
+ @sensors << MotorControlAnalogSensors.new(@handle, i)
455
+ end
456
+ end
457
+
458
+ def load_inputs
459
+ ptr = ::FFI::MemoryPointer.new(:int)
460
+ Klass.getInputCount(@handle, ptr)
461
+ @inputs = []
462
+ ptr.get_int(0).times do |i|
463
+ @inputs << MotorControlDigitalInputs.new(@handle, i)
464
+ end
465
+ end
466
+
467
+ def load_encoders
468
+ ptr = ::FFI::MemoryPointer.new(:int)
469
+ Klass.getEncoderCount(@handle, ptr)
470
+ @encoders = []
471
+ ptr.get_int(0).times do |i|
472
+ @encoders << MotorControlEncoders.new(@handle, i)
473
+ end
474
+ end
475
+
476
+ def load_motors
477
+ ptr = ::FFI::MemoryPointer.new(:int)
478
+ Klass.getMotorCount(@handle, ptr)
479
+ @motors = []
480
+ ptr.get_int(0).times do |i|
481
+ @motors << MotorControlMotors.new(@handle, i)
482
+ end
483
+ end
484
+
485
+ def remove_specific_event_handlers
486
+ Klass.set_OnVelocityChange_Handler(@handle, nil, nil)
487
+ Klass.set_OnCurrentChange_Handler(@handle, nil, nil)
488
+ Klass.set_OnInputChange_Handler(@handle, nil, nil)
489
+ Klass.set_OnEncoderPositionChange_Handler(@handle, nil, nil)
490
+ Klass.set_OnEncoderPositionUpdate_Handler(@handle, nil, nil)
491
+ Klass.set_OnBackEMFUpdate_Handler(@handle, nil, nil)
492
+ Klass.set_OnSensorUpdate_Handler(@handle, nil, nil)
493
+ Klass.set_OnCurrentUpdate_Handler(@handle, nil, nil)
494
+ end
495
+ end
496
+
497
+ end