1 /*
2 * $RCSfile: sample.cpp,v $
3 * $Revision: 1.24 $
4 * $Date: 2009/11/26 21:53:09 $
5 * :tabSize=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.24, 26 November 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 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 NUM_CHANNELS = 16;
133 unsigned short counts[ NUM_CHANNELS ];
134 double volts[ NUM_CHANNELS ];
135 unsigned char gainCodes[ NUM_CHANNELS ];
136 printf( "A/D settings successfully configured\n" );
137
138 /*
139 * demonstrate automatic A/D calibration
140 */
141 /*API*/ result = ADC_SetCal( deviceIndex, ":AUTO:" );
142 if( result == AIOUSB_SUCCESS )
143 printf( "Automatic calibration completed successfully\n" );
144 else
145 printf( "Error '%s' performing automatic A/D calibration\n"
146 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
147
148 /*
149 * verify that A/D ground calibration is correct
150 */
151 /*API*/ ADC_SetOversample( deviceIndex, 0 );
152 /*API*/ ADC_SetScanLimits( deviceIndex, CAL_CHANNEL, CAL_CHANNEL );
153 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_GROUND );
154 /*API*/ result = ADC_GetScan( deviceIndex, counts );
155 if( result == AIOUSB_SUCCESS )
156 printf( "Ground counts = %u (should be approx. 0)\n", counts[ CAL_CHANNEL ] );
157 else
158 printf( "Error '%s' attempting to read ground counts\n"
159 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
160
161 /*
162 * verify that A/D reference calibration is correct
163 */
164 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_REFERENCE );
165 /*API*/ result = ADC_GetScan( deviceIndex, counts );
166 if( result == AIOUSB_SUCCESS )
167 printf( "Reference counts = %u (should be approx. 65102)\n", counts[ CAL_CHANNEL ] );
168 else
169 printf( "Error '%s' attempting to read reference counts\n"
170 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
171
172 /*
173 * demonstrate scanning channels and measuring voltages
174 */
175 for( int channel = 0; channel < NUM_CHANNELS; channel++ )
176 gainCodes[ channel ] = AD_GAIN_CODE_0_10V;
177 /*API*/ ADC_RangeAll( deviceIndex, gainCodes, AIOUSB_TRUE );
178 /*API*/ ADC_SetOversample( deviceIndex, 10 );
179 /*API*/ ADC_SetScanLimits( deviceIndex, 0, NUM_CHANNELS - 1 );
180 /*API*/ ADC_ADMode( deviceIndex, 0 /* TriggerMode */, AD_CAL_MODE_NORMAL );
181 /*API*/ result = ADC_GetScanV( deviceIndex, volts );
182 if( result == AIOUSB_SUCCESS ) {
183 printf( "Volts read:\n" );
184 for( int channel = 0; channel < NUM_CHANNELS; channel++ )
185 printf( " Channel %2d = %f\n", channel, volts[ channel ] );
186 } else
187 printf( "Error '%s' performing A/D channel scan\n"
188 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
189
190 /*
191 * demonstrate reading a single channel in volts
192 */
193 /*API*/ result = ADC_GetChannelV( deviceIndex, CAL_CHANNEL, &volts[ CAL_CHANNEL ] );
194 if( result == AIOUSB_SUCCESS )
195 printf( "Volts read from A/D channel %d = %f\n", CAL_CHANNEL, volts[ CAL_CHANNEL ] );
196 else
197 printf( "Error '%s' reading A/D channel %d\n"
198 /*API*/ , AIOUSB_GetResultCodeAsString( result )
199 , CAL_CHANNEL );
200
201 /*
202 * demonstrate bulk acquire
203 */
204 AIOUSB_Reset( deviceIndex );
205 /*API*/ ADC_SetOversample( deviceIndex, 10 );
206 /*API*/ ADC_SetScanLimits( deviceIndex, 0, NUM_CHANNELS - 1 );
207 /*API*/ AIOUSB_SetStreamingBlockSize( deviceIndex, 100000 );
208 const int BULK_BYTES = 100000 /* scans */
209 * NUM_CHANNELS
210 * sizeof( unsigned short ) /* bytes / sample */
211 * 11 /* 1 sample + 10 oversamples */;
212 const double CLOCK_SPEED = 100000; // Hz
213 unsigned short *const dataBuf = ( unsigned short * ) malloc( BULK_BYTES );
214 if( dataBuf != 0 ) {
215 /*
216 * make sure counter is stopped
217 */
218 double clockHz = 0;
219 /*API*/ CTR_StartOutputFreq( deviceIndex, 0, &clockHz );
220
221 /*
222 * configure A/D for timer-triggered acquisition
223 */
224 /*API*/ ADC_ADMode( deviceIndex, AD_TRIGGER_SCAN | AD_TRIGGER_TIMER, AD_CAL_MODE_NORMAL );
225
226 /*
227 * start bulk acquire; ADC_BulkAcquire() will take care of starting
228 * and stopping the counter; but we do have to tell it what clock
229 * speed to use, which is why we call AIOUSB_SetMiscClock()
230 */
231 /*API*/ AIOUSB_SetMiscClock( deviceIndex, CLOCK_SPEED );
232 /*API*/ result = ADC_BulkAcquire( deviceIndex, BULK_BYTES, dataBuf );
233 if( result == AIOUSB_SUCCESS )
234 printf( "Started bulk acquire of %d bytes\n", BULK_BYTES );
235 else
236 printf( "Error '%s' attempting to start bulk acquire of %d bytes\n"
237 /*API*/ , AIOUSB_GetResultCodeAsString( result )
238 , BULK_BYTES );
239
240 /*
241 * use bulk poll to monitor progress
242 */
243 if( result == AIOUSB_SUCCESS ) {
244 unsigned long bytesRemaining = BULK_BYTES;
245 for( int seconds = 0; seconds < 100; seconds++ ) {
246 sleep( 1 );
247 /*API*/ result = ADC_BulkPoll( deviceIndex, &bytesRemaining );
248 if( result == AIOUSB_SUCCESS ) {
249 printf( " %lu bytes remaining\n", bytesRemaining );
250 if( bytesRemaining == 0 )
251 break; // from for()
252 } else {
253 printf( "Error '%s' polling bulk acquire progress\n"
254 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
255 break; // from for()
256 } // if( result ...
257 } // for( int seconds ...
258
259 /*
260 * turn off timer-triggered mode
261 */
262 /*API*/ ADC_ADMode( deviceIndex, 0, AD_CAL_MODE_NORMAL );
263
264 /*
265 * if all the data was apparently received, scan it for zeros; it's
266 * unlikely that any of the data would be zero, so any zeros, particularly
267 * a large block of zeros would suggest that the data is not valid
268 */
269 if(
270 result == AIOUSB_SUCCESS
271 && bytesRemaining == 0
272 ) {
273 bool anyZeroData = false;
274 int zeroIndex = -1;
275 for( int index = 0; index < BULK_BYTES / ( int ) sizeof( unsigned short ); index++ ) {
276 if( dataBuf[ index ] == 0 ) {
277 anyZeroData = true;
278 if( zeroIndex < 0 )
279 zeroIndex = index;
280 } else {
281 if( zeroIndex >= 0 ) {
282 printf( " Zero data from index %d to %d\n", zeroIndex, index - 1 );
283 zeroIndex = -1;
284 } // if( zeroIndex ...
285 } // if( dataBuf[ ...
286 } // for( int index ...
287 if( anyZeroData == false )
288 printf( "Successfully bulk acquired %d bytes\n", BULK_BYTES );
289 } else
290 printf( "Failed to bulk acquire %d bytes\n", BULK_BYTES );
291 } // if( result ...
292
293 free( dataBuf );
294 } // if( dataBuf ...
295 } else
296 printf( "Error '%s' setting A/D configuration\n"
297 /*API*/ , AIOUSB_GetResultCodeAsString( result ) );
298 } else
299 printf( "Failed to find USB-AI16-16A device\n" );
300 } else
301 printf( "No ACCES devices found on USB bus\n" );
302
303 /*
304 * MUST call AIOUSB_Exit() before program exits,
305 * but only if AIOUSB_Init() succeeded
306 */
307 /*API*/ AIOUSB_Exit();
308 } // if( result ...
309 return ( int ) result;
310 } // main()
311
312
313 /* end of file */