phidgets_native 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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