1 /*
2 * $RCSfile: sample.cpp,v $
3 * $Revision: 1.26 $
4 * $Date: 2009/12/22 22:23:35 $
5 * jEdit:tabSize=4:indentSize=4:collapseFolds=1:
6 *
7 * AIOUSB library sample program
8 */
9
10
11 // {{{ notes and build instructions
12 /*
13 * This source code looks best with a tab width of 4.
14 *
15 * All the API functions that DO NOT begin "AIOUSB_" are standard API functions, largely
16 * documented in http://accesio.com/MANUALS/USB%20Software%20Reference.pdf. The functions
17 * that DO begin with "AIOUSB_" are "extended" API functions added to the Linux
18 * implementation. Source code lines in this sample program that are prefixed with the
19 * comment "/ * API * /" highlight calls to the AIOUSB API.
20 *
21 * LIBUSB (http://www.libusb.org/) must be installed on the Linux box (the AIOUSB code
22 * was developed using libusb version 1.0.3). After installing libusb, it may also be
23 * necessary to set an environment variable so that the libusb and aiousb header files can
24 * be located:
25 *
26 * export CPATH=/usr/local/include/libusb-1.0/:/usr/local/include/aiousb/
27 *
28 * Once libusb is installed properly, it should be possible to compile the sample program
29 * using the simple command:
30 *
31 * make
32 *
33 * Alternatively, one can "manually" compile the sample program using the command:
34 *
35 * g++ sample.cpp -laiousb -lusb-1.0 -o sample
36 *
37 * or, to enable debug features
38 *
39 * g++ -ggdb sample.cpp -laiousbdbg -lusb-1.0 -o sample
40 */
41 // }}}
42
43 // {{{ includes
44 #include <aiousb.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 using namespace AIOUSB;
48 // }}}
49
50 int main( int argc, char **argv ) {
51 printf(
52 "USB-AI16-16A sample program version 1.26, 22 December 2009\n"
53 " AIOUSB library version %s, %s\n"
54 " This program demonstrates controlling a USB-AI16-16A device on\n"
55 " the USB bus. For simplicity, it uses the first such device found\n"
56 " on the bus.\n"
57 /*API*/ , AIOUSB_GetVersion(), AIOUSB_GetVersionDate()
58 );
59
60 /*
61 * MUST call AIOUSB_Init() before any meaningful AIOUSB functions;
62 * AIOUSB_GetVersion() above is an exception
63 */
64 /*API*/ unsigned long result = AIOUSB_Init();
65 if( result == AIOUSB_SUCCESS ) {
66 /*
67 * call GetDevices() to obtain "list" of devices found on the bus
68 */
69 /*API*/ unsigned long deviceMask = GetDevices();
70 if( deviceMask != 0 ) {
71 /*
72 * at least one ACCES device detected, but we want one of a specific type
73 */
74 /*API*/ AIOUSB_ListDevices(); // print list of all devices found on the bus
75 const int MAX_NAME_SIZE = 20;
76 char name[ MAX_NAME_SIZE + 2 ];
77 unsigned long productID, nameSize, numDIOBytes, numCounters;
78 unsigned long deviceIndex = 0;
79 bool deviceFound = false;
80 while( deviceMask != 0 ) {
81 if( ( deviceMask & 1 ) != 0 ) {
82 // found a device, but is it the correct type?
83 nameSize = MAX_NAME_SIZE;
84 /*API*/ result = QueryDeviceInfo( deviceIndex, &productID, &nameSize, name, &numDIOBytes, &numCounters );
85 if( result == AIOUSB_SUCCESS ) {
86 if(
87 productID >= USB_AI16_16A
88 && productID <= USB_AI12_128E
89 ) {
90 // found a USB-AI16-16A family device
91 deviceFound = true;
92 break; // from while()
93 } // if( productID ...
94 } else
95 printf( "Error '%s' querying device at index %lu\n"
96 /*API*/ , AIOUSB_GetResultCodeAsString( result ), deviceIndex );
97 } // if( ( deviceMask ...
98 deviceIndex++;
99 deviceMask >>= 1;
100 } // while( deviceMask ...
101 if( deviceFound ) {
102 /*API*/ AIOUSB_Reset( deviceIndex );
103 /*API*/ AIOUSB_SetCommTimeout( deviceIndex, 1000 );
104 /*API*/ AIOUSB_SetDiscardFirstSample( deviceIndex, AIOUSB_TRUE );
105
106 __uint64_t serialNumber;
107 /*API*/ result = GetDeviceSerialNumber( deviceIndex, &serialNumber );
108 if( result == AIOUSB_SUCCESS )
109 printf( "Serial number of device at index %lu: %llx\n", deviceIndex, ( long long ) serialNumber );
110 else
111 printf( "Error '%s' getting serial number of device at index %lu\n"
112 /*API*/ , AIOUSB_GetResultCodeAsString( result ), deviceIndex );
113
114 /*
115 * demonstrate A/D configuration; there are two ways to configure the A/D;
116 * one way is to create an ADConfigBlock instance and configure it, and then
117 * send the whole thing to the device using ADC_SetConfig(); the other way
118 * is to use the discrete API functions such as ADC_SetScanLimits(), which
119 * send the new settings to the device immediately; here we demonstrate the
120 * ADConfigBlock technique; below we demonstrate use of the discrete functions
121 */
122 ADConfigBlock configBlock;
123 /*API*/ AIOUSB_InitConfigBlock( &configBlock, deviceIndex, AIOUSB_FALSE );
124 /*API*/ AIOUSB_SetAllGainCodeAndDiffMode( &configBlock, AD_GAIN_CODE_10V, AIOUSB_FALSE );
125 /*API*/ AIOUSB_SetCalMode( &configBlock, AD_CAL_MODE_NORMAL );
126 /*API*/ AIOUSB_SetTriggerMode( &configBlock, 0 );
127 /*API*/ AIOUSB_SetScanRange( &configBlock, 2, 13 );
128 /*API*/ AIOUSB_SetOversample( &configBlock, 0 );
129 /*API*/ result = ADC_SetConfig( deviceIndex, configBlock.registers, &configBlock.size );
130 if( result == AIOUSB_SUCCESS ) {
131 const int CAL_CHANNEL = 5;
132 const int MAX_CHANNELS = 128;
133 const int NUM_CHANNELS = 16;
134 unsigned short counts[ MAX_CHANNELS ];
135 double volts[ MAX_CHANNELS ];
136 unsigned char gainCodes[ NUM_CHANNELS ];
137 printf( "A/D settings successfully configured\n" );
138
139 /*
140 * demonstrate automatic A/D calibration
141 */
142 /*API*/ result = ADC_SetCal( deviceIndex, ":AUTO:" );
143 if( result == AIOUSB_SUCCESS )
144 printf( "Automatic calibration completed successfully\n" );
145 else
146 printf( "Error '%s' performing automatic A/D calibration\n"
147 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
148
149 /*
150 * verify that A/D ground calibration is correct
151 */
152 /*API*/ ADC_SetOversample( deviceIndex, 0 );
153 /*API*/ ADC_SetScanLimits( deviceIndex, CAL_CHANNEL, CAL_CHANNEL );
154 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_GROUND );
155 /*API*/ result = ADC_GetScan( deviceIndex, counts );
156 if( result == AIOUSB_SUCCESS )
157 printf( "Ground counts = %u (should be approx. 0)\n", counts[ CAL_CHANNEL ] );
158 else
159 printf( "Error '%s' attempting to read ground counts\n"
160 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
161
162 /*
163 * verify that A/D reference calibration is correct
164 */
165 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_REFERENCE );
166 /*API*/ result = ADC_GetScan( deviceIndex, counts );
167 if( result == AIOUSB_SUCCESS )
168 printf( "Reference counts = %u (should be approx. 65130)\n", counts[ CAL_CHANNEL ] );
169 else
170 printf( "Error '%s' attempting to read reference counts\n"
171 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
172
173 /*
174 * demonstrate scanning channels and measuring voltages
175 */
176 for( int channel = 0; channel < NUM_CHANNELS; channel++ )
177 gainCodes[ channel ] = AD_GAIN_CODE_0_10V;
178 /*API*/ ADC_RangeAll( deviceIndex, gainCodes, AIOUSB_TRUE );
179 /*API*/ ADC_SetOversample( deviceIndex, 10 );
180 /*API*/ ADC_SetScanLimits( deviceIndex, 0, NUM_CHANNELS - 1 );
181 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_NORMAL );
182 /*API*/ result = ADC_GetScanV( deviceIndex, volts );
183 if( result == AIOUSB_SUCCESS ) {
184 printf( "Volts read:\n" );
185 for( int channel = 0; channel < NUM_CHANNELS; channel++ )
186 printf( " Channel %2d = %f\n", channel, volts[ channel ] );
187 } else
188 printf( "Error '%s' performing A/D channel scan\n"
189 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
190
191 /*
192 * demonstrate reading a single channel in volts
193 */
194 /*API*/ result = ADC_GetChannelV( deviceIndex, CAL_CHANNEL, &volts[ CAL_CHANNEL ] );
195 if( result == AIOUSB_SUCCESS )
196 printf( "Volts read from A/D channel %d = %f\n", CAL_CHANNEL, volts[ CAL_CHANNEL ] );
197 else
198 printf( "Error '%s' reading A/D channel %d\n"
199 /*API*/ , AIOUSB_GetResultCodeAsString( result )
200 , CAL_CHANNEL );
201
202 /*
203 * demonstrate bulk acquire
204 */
205 /*API*/ AIOUSB_Reset( deviceIndex );
206 /*API*/ ADC_SetOversample( deviceIndex, 10 );
207 /*API*/ ADC_SetScanLimits( deviceIndex, 0, NUM_CHANNELS - 1 );
208 /*API*/ AIOUSB_SetStreamingBlockSize( deviceIndex, 100000 );
209 const int BULK_BYTES = 100000 /* scans */
210 * NUM_CHANNELS
211 * sizeof( unsigned short ) /* bytes / sample */
212 * 11 /* 1 sample + 10 oversamples */;
213 const double CLOCK_SPEED = 100000; // Hz
214 unsigned short *const dataBuf = ( unsigned short * ) malloc( BULK_BYTES );
215 if( dataBuf != 0 ) {
216 /*
217 * make sure counter is stopped
218 */
219 double clockHz = 0;
220 /*API*/ CTR_StartOutputFreq( deviceIndex, 0, &clockHz );
221
222 /*
223 * configure A/D for timer-triggered acquisition
224 */
225 /*API*/ ADC_ADMode( deviceIndex, AD_TRIGGER_SCAN | AD_TRIGGER_TIMER, AD_CAL_MODE_NORMAL );
226
227 /*
228 * start bulk acquire; ADC_BulkAcquire() will take care of starting
229 * and stopping the counter; but we do have to tell it what clock
230 * speed to use, which is why we call AIOUSB_SetMiscClock()
231 */
232 /*API*/ AIOUSB_SetMiscClock( deviceIndex, CLOCK_SPEED );
233 /*API*/ result = ADC_BulkAcquire( deviceIndex, BULK_BYTES, dataBuf );
234 if( result == AIOUSB_SUCCESS )
235 printf( "Started bulk acquire of %d bytes\n", BULK_BYTES );
236 else
237 printf( "Error '%s' attempting to start bulk acquire of %d bytes\n"
238 /*API*/ , AIOUSB_GetResultCodeAsString( result )
239 , BULK_BYTES );
240
241 /*
242 * use bulk poll to monitor progress
243 */
244 if( result == AIOUSB_SUCCESS ) {
245 unsigned long bytesRemaining = BULK_BYTES;
246 for( int seconds = 0; seconds < 100; seconds++ ) {
247 sleep( 1 );
248 /*API*/ result = ADC_BulkPoll( deviceIndex, &bytesRemaining );
249 if( result == AIOUSB_SUCCESS ) {
250 printf( " %lu bytes remaining\n", bytesRemaining );
251 if( bytesRemaining == 0 )
252 break; // from for()
253 } else {
254 printf( "Error '%s' polling bulk acquire progress\n"
255 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
256 break; // from for()
257 } // if( result ...
258 } // for( int seconds ...
259
260 /*
261 * turn off timer-triggered mode
262 */
263 /*API*/ ADC_ADMode( deviceIndex, 0, AD_CAL_MODE_NORMAL );
264
265 /*
266 * if all the data was apparently received, scan it for zeros; it's
267 * unlikely that any of the data would be zero, so any zeros, particularly
268 * a large block of zeros would suggest that the data is not valid
269 */
270 if(
271 result == AIOUSB_SUCCESS
272 && bytesRemaining == 0
273 ) {
274 bool anyZeroData = false;
275 int zeroIndex = -1;
276 for( int index = 0; index < BULK_BYTES / ( int ) sizeof( unsigned short ); index++ ) {
277 if( dataBuf[ index ] == 0 ) {
278 anyZeroData = true;
279 if( zeroIndex < 0 )
280 zeroIndex = index;
281 } else {
282 if( zeroIndex >= 0 ) {
283 printf( " Zero data from index %d to %d\n", zeroIndex, index - 1 );
284 zeroIndex = -1;
285 } // if( zeroIndex ...
286 } // if( dataBuf[ ...
287 } // for( int index ...
288 if( anyZeroData == false )
289 printf( "Successfully bulk acquired %d bytes\n", BULK_BYTES );
290 } else
291 printf( "Failed to bulk acquire %d bytes\n", BULK_BYTES );
292 } // if( result ...
293
294 free( dataBuf );
295 } // if( dataBuf ...
296 } else
297 printf( "Error '%s' setting A/D configuration\n"
298 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
299 } else
300 printf( "Failed to find USB-AI16-16A device\n" );
301 } else
302 printf( "No ACCES devices found on USB bus\n" );
303
304 /*
305 * MUST call AIOUSB_Exit() before program exits,
306 * but only if AIOUSB_Init() succeeded
307 */
308 /*API*/ AIOUSB_Exit();
309 } // if( result ...
310 return ( int ) result;
311 } // main()
312
313
314 /* end of file */