phidgets_native 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -167,10 +167,16 @@ by the Phidget API and/or hardware.
167
167
  ==Logging
168
168
  The phidget api has built in debug logging which can be enabled on a global basis
169
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
-
170
+ pass a path to a text file where output can alternatively be redirected.
174
171
  PhidgetsNative.enable_logging!(:verbose)
175
172
  PhidgetsNative.log :info, "My favorite color is chartreuse"
176
173
  PhidgetsNative.disable_logging!
174
+ Note that you can also use the log method to send your own messages to the logger,
175
+ if you think you have something you need to add.
176
+
177
+ =Changelog
178
+ == Version 0.2.1
179
+ - Added dual-ratiometric mode features and interfaces to the InterfaceKit
180
+
181
+ == Version 0.2.0
182
+ - First gem release, supporting all api functions of the Spatial, GPS, InterfaceKit, & AdvancedServo phidgets
@@ -0,0 +1,50 @@
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
+
20
+ ifkit.ratiometric = true
21
+ ifkit.ratiometric 6, false
22
+ ifkit.ratiometric 7, false
23
+
24
+ # Test sensor_raw
25
+ puts "Ratiometric states:"
26
+ ConsoleTable.new((0...ifkit.sensor_count).collect{|i| "Sensor #{i}"}).output do
27
+ [(0...ifkit.sensor_count).collect{|i| ifkit.ratiometric(i).inspect } ]
28
+ end
29
+
30
+ puts "\nPolled Values:"
31
+ i = 0
32
+ ConsoleTable.new([
33
+ 'Sensor Sample Rates',
34
+ '%-40s' % 'sensors',
35
+ ]).output(:header => (i == 0), :separator => false) do |columns|
36
+ i+=1
37
+
38
+ values = ifkit.sensors
39
+ if values
40
+ values[0] = '%.1f %% (RH)' % [values[0].to_f * 0.1906 - 40.2]
41
+ values[1] = '%.1f deg (C)' % [values[1].to_f * 0.22222 - 61.111]
42
+ values[2] = '%.1f deg (C)' % [values[2].to_f * 0.22222 - 61.111]
43
+
44
+ values[6] = '%.3f (V)' % [(values[6].to_f / 200 - 2.5) / 0.0681]
45
+ values[7] = '%.3f (V)' % [(values[7].to_f / 200 - 2.5) / 0.0681]
46
+ end
47
+
48
+ [ [ ifkit.sensor_sample_rates, values.inspect] ]
49
+ end while sleep(1)
50
+ end
@@ -40,15 +40,20 @@ int CCONV interfacekit_on_attach(CPhidgetHandle phid, void *userptr) {
40
40
  if(ifkit_info->data_rates_min) xfree(ifkit_info->data_rates_min);
41
41
  if(ifkit_info->sensor_change_triggers) xfree(ifkit_info->sensor_change_triggers);
42
42
  if(ifkit_info->analog_sample_rates) xfree(ifkit_info->analog_sample_rates);
43
+ if(ifkit_info->is_ratiometric) xfree(ifkit_info->is_ratiometric);
44
+ if(ifkit_info->updated_since_last_ratiometric_cycle) xfree(ifkit_info->updated_since_last_ratiometric_cycle);
43
45
 
44
46
  ifkit_info->data_rates = ALLOC_N(int, ifkit_info->analog_input_count);
45
47
  ifkit_info->data_rates_max = ALLOC_N(int, ifkit_info->analog_input_count);
46
48
  ifkit_info->data_rates_min = ALLOC_N(int, ifkit_info->analog_input_count);
47
49
  ifkit_info->sensor_change_triggers = ALLOC_N(int, ifkit_info->analog_input_count);
48
-
49
50
  ifkit_info->analog_sample_rates = ALLOC_N(SampleRate, ifkit_info->analog_input_count);
51
+ ifkit_info->is_ratiometric = ALLOC_N(bool, ifkit_info->analog_input_count);
52
+ ifkit_info->updated_since_last_ratiometric_cycle = ALLOC_N(bool, ifkit_info->analog_input_count);
50
53
 
51
54
  memset(ifkit_info->analog_sample_rates, 0, sizeof(SampleRate) * ifkit_info->analog_input_count);
55
+ memset(ifkit_info->is_ratiometric, 0, sizeof(bool) * ifkit_info->analog_input_count);
56
+ memset(ifkit_info->updated_since_last_ratiometric_cycle, 0, sizeof(bool) * ifkit_info->analog_input_count);
52
57
 
53
58
  for(int i=0;i<ifkit_info->analog_input_count;i++) {
54
59
  ifkit_info->data_rates[i] = DEFAULT_INTERFACEKIT_DATA_RATE;
@@ -61,18 +66,15 @@ int CCONV interfacekit_on_attach(CPhidgetHandle phid, void *userptr) {
61
66
  ifkit_info->is_data_rates_known = true;
62
67
  }
63
68
 
64
- // If the interfacekit isn't what we expect, we need to perform a change:
65
- report(interfacekit_assert_ratiometric_state( info ));
66
-
67
- // Set the data-rate/sensor-thresholds
68
- for(int i=0;i<ifkit_info->analog_input_count;i++) {
69
- if (ifkit_info->data_rates[i] > 0) {
70
- report(CPhidgetInterfaceKit_setSensorChangeTrigger(interfacekit, i, 0));
71
- report(CPhidgetInterfaceKit_setDataRate(interfacekit, i, ifkit_info->data_rates[i]));
72
- } else {
73
- report(CPhidgetInterfaceKit_setDataRate(interfacekit, i, 0));
74
- report(CPhidgetInterfaceKit_setSensorChangeTrigger(interfacekit, i, ifkit_info->sensor_change_triggers[i]));
75
- }
69
+ if ( interfacekit_ratiometric_state_is_uniform(ifkit_info) ) {
70
+ // Set the board's ratiometric state:
71
+ report(interfacekit_assert_ratiometric_state( info ));
72
+ // Set the data-rate/sensor-thresholds
73
+ report(interfacekit_assert_sensor_rates(info));
74
+ }
75
+ else {
76
+ report(interfacekit_assert_dual_ratiometric_mode(info));
77
+ report(interfacekit_maximize_data_rate(info));
76
78
  }
77
79
 
78
80
  // Read in all of our initial input values:
@@ -83,7 +85,7 @@ int CCONV interfacekit_on_attach(CPhidgetHandle phid, void *userptr) {
83
85
  report(CPhidgetInterfaceKit_setOutputState(interfacekit,i, ifkit_info->digital_output_states[i]));
84
86
 
85
87
  for(int i=0; i<ifkit_info->analog_input_count; i++)
86
- if (ifkit_info->rationmetric_changed_usec == 0)
88
+ if (ifkit_info->ratiometric_changed_usec == 0)
87
89
  // We only read these in if we haven't recently been changed ratiometric status:
88
90
  report(CPhidgetInterfaceKit_getSensorValue(interfacekit,i, &ifkit_info->analog_input_states[i]));
89
91
  else
@@ -119,26 +121,18 @@ int CCONV interfacekit_on_detach(CPhidgetHandle phid, void *userptr) {
119
121
  void interfacekit_on_free(void *type_info) {
120
122
  InterfaceKitInfo *ifkit_info = type_info;
121
123
 
122
- if(ifkit_info->data_rates)
123
- xfree(ifkit_info->data_rates);
124
- if(ifkit_info->data_rates_min)
125
- xfree(ifkit_info->data_rates_min);
126
- if(ifkit_info->data_rates_max)
127
- xfree(ifkit_info->data_rates_max);
128
- if(ifkit_info->sensor_change_triggers)
129
- xfree(ifkit_info->sensor_change_triggers);
130
- if (ifkit_info->digital_input_states)
131
- xfree(ifkit_info->digital_input_states);
132
- if (ifkit_info->digital_output_states)
133
- xfree(ifkit_info->digital_output_states);
134
- if (ifkit_info->analog_input_states)
135
- xfree(ifkit_info->analog_input_states);
136
- if(ifkit_info->digital_sample_rates)
137
- xfree(ifkit_info->digital_sample_rates);
138
- if(ifkit_info->analog_sample_rates)
139
- xfree(ifkit_info->analog_sample_rates);
140
- if (ifkit_info)
141
- xfree(ifkit_info);
124
+ if(ifkit_info->is_ratiometric) xfree(ifkit_info->is_ratiometric);
125
+ if(ifkit_info->updated_since_last_ratiometric_cycle) xfree(ifkit_info->updated_since_last_ratiometric_cycle);
126
+ if(ifkit_info->data_rates) xfree(ifkit_info->data_rates);
127
+ if(ifkit_info->data_rates_min) xfree(ifkit_info->data_rates_min);
128
+ if(ifkit_info->data_rates_max) xfree(ifkit_info->data_rates_max);
129
+ if(ifkit_info->sensor_change_triggers) xfree(ifkit_info->sensor_change_triggers);
130
+ if (ifkit_info->digital_input_states) xfree(ifkit_info->digital_input_states);
131
+ if (ifkit_info->digital_output_states) xfree(ifkit_info->digital_output_states);
132
+ if (ifkit_info->analog_input_states) xfree(ifkit_info->analog_input_states);
133
+ if(ifkit_info->digital_sample_rates) xfree(ifkit_info->digital_sample_rates);
134
+ if(ifkit_info->analog_sample_rates) xfree(ifkit_info->analog_sample_rates);
135
+ if (ifkit_info) xfree(ifkit_info);
142
136
  return;
143
137
  }
144
138
 
@@ -158,12 +152,14 @@ int interfacekit_on_analog_change(CPhidgetInterfaceKitHandle interfacekit, void
158
152
  PhidgetInfo *info = userptr;
159
153
  InterfaceKitInfo *ifkit_info = info->type_info;
160
154
 
161
- sample_tick(&ifkit_info->analog_sample_rates[index], NULL);
155
+ bool record_value = false;
156
+
157
+ int current_ratiometric_state = PFALSE;
162
158
 
163
159
  if (ifkit_info->analog_input_states) {
164
- if (ifkit_info->rationmetric_changed_usec == 0)
165
- ifkit_info->analog_input_states[index] = sensorValue;
166
- else {
160
+ if (ifkit_info->is_dual_ratiometric_mode && interfacekit_is_time_to_flip_ratiometric_state(info) ) {
161
+ report(interfacekit_flip_ratiometric_state(info));
162
+ } else if (ifkit_info->ratiometric_changed_usec != 0) {
167
163
  // We need to wait 50 milliseconds before accepting values after a ratiometric
168
164
  // state change. If we're in this path, it's TBD whether 50 ms has passed
169
165
  int usec_difference;
@@ -171,17 +167,31 @@ int interfacekit_on_analog_change(CPhidgetInterfaceKitHandle interfacekit, void
171
167
  gettimeofday(&now, NULL);
172
168
 
173
169
  usec_difference = ( now.tv_usec +
174
- ( (now.tv_usec < ifkit_info->rationmetric_changed_usec) ? 1000000 : 0) -
175
- ifkit_info->rationmetric_changed_usec );
176
-
170
+ ( (now.tv_usec < ifkit_info->ratiometric_changed_usec) ? 1000000 : 0) -
171
+ ifkit_info->ratiometric_changed_usec );
172
+
177
173
  // Did we wait long enough between a ratiometric status change:
178
174
  if ( usec_difference > INTERFACEKIT_RATIOMETRIC_RESET_USECS ) {
179
- ifkit_info->rationmetric_changed_usec = 0;
180
-
181
- // And sure, go ahead and accepti this value:
182
- ifkit_info->analog_input_states[index] = sensorValue;
175
+ ifkit_info->ratiometric_changed_usec = 0;
183
176
  }
184
177
  }
178
+
179
+ if (ifkit_info->ratiometric_changed_usec == 0) {
180
+ if (ifkit_info->is_dual_ratiometric_mode) {
181
+ report(CPhidgetInterfaceKit_getRatiometric(interfacekit, &current_ratiometric_state));
182
+
183
+ if ( (current_ratiometric_state == PTRUE) == ifkit_info->is_ratiometric[index] )
184
+ record_value = true;
185
+ } else
186
+ record_value = true;
187
+ }
188
+
189
+ if (record_value) {
190
+ ifkit_info->analog_input_states[index] = sensorValue;
191
+ sample_tick(&ifkit_info->analog_sample_rates[index], NULL);
192
+ if(ifkit_info->is_dual_ratiometric_mode)
193
+ ifkit_info->updated_since_last_ratiometric_cycle[index] = true;
194
+ }
185
195
  }
186
196
 
187
197
  return 0;
@@ -192,23 +202,134 @@ int interfacekit_assert_ratiometric_state(PhidgetInfo *info) {
192
202
  CPhidgetInterfaceKitHandle interfacekit = (CPhidgetInterfaceKitHandle) info->handle;
193
203
  int ret = 0;
194
204
 
195
- int is_ratiometric_already;
196
- ret = CPhidgetInterfaceKit_getRatiometric(interfacekit, &is_ratiometric_already);
197
- if (ret != EPHIDGET_OK) return ret;
205
+ bool change_mode = false;
198
206
 
199
- if (ifkit_info->is_ratiometric != (ifkit_info->is_ratiometric == PTRUE) ) {
200
- ret = CPhidgetInterfaceKit_setRatiometric(interfacekit, (ifkit_info->is_ratiometric) ? PTRUE : PFALSE );
207
+ if (ifkit_info->is_dual_ratiometric_mode) {
208
+ ifkit_info->is_dual_ratiometric_mode = false;
209
+ change_mode = true;
210
+ report(interfacekit_assert_sensor_rates(info));
211
+ } else {
212
+ int is_ratiometric_already;
213
+ ret = CPhidgetInterfaceKit_getRatiometric(interfacekit, &is_ratiometric_already);
214
+ if (ret != EPHIDGET_OK) return ret;
215
+
216
+ if (ifkit_info->is_ratiometric[0] != (is_ratiometric_already == PTRUE) )
217
+ change_mode = true;
218
+ }
219
+
220
+ if (change_mode) {
221
+ ret = CPhidgetInterfaceKit_setRatiometric(interfacekit, (ifkit_info->is_ratiometric[0]) ? PTRUE : PFALSE );
201
222
  if (ret != EPHIDGET_OK) return ret;
202
223
 
203
224
  // Zero-out the analog struct:
204
225
  memset(ifkit_info->analog_input_states, 0, sizeof(int) * ifkit_info->analog_input_count);
205
226
 
206
227
  // We need to wait 50ms after this change before we start to read in values:
207
- struct timeval now;
208
- gettimeofday(&now, NULL);
228
+ interfacekit_stamp_ratiometric_change(ifkit_info);
229
+ }
230
+
231
+ return EPHIDGET_OK;
232
+ }
233
+
234
+ bool interfacekit_ratiometric_state_is_uniform(InterfaceKitInfo *ifkit_info) {
235
+ bool first_state = ifkit_info->is_ratiometric[0];
236
+
237
+ for(int i=1; i<ifkit_info->analog_input_count;i++)
238
+ if (ifkit_info->is_ratiometric[i] != first_state)
239
+ return false;
240
+
241
+ return true;
242
+ }
243
+
244
+ bool interfacekit_is_time_to_flip_ratiometric_state(PhidgetInfo *info) {
245
+ InterfaceKitInfo *ifkit_info = info->type_info;
246
+ CPhidgetInterfaceKitHandle interfacekit = (CPhidgetInterfaceKitHandle) info->handle;
247
+
248
+ int current_ratiometric_state = PFALSE;
249
+
250
+ report(CPhidgetInterfaceKit_getRatiometric(interfacekit, &current_ratiometric_state));
251
+
252
+ for(int i=0; i<ifkit_info->analog_input_count;i++)
253
+ if ( (ifkit_info->is_ratiometric[i] == (current_ratiometric_state == PTRUE)) &&
254
+ (ifkit_info->updated_since_last_ratiometric_cycle[i] == false) )
255
+ return false;
256
+
257
+ return true;
258
+ }
259
+
260
+ // This method ensures that the sensor data rates are set to what's been requested
261
+ // by the user. It's typically only used when initializing, and when turning on
262
+ // a uniform ratiometric state:
263
+ int interfacekit_assert_sensor_rates(PhidgetInfo *info) {
264
+ InterfaceKitInfo *ifkit_info = info->type_info;
265
+ CPhidgetInterfaceKitHandle interfacekit = (CPhidgetInterfaceKitHandle) info->handle;
266
+
267
+ for(int i=0;i<ifkit_info->analog_input_count;i++) {
268
+ if (ifkit_info->data_rates[i] > 0) {
269
+ report(CPhidgetInterfaceKit_setSensorChangeTrigger(interfacekit, i, 0));
270
+ report(CPhidgetInterfaceKit_setDataRate(interfacekit, i, ifkit_info->data_rates[i]));
271
+ } else {
272
+ report(CPhidgetInterfaceKit_setDataRate(interfacekit, i, 0));
273
+ report(CPhidgetInterfaceKit_setSensorChangeTrigger(interfacekit, i, ifkit_info->sensor_change_triggers[i]));
274
+ }
275
+ }
209
276
 
210
- ifkit_info->rationmetric_changed_usec = (now.tv_usec == 0) ? 1 : now.tv_usec;
277
+ return EPHIDGET_OK;
278
+ }
279
+
280
+ int interfacekit_assert_dual_ratiometric_mode(PhidgetInfo *info) {
281
+ InterfaceKitInfo *ifkit_info = info->type_info;
282
+
283
+ if (!ifkit_info->is_dual_ratiometric_mode) {
284
+ ifkit_info->is_dual_ratiometric_mode = true;
285
+ memset(ifkit_info->updated_since_last_ratiometric_cycle, 0, sizeof(bool) * ifkit_info->analog_input_count);
286
+ return interfacekit_maximize_data_rate(info);
211
287
  }
212
288
 
213
289
  return EPHIDGET_OK;
214
290
  }
291
+
292
+ int interfacekit_maximize_data_rate(PhidgetInfo *info) {
293
+ InterfaceKitInfo *ifkit_info = info->type_info;
294
+ CPhidgetInterfaceKitHandle interfacekit = (CPhidgetInterfaceKitHandle) info->handle;
295
+
296
+ for(int i=0;i<ifkit_info->analog_input_count;i++)
297
+ if (ifkit_info->data_rates[i] > 0) {
298
+ report(CPhidgetInterfaceKit_setSensorChangeTrigger(interfacekit, i, 0));
299
+ report(CPhidgetInterfaceKit_setDataRate(interfacekit, i, DEFAULT_INTERFACEKIT_DATA_RATE));
300
+ }
301
+
302
+ return EPHIDGET_OK;
303
+ }
304
+
305
+ int interfacekit_flip_ratiometric_state(PhidgetInfo *info) {
306
+ InterfaceKitInfo *ifkit_info = info->type_info;
307
+ CPhidgetInterfaceKitHandle interfacekit = (CPhidgetInterfaceKitHandle) info->handle;
308
+
309
+ int ret;
310
+ int current_state;
311
+
312
+ ret = CPhidgetInterfaceKit_getRatiometric(interfacekit, &current_state);
313
+ if (ret != EPHIDGET_OK) return ret;
314
+
315
+ ret = CPhidgetInterfaceKit_setRatiometric(interfacekit, (current_state) ? PFALSE : PTRUE );
316
+ if (ret != EPHIDGET_OK) return ret;
317
+
318
+ // We need to wait 50ms after this change before we start to read in values:
319
+ interfacekit_stamp_ratiometric_change(ifkit_info);
320
+
321
+ memset(ifkit_info->updated_since_last_ratiometric_cycle, 0, sizeof(bool) * ifkit_info->analog_input_count);
322
+
323
+ return EPHIDGET_OK;
324
+ }
325
+
326
+ // This stamps the ifkit struct with the current time. We cheat a bit to make
327
+ // our lookup code a bit easier, by stamping the case of 0 with a 1:
328
+ int interfacekit_stamp_ratiometric_change(InterfaceKitInfo *ifkit_info) {
329
+ struct timeval now;
330
+ gettimeofday(&now, NULL);
331
+
332
+ ifkit_info->ratiometric_changed_usec = (now.tv_usec == 0) ? 1 : now.tv_usec;
333
+
334
+ return EPHIDGET_OK;
335
+ }
@@ -12,19 +12,47 @@ const char MSG_DATA_RATE_EXCEEDS_LIMIT[] = "provided rate exceeds allowed limit"
12
12
  const char MSG_CHANGE_TRIG_VALUE_MUST_BE_FIXNUM[] = "threshold must be a fixnum";
13
13
  const char MSG_CHANGE_TRIG_EXCEEDS_LIMIT[] = "provided threshold exceeds allowed limit";
14
14
 
15
+ const char MSG_RATIOMETRIC_NOT_UNIFORM[] = "this action can't be performed unless all sensors are of the same ratiometric state";
16
+
15
17
  /*
16
18
  * Document-class: PhidgetsNative::InterfaceKit < PhidgetsNative::Device
17
19
  *
18
20
  * This class provides functionality specific to the "InterfaceKit" device class.
19
21
  * Primarily, this phidget reports the values of analog and digital inputs, and
20
22
  * provides interfaces for outputing to analog and digital components.
23
+ *
24
+ * *NOTE:* Unlike the native phidget libraries, this implementation supports a
25
+ * "Dual Ratiometric" mode for the interface kit. This dual-mode is acheived by
26
+ * rapidly cycling the controller between ratiometric on and off states in the
27
+ * device polling loop. The benefit to supporting mixed states is that you
28
+ * can support multiple devices types on a single controller. Unfortunately,
29
+ * the ramification of doing so reduces the sample rates to a small fraction
30
+ * (roughly 8 times per second) of the maximum data rate (roughly 125 times per
31
+ * second). For many applications, the sampling rates aren't so sensitive that
32
+ * dual-ratiometric mode will be a problem.
33
+ *
34
+ * "Dual ratiometric" mode will automatically enable itself if you specify per-sensor
35
+ * ratiometric states using the ratiometric() method. Similary, uniform-ratiometric
36
+ * mode will automatically return at any time that all sensors return to a uniform
37
+ * state. If you don't intend to take advantage of this feature, simply use the
38
+ * ratiometric= method to set all analog inputs to the same state, and ignore the
39
+ * ratiometric() method.
21
40
  */
22
41
 
42
+ /*
43
+ * Document-class: PhidgetsNative::InterfaceKit::RatiometricNotUniform
44
+ *
45
+ * This exception is raised when the library encounters a request that cannot be
46
+ * satisfied since the ratiometric state of the analog sensors are not uniform.
47
+ */
23
48
  void Init_phidgets_native_interfacekit(VALUE m_Phidget) {
24
49
  VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
25
50
 
26
51
  VALUE c_InterfaceKit = rb_define_class_under(m_Phidget,"InterfaceKit",c_Device);
27
52
 
53
+ VALUE c_RatiometricNotUniform = rb_define_class_under(c_InterfaceKit,
54
+ "RatiometricNotUniform", rb_eStandardError);
55
+
28
56
  /*
29
57
  * Document-method: new
30
58
  * call-seq:
@@ -119,6 +147,26 @@ void Init_phidgets_native_interfacekit(VALUE m_Phidget) {
119
147
  */
120
148
  rb_define_method(c_InterfaceKit, "ratiometric=", interfacekit_ratiometric_set, 1);
121
149
 
150
+ /*
151
+ * Document-method: ratiometric
152
+ * call-seq:
153
+ * ratiometric(Fixnum index, Boolean state) -> Fixnum
154
+ *
155
+ * This method sets the ratiometric state for the analog sensor at the provided
156
+ * index. Note that phidget boards only support a board-wide ratiometric state.
157
+ * As such, when you set the state per the sensor in this library, the library
158
+ * will automatically toggle the board state between ratio and non-ratio metric
159
+ * modes for you. As a side-effect of the toggle action, your data rate will
160
+ * drop substantially, and you'll not be able to adjust the data_rate and
161
+ * change_trigger parameters. To re-enable the data_rate and change_trigger
162
+ * features, use the ratiometric= method to set the state for the entire board.
163
+ * The return value for this method is simply what was specified for
164
+ * the state.
165
+ * For more information on how analog inputs are polled, you can read up on the
166
+ * Phidget {Analog Input Primer}[http://www.phidgets.com/docs/Analog_Input_Primer]
167
+ */
168
+ rb_define_method(c_InterfaceKit, "ratiometric", interfacekit_ratiometric, -1);
169
+
122
170
  /*
123
171
  * Document-method: data_rates_max
124
172
  * call-seq:
@@ -256,8 +304,8 @@ VALUE interfacekit_initialize(VALUE self, VALUE serial) {
256
304
 
257
305
  InterfaceKitInfo *ifkit_info = ALLOC(InterfaceKitInfo);
258
306
  memset(ifkit_info, 0, sizeof(InterfaceKitInfo));
259
- ifkit_info->is_ratiometric = false;
260
307
  ifkit_info->is_data_rates_known = false;
308
+ ifkit_info->is_dual_ratiometric_mode = false;
261
309
 
262
310
  CPhidgetInterfaceKitHandle interfacekit = 0;
263
311
  ensure(CPhidgetInterfaceKit_create(&interfacekit));
@@ -339,6 +387,10 @@ VALUE interfacekit_sensor_count(VALUE self) {
339
387
  VALUE interfacekit_is_ratiometric(VALUE self) {
340
388
  InterfaceKitInfo *ifkit_info = device_type_info(self);
341
389
 
390
+ // If ratiometric state is not uniform, raise an exception
391
+ if (!interfacekit_ratiometric_state_is_uniform(ifkit_info))
392
+ interfacekit_raise_ratiometric_not_uniform();
393
+
342
394
  return (ifkit_info->is_ratiometric) ? Qtrue : Qfalse;
343
395
  }
344
396
 
@@ -346,19 +398,64 @@ VALUE interfacekit_ratiometric_set(VALUE self, VALUE is_ratiometric) {
346
398
  PhidgetInfo *info = device_info(self);
347
399
  InterfaceKitInfo *ifkit_info = device_type_info(self);
348
400
 
401
+ if (!info->is_attached) return Qnil;
402
+
403
+ bool is_ratiometric_bool;
404
+
349
405
  if (TYPE(is_ratiometric) == T_TRUE)
350
- ifkit_info->is_ratiometric = true;
406
+ is_ratiometric_bool = true;
351
407
  else if (TYPE(is_ratiometric) == T_FALSE)
352
- ifkit_info->is_ratiometric = false;
408
+ is_ratiometric_bool = false;
353
409
  else
354
410
  rb_raise(rb_eTypeError, MSG_RATIOMETRIC_MUST_BE_BOOL);
355
411
 
356
- if (info->is_attached)
357
- ensure(interfacekit_assert_ratiometric_state( info ));
412
+ for(int i=0; i<ifkit_info->analog_input_count;i++)
413
+ ifkit_info->is_ratiometric[i] = is_ratiometric_bool;
414
+
415
+ ensure(interfacekit_assert_ratiometric_state( info ));
358
416
 
359
417
  return is_ratiometric;
360
418
  }
361
419
 
420
+ VALUE interfacekit_ratiometric(int argc, VALUE* argv, VALUE self) {
421
+ VALUE index;
422
+ VALUE is_ratiometric;
423
+
424
+ rb_scan_args(argc, argv, "11", &index, &is_ratiometric);
425
+
426
+ if (TYPE(index) != T_FIXNUM)
427
+ rb_raise(rb_eTypeError, MSG_SENSOR_INDEX_MUST_BE_FIXNUM);
428
+
429
+ PhidgetInfo *info = device_info(self);
430
+ InterfaceKitInfo *ifkit_info = info->type_info;
431
+
432
+ int index_int = FIX2INT(index);
433
+ if ((ifkit_info->analog_input_count == 0) || (index_int > (ifkit_info->analog_input_count-1)))
434
+ rb_raise(rb_eTypeError, MSG_SENSOR_INDEX_TOO_HIGH);
435
+
436
+ VALUE ret;
437
+ if(NIL_P(is_ratiometric)) {
438
+ // It's a get request:
439
+ ret = (ifkit_info->is_ratiometric[index_int]) ? Qtrue : Qfalse;
440
+ } else {
441
+ if (TYPE(is_ratiometric) == T_TRUE)
442
+ ifkit_info->is_ratiometric[index_int] = true;
443
+ else if (TYPE(is_ratiometric) == T_FALSE)
444
+ ifkit_info->is_ratiometric[index_int] = false;
445
+ else
446
+ rb_raise(rb_eTypeError, MSG_RATIOMETRIC_MUST_BE_BOOL);
447
+
448
+ ret = is_ratiometric;
449
+
450
+ if (interfacekit_ratiometric_state_is_uniform(ifkit_info))
451
+ ensure(interfacekit_assert_ratiometric_state(info));
452
+ else
453
+ ensure(interfacekit_assert_dual_ratiometric_mode(info));
454
+ }
455
+
456
+ return ret;
457
+ }
458
+
362
459
  VALUE interfacekit_data_rates_max(VALUE self) {
363
460
  InterfaceKitInfo *ifkit_info = device_type_info(self);
364
461
 
@@ -459,6 +556,10 @@ VALUE interfacekit_data_rate_set(VALUE self, VALUE index, VALUE rate) {
459
556
  PhidgetInfo *info = device_info(self);
460
557
  InterfaceKitInfo *ifkit_info = info->type_info;
461
558
 
559
+ // If ratiometric state is not uniform, raise an exception
560
+ if (!interfacekit_ratiometric_state_is_uniform(ifkit_info))
561
+ interfacekit_raise_ratiometric_not_uniform();
562
+
462
563
  if (TYPE(index) != T_FIXNUM)
463
564
  rb_raise(rb_eTypeError, MSG_SENSOR_INDEX_MUST_BE_FIXNUM);
464
565
 
@@ -486,6 +587,10 @@ VALUE interfacekit_change_trigger_set(VALUE self, VALUE index, VALUE rate_thresh
486
587
  PhidgetInfo *info = device_info(self);
487
588
  InterfaceKitInfo *ifkit_info = info->type_info;
488
589
 
590
+ // If ratiometric state is not uniform, raise an exception
591
+ if (!interfacekit_ratiometric_state_is_uniform(ifkit_info))
592
+ interfacekit_raise_ratiometric_not_uniform();
593
+
489
594
  if (TYPE(index) != T_FIXNUM)
490
595
  rb_raise(rb_eTypeError, MSG_SENSOR_INDEX_MUST_BE_FIXNUM);
491
596
 
@@ -509,3 +614,15 @@ VALUE interfacekit_change_trigger_set(VALUE self, VALUE index, VALUE rate_thresh
509
614
 
510
615
  return rate_thresh;
511
616
  }
617
+
618
+ void interfacekit_raise_ratiometric_not_uniform() {
619
+ VALUE m_Phidget = rb_const_get(rb_cObject, rb_intern("PhidgetsNative"));
620
+
621
+ VALUE c_InterfaceKit = rb_const_get(m_Phidget, rb_intern("InterfaceKit"));
622
+
623
+ VALUE c_Exception = rb_const_get(c_InterfaceKit, rb_intern("RatiometricNotUniform"));
624
+
625
+ rb_raise(c_Exception, MSG_RATIOMETRIC_NOT_UNIFORM);
626
+
627
+ return;
628
+ }
@@ -142,8 +142,13 @@ typedef struct interfacekit_info {
142
142
  int digital_input_count_prior;
143
143
  int digital_output_count_prior;
144
144
 
145
- bool is_ratiometric;
146
- int rationmetric_changed_usec;
145
+ bool is_dual_ratiometric_mode;
146
+ bool *is_ratiometric;
147
+ int ratiometric_changed_usec;
148
+
149
+ // This tracks whether it's time to change the ratiometric state, for the case
150
+ // of a dual-mode ratiometric change:
151
+ bool *updated_since_last_ratiometric_cycle;
147
152
 
148
153
 
149
154
  // This flag works for all of the below properties
@@ -282,6 +287,14 @@ int CCONV interfacekit_on_detach(CPhidgetHandle phid, void *userptr);
282
287
  int interfacekit_on_digital_change(CPhidgetInterfaceKitHandle interfacekit, void *userptr, int index, int inputState);
283
288
  int interfacekit_on_analog_change(CPhidgetInterfaceKitHandle interfacekit, void *userptr, int index, int sensorValue);
284
289
  int interfacekit_assert_ratiometric_state(PhidgetInfo *info);
290
+ bool interfacekit_ratiometric_state_is_uniform(InterfaceKitInfo *ifkit_info);
291
+ void interfacekit_raise_ratiometric_not_uniform();
292
+ int interfacekit_maximize_data_rate(PhidgetInfo *info);
293
+ int interfacekit_assert_dual_ratiometric_mode(PhidgetInfo *info);
294
+ int interfacekit_assert_sensor_rates(PhidgetInfo *info);
295
+ int interfacekit_stamp_ratiometric_change(InterfaceKitInfo *ifkit_info);
296
+ int interfacekit_flip_ratiometric_state(PhidgetInfo *info);
297
+ bool interfacekit_is_time_to_flip_ratiometric_state(PhidgetInfo *info);
285
298
  VALUE interfacekit_initialize(VALUE self, VALUE serial);
286
299
  VALUE interfacekit_close(VALUE self);
287
300
  VALUE interfacekit_sensor_sample_rates(VALUE self);
@@ -291,6 +304,7 @@ VALUE interfacekit_output_count(VALUE self);
291
304
  VALUE interfacekit_sensor_count(VALUE self);
292
305
  VALUE interfacekit_is_ratiometric(VALUE self);
293
306
  VALUE interfacekit_ratiometric_set(VALUE self, VALUE is_ratiometric);
307
+ VALUE interfacekit_ratiometric(int argc, VALUE* argv, VALUE self);
294
308
  VALUE interfacekit_data_rates_max(VALUE self);
295
309
  VALUE interfacekit_data_rates_min(VALUE self);
296
310
  VALUE interfacekit_data_rates(VALUE self);
@@ -351,7 +365,6 @@ VALUE advancedservo_engaged_set(VALUE self, VALUE index, VALUE value);
351
365
  VALUE advancedservo_is_stopped(VALUE self, VALUE index);
352
366
  VALUE advancedservo_servo_parameters_set(VALUE self, VALUE index, VALUE min_us, VALUE max_us, VALUE degrees, VALUE velocity_max);
353
367
 
354
-
355
368
  // Stub initializers:
356
369
  VALUE accelerometer_initialize(VALUE self, VALUE serial);
357
370
  VALUE advancedservo_initialize(VALUE self, VALUE serial);
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "phidgets_native"
3
- s.version = "0.2.0"
3
+ s.version = "0.2.1"
4
4
  s.summary = "Native C-extension gem for the Phidgets library in ruby"
5
5
  s.author = "Chris DeRose"
6
6
  s.description = s.summary
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phidgets_native
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-27 00:00:00.000000000 Z
12
+ date: 2013-09-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
16
- requirement: &70163161506660 !ruby/object:Gem::Requirement
16
+ requirement: &70329854728720 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70163161506660
24
+ version_requirements: *70329854728720
25
25
  description: Native C-extension gem for the Phidgets library in ruby
26
26
  email: cderose@derosetechnologies.com
27
27
  executables: []
@@ -61,6 +61,7 @@ files:
61
61
  - ext/phidgets_native/extconf.rb
62
62
  - examples/advancedservo.rb
63
63
  - examples/gps.rb
64
+ - examples/interface_kit-dualratiometric.rb
64
65
  - examples/interface_kit.rb
65
66
  - examples/list_all.rb
66
67
  - examples/spatial.rb