1 /*
   2  * $RCSfile: sample.cpp,v $
   3  * $Revision: 1.9 $
   4  * $Date: 2010/01/29 18:32:46 $
   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 <string.h>
  47 #include <unistd.h>
  48 using namespace AIOUSB;
  49 // }}}
  50 
  51 int main( int argc, char **argv ) {
  52     printf(
  53         "USB-DIO-16A sample program version 1.9, 29 January 2010\n"
  54         "  AIOUSB library version %s, %s\n"
  55         "  This program demonstrates high speed streaming between 2 USB-DIO-16A\n"
  56         "  devices on the same USB bus. For simplicity, it uses the first 2 such\n"
  57         "  devices found on the bus.\n"
  58 /*API*/ , AIOUSB_GetVersion(), AIOUSB_GetVersionDate()
  59     );
  60 
  61     /*
  62      * MUST call AIOUSB_Init() before any meaningful AIOUSB functions;
  63      * AIOUSB_GetVersion() above is an exception
  64      */
  65 /*API*/ unsigned long result = AIOUSB_Init();
  66     if( result == AIOUSB_SUCCESS ) {
  67         /*
  68          * call GetDevices() to obtain "list" of devices found on the bus
  69          */
  70 /*API*/ unsigned long deviceMask = GetDevices();
  71         if( deviceMask != 0 ) {
  72             /*
  73              * at least one ACCES device detected, but we want devices of a specific type
  74              */
  75 /*API*/     AIOUSB_ListDevices();               // print list of all devices found on the bus
  76 
  77             /*
  78              * search for two USB-DIO-16A devices; the first one will be the
  79              * sender of data, and the second one will be the receiver
  80              */
  81             __uint64_t serialNumber1 = 0        // serial number of sender board
  82                 , serialNumber2 = 0;            // serial number of receiver board
  83             int deviceIndex1 = -1
  84                 , deviceIndex2 = -1
  85                 , index = 0;
  86             while( deviceMask != 0 ) {
  87                 if( ( deviceMask & 1 ) != 0 ) {
  88                     // found a device, but is it the correct type?
  89                     unsigned long productID;
  90 /*API*/             result = QueryDeviceInfo( index, &productID, NULL, NULL, NULL, NULL );
  91                     if( result == AIOUSB_SUCCESS ) {
  92                         if( productID == USB_DIO_16A ) {
  93                             // found a USB-DIO-16A
  94                             if( deviceIndex1 < 0 ) {
  95 /*API*/                         result = GetDeviceSerialNumber( index, &serialNumber1 );
  96                                 if( result == AIOUSB_SUCCESS ) {
  97                                     deviceIndex1 = index;
  98                                     printf( "Sending device at index %d, serial number %llx\n"
  99                                         , deviceIndex1, ( long long ) serialNumber1 );
 100                                 } else {
 101                                     printf( "Error '%s' getting serial number of device at index %d\n"
 102 /*API*/                                 , AIOUSB_GetResultCodeAsString( result ), index );
 103                                     break;      // from while()
 104                                 }   // if( result ...
 105                             } else if( deviceIndex2 < 0 ) {
 106 /*API*/                         result = GetDeviceSerialNumber( index, &serialNumber2 );
 107                                 if( result == AIOUSB_SUCCESS ) {
 108                                     if( serialNumber2 == serialNumber1 ) {
 109                                         printf(
 110                                             "Error: device at index %d and device at index %d have the same serial number of %llx\n"
 111                                             , deviceIndex1, index, ( long long ) serialNumber1
 112                                         );
 113                                     } else {
 114                                         deviceIndex2 = index;
 115                                         printf( "Receiving device at index %d, serial number %llx\n"
 116                                             , deviceIndex2, ( long long ) serialNumber2 );
 117                                     }   // if( serialNumber2 ...
 118                                     break;      // from while()
 119                                 } else {
 120                                     printf( "Error '%s' getting serial number of device at index %d\n"
 121 /*API*/                                 , AIOUSB_GetResultCodeAsString( result ), index );
 122                                     break;      // from while()
 123                                 }   // if( result ...
 124                             }   // else if( deviceIndex2 ...
 125                         }   // if( productID ...
 126                     } else {
 127                         printf( "Error '%s' querying device at index %d\n"
 128 /*API*/                     , AIOUSB_GetResultCodeAsString( result ), index );
 129                         /*
 130                          * even though we got an error from this device,
 131                          * keep searching for other devices
 132                          */
 133                     }   // if( result ...
 134                 }   // if( ( deviceMask ...
 135                 index++;
 136                 deviceMask >>= 1;
 137             }   // while( deviceMask ...
 138 
 139             if(
 140                 deviceIndex1 >= 0
 141                 && deviceIndex2 >= 0
 142                 && serialNumber1 != 0
 143                 && serialNumber2 != 0
 144             ) {
 145                 /*
 146                  * allocate buffer for streaming DIO data to send to receiver
 147                  */
 148                 const double CLOCK_SPEED = 1000000;             // Hz
 149                 const unsigned long FRAME_POINTS = 1024000;     // must be multiple of 256
 150                 unsigned short *const frameData = ( unsigned short * ) malloc( FRAME_POINTS * sizeof( unsigned short ) );
 151                 if( frameData != 0 ) {
 152                     /*
 153                      * fill buffer with a pattern that the receiver can verify
 154                      */
 155                     unsigned long point;
 156                     for( point = 0; point < FRAME_POINTS; point++ )
 157                         frameData[ point ] = point & 0xfffful;
 158 
 159                     /*
 160                      * fork receiver process, passing it the serial number of
 161                      * the receiver board
 162                      */
 163                     const pid_t pid = fork();
 164                     if( pid < 0 ) {
 165                         printf( "Error creating receiver process\n" );
 166                     } else if( pid == 0 ) {
 167                         /*
 168                          * we are now the child process, execute the receiver program; its command
 169                          * line usage is: receiver <hex serial number> <num. points>
 170                          */
 171                         char serialNumber[ 50 ]
 172                             , numPoints[ 20 ];
 173                         sprintf( serialNumber, "%llx", ( long long ) serialNumber2 );
 174                         sprintf( numPoints, "%lu", FRAME_POINTS );
 175                         execl( "./receiver", "receiver", serialNumber, numPoints, NULL );
 176                     } else {
 177                         /*
 178                          * receiver process successfully created; proceed to send the data;
 179                          * configure sending device to send streaming DIO data; sender will
 180                          * control the clock; in this sample program, the sender and receiver
 181                          * are wired together; therefore, their I/O ports must have opposite
 182                          * direction; however, within a device, ports C and D always have
 183                          * opposite direction; so we must configure one board with A, B and C
 184                          * as outputs, and port D as input; then we must configure the other
 185                          * board to be the opposite, or A, B and C as inputs, and port D as
 186                          * output
 187                          */
 188                         unsigned char outputMask = 0x07;    // sender: port D is input; C, B and A are output
 189                         unsigned long initialData = 0xffffffff;
 190                         unsigned char tristateMask = 0x00;
 191                         double ReadClockHz
 192                             , WriteClockHz;
 193                         unsigned long transferred;
 194 
 195                         /*
 196                          * set up communication parameters
 197                          */
 198 /*API*/                 AIOUSB_SetCommTimeout( deviceIndex1, 1000 );
 199 /*API*/                 AIOUSB_SetStreamingBlockSize( deviceIndex1, 256 );
 200 
 201                         /*
 202                          * start the clock; the sender (us) will control the clock
 203                          */
 204                         ReadClockHz = 0;
 205                         WriteClockHz = CLOCK_SPEED;
 206 /*API*/                 result = DIO_StreamSetClocks( deviceIndex1, &ReadClockHz, &WriteClockHz );
 207                         if( result == AIOUSB_SUCCESS ) {
 208                             printf( "Stream clock for device at index %d set to %0.1f Hz\n"
 209                                 , deviceIndex1, WriteClockHz );
 210                         } else {
 211                             printf( "Error '%s' setting stream clock for device at index %d\n"
 212 /*API*/                         , AIOUSB_GetResultCodeAsString( result ), deviceIndex1 );
 213                             goto abort;
 214                         }   // if( result ...
 215 
 216                         /*
 217                          * open stream for writing
 218                          */
 219 /*API*/                 result = DIO_StreamOpen( deviceIndex1, AIOUSB_FALSE /* open for writing */ );
 220                         if( result != AIOUSB_SUCCESS ) {
 221                             printf( "Error '%s' opening write stream for device at index %d\n"
 222 /*API*/                         , AIOUSB_GetResultCodeAsString( result ), deviceIndex1 );
 223                             goto abort;
 224                         }   // if( result ...
 225 
 226                         /*
 227                          * configure I/O ports
 228                          */
 229 /*API*/                 result = DIO_ConfigureEx( deviceIndex1, &outputMask, &initialData, &tristateMask );
 230                         if( result != AIOUSB_SUCCESS ) {
 231                             printf( "Error '%s' configuring device at index %d\n"
 232 /*API*/                         , AIOUSB_GetResultCodeAsString( result ), deviceIndex1 );
 233 /*API*/                     DIO_StreamClose( deviceIndex1 );
 234                             goto abort;
 235                         }   // if( result ...
 236 
 237                         /*
 238                          * send frame
 239                          */
 240 /*API*/                 result = DIO_StreamFrame( deviceIndex1, FRAME_POINTS, frameData, &transferred );
 241                         if( result == AIOUSB_SUCCESS ) {
 242                             if( transferred == FRAME_POINTS * sizeof( unsigned short ) )
 243                                 printf( "%lu point frame successfully written to device at index %d\n"
 244                                     , FRAME_POINTS, deviceIndex1 );
 245                             else
 246                                 printf(
 247                                     "Error: incorrect amount of frame data written to device at index %d\n"
 248                                     "  attempted to write %lu bytes, but actually wrote %lu bytes\n"
 249                                     , deviceIndex1
 250                                     , FRAME_POINTS * sizeof( unsigned short )
 251                                     , transferred );
 252                         } else {
 253                             printf( "Error '%s' writing frame to device at index %d\n"
 254 /*API*/                         , AIOUSB_GetResultCodeAsString( result ), deviceIndex1 );
 255                             AIOUSB_ClearFIFO( deviceIndex1, CLEAR_FIFO_METHOD_IMMEDIATE_AND_ABORT );
 256                         }   // if( result ...
 257 
 258                         /*
 259                          * stop write clock and close stream, but after giving the FIFO time to empty
 260                          * and the receiver time to finish receiving; after the call to DIO_StreamFrame()
 261                          * there may still be data in the sending FIFO; an alternative is to simply not
 262                          * turn off the write clock; the required delay is dependent on the clock rate;
 263                          * the faster the clock, the smaller the delay required; unfortunately, there's
 264                          * no handshaking between the software and the hardware to indicate when
 265                          * transmission is finished
 266                          */
 267                         sleep( 2 );
 268                         ReadClockHz = WriteClockHz = 0;
 269 /*API*/                 DIO_StreamSetClocks( deviceIndex1, &ReadClockHz, &WriteClockHz );
 270 /*API*/                 DIO_StreamClose( deviceIndex1 );
 271 abort:;
 272                     }   // else if( pid ...
 273 
 274                     free( frameData );
 275                 } else {
 276                     printf( "Unable to allocate buffer for frame data\n" );
 277                 }   // if( frameData ...
 278             } else
 279                 printf( "Failed to find 2 USB-DIO-16A devices\n" );
 280         } else
 281             printf( "No ACCES devices found on USB bus\n" );
 282 
 283         /*
 284          * MUST call AIOUSB_Exit() before program exits,
 285          * but only if AIOUSB_Init() succeeded
 286          */
 287 /*API*/ AIOUSB_Exit();
 288     }   // if( result ...
 289 
 290     /*
 291      * pause briefly so receiver can print its output
 292      * before command line prompt reappears
 293      */
 294     sleep( 2 );
 295     return ( int ) result;
 296 }   // main()
 297 
 298 
 299 /* end of file */