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