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 */