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 +10 -4
- data/examples/interface_kit-dualratiometric.rb +50 -0
- data/ext/phidgets_native/interfacekit.c +174 -53
- data/ext/phidgets_native/interfacekit_ruby.c +122 -5
- data/ext/phidgets_native/phidgets_native.h +16 -3
- data/phidgets_native.gemspec +1 -1
- metadata +5 -4
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.
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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->
|
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->
|
123
|
-
|
124
|
-
if(ifkit_info->
|
125
|
-
|
126
|
-
if(ifkit_info->data_rates_max)
|
127
|
-
|
128
|
-
if(ifkit_info->
|
129
|
-
|
130
|
-
if (ifkit_info->
|
131
|
-
|
132
|
-
if (ifkit_info->
|
133
|
-
|
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
|
-
|
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->
|
165
|
-
|
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->
|
175
|
-
ifkit_info->
|
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->
|
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, ¤t_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
|
-
|
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->
|
200
|
-
|
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
|
-
|
208
|
-
|
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, ¤t_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
|
-
|
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, ¤t_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
|
-
|
406
|
+
is_ratiometric_bool = true;
|
351
407
|
else if (TYPE(is_ratiometric) == T_FALSE)
|
352
|
-
|
408
|
+
is_ratiometric_bool = false;
|
353
409
|
else
|
354
410
|
rb_raise(rb_eTypeError, MSG_RATIOMETRIC_MUST_BE_BOOL);
|
355
411
|
|
356
|
-
|
357
|
-
|
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
|
146
|
-
|
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);
|
data/phidgets_native.gemspec
CHANGED
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.
|
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-
|
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: &
|
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: *
|
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
|