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