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