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