Subversion Repositories f9daq

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
145 f9daq 1
/* vxi11_user.cc
2
 * Copyright (C) 2006 Steve D. Sharples
3
 *
4
 * User library for opening, closing, sending to and receiving from
5
 * a device enabled with the VXI11 RPC ethernet protocol. Uses the files
6
 * generated by rpcgen vxi11.x.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
 *
22
 * The author's email address is steve.sharples@nottingham.ac.uk
23
 */
24
 
25
#include "vxi11_user.h"
26
 
27
/*****************************************************************************
28
 * GENERAL NOTES
29
 *****************************************************************************
30
 *
31
 * There are four functions at the heart of this library:
32
 *
33
 * int  vxi11_open_device(char *ip, CLIENT **client, VXI11_LINK **link)
34
 * int  vxi11_close_device(char *ip, CLIENT *client, VXI11_LINK *link)
35
 * int  vxi11_send(CLIENT *client, VXI11_LINK *link, char *cmd, unsigned long len)
36
 * long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len, unsigned long timeout)
37
 *
38
 * Note that all 4 of these use separate client and link structures. All the
39
 * other functions are built on these four core functions, and the first layer
40
 * of abstraction is to combine the CLIENT and VXI11_LINK structures into a
41
 * single entity, which I've called a CLINK. For the send and receive
42
 * functions, this is just a simple wrapper. For the open and close functions
43
 * it's a bit more complicated, because we somehow have to keep track of
44
 * whether we've already opened a device with the same IP address before (in
45
 * which case we need to recycle a previously created client), or whether
46
 * we've still got any other links to a given IP address left when we are
47
 * asked to close a clink (in which case we can sever the link, but have to
48
 * keep the client open). This is so the person using this library from
49
 * userland does not have to keep track of whether they are talking to a
50
 * different physical instrument or not each time they establish a connection.
51
 *
52
 * So the base functions that the user will probably want to use are:
53
 *
54
 * int  vxi11_open_device(char *ip, CLINK *clink)
55
 * int  vxi11_close_device(char *ip, CLINK *clink)
56
 * int  vxi11_send(CLINK *clink, char *cmd, unsigned long len)
57
 *    --- or --- (if sending just text)
58
 * int  vxi11_send(CLINK *clink, char *cmd)
59
 * long vxi11_receive(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout)
60
 *
61
 * There are then useful (to me, anyway) more specific functions built on top
62
 * of these:
63
 *
64
 * int  vxi11_send_data_block(CLINK *clink, char *cmd, char *buffer, unsigned long len)
65
 * long vxi11_receive_data_block(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout)
66
 * long vxi11_send_and_receive(CLINK *clink, char *cmd, char *buf, unsigned long buf_len, unsigned long timeout)
67
 * long vxi11_obtain_long_value(CLINK *clink, char *cmd, unsigned long timeout)
68
 * double vxi11_obtain_double_value(CLINK *clink, char *cmd, unsigned long timeout)
69
 *
70
 * (then there are some shorthand wrappers for the above without specifying
71
 * the timeout due to sheer laziness---explore yourself)
72
 */
73
 
74
 
75
/* Global variables. Keep track of multiple links per client. We need this
76
 * because:
77
 * - we'd like the library to be able to cope with multiple links to a given
78
 *   client AND multiple links to multiple clients
79
 * - we'd like to just refer to a client/link ("clink") as a single
80
 *   entity from user land, we don't want to worry about different
81
 *   initialisation procedures, depending on whether it's an instrument
82
 *   with the same IP address or not
83
 */
84
char    VXI11_IP_ADDRESS[VXI11_MAX_CLIENTS][20];
85
CLIENT  *VXI11_CLIENT_ADDRESS[VXI11_MAX_CLIENTS];
86
int     VXI11_DEVICE_NO = 0;
87
int     VXI11_LINK_COUNT[VXI11_MAX_CLIENTS];
88
 
89
/*****************************************************************************
90
 * KEY USER FUNCTIONS - USE THESE FROM YOUR PROGRAMS OR INSTRUMENT LIBRARIES *
91
 *****************************************************************************/
92
 
93
/* OPEN FUNCTIONS *
94
 * ============== */
95
 
96
/* Use this function from user land to open a device and create a link. Can be
97
 * used multiple times for the same device (the library will keep track).*/
98
int     vxi11_open_device(const char *ip, CLINK *clink, char *device) {
99
int     ret;
100
int     l;
101
int     device_no=-1;
102
 
103
//      printf("before doing anything, clink->link = %ld\n", clink->link);
104
        /* Have a look to see if we've already initialised an instrument with
105
         * this IP address */
106
        for (l=0; l<VXI11_MAX_CLIENTS; l++){
107
                if (strcmp(ip,VXI11_IP_ADDRESS[l]) == 0 ) {
108
                        device_no=l;
109
//                      printf("Open function, search, found ip address %s, device no %d\n",ip,device_no);
110
                        }
111
                }
112
 
113
        /* Couldn't find a match, must be a new IP address */
114
        if (device_no < 0) {
115
                /* Uh-oh, we're out of storage space. Increase the #define
116
                 * for VXI11_MAX_CLIENTS in vxi11_user.h */
117
                if (VXI11_DEVICE_NO >= VXI11_MAX_CLIENTS) {
118
                        printf("Error: maximum of %d clients allowed\n",VXI11_MAX_CLIENTS);
119
                        ret = -VXI11_MAX_CLIENTS;
120
                        }
121
                /* Create a new client, keep a note of where the client pointer
122
                 * is, for this IP address. Because it's a new client, this
123
                 * must be link number 1. Keep track of how many devices we've
124
                 * opened so we don't run out of storage space. */
125
                else {
126
                        ret = vxi11_open_device(ip, &(clink->client), &(clink->link), device);
127
                        strncpy(VXI11_IP_ADDRESS[VXI11_DEVICE_NO],ip,20);
128
                        VXI11_CLIENT_ADDRESS[VXI11_DEVICE_NO] = clink->client;
129
                        VXI11_LINK_COUNT[VXI11_DEVICE_NO]=1;
130
//                      printf("Open function, could not find ip address %s.\n",ip);
131
//                      printf("So now, VXI11_IP_ADDRESS[%d]=%s,\n",VXI11_DEVICE_NO,VXI11_IP_ADDRESS[VXI11_DEVICE_NO]);
132
//                      printf("VXI11_CLIENT_ADDRESS[%d]=%ld,\n",VXI11_DEVICE_NO,VXI11_CLIENT_ADDRESS[VXI11_DEVICE_NO]);
133
//                      printf("          clink->client=%ld,\n",clink->client);
134
//                      printf("VXI11_LINK_COUNT[%d]=%d.\n",VXI11_DEVICE_NO,VXI11_LINK_COUNT[VXI11_DEVICE_NO]);
135
                        VXI11_DEVICE_NO++;
136
                        }
137
                }
138
        /* already got a client for this IP address */
139
        else {
140
                /* Copy the client pointer address. Just establish a new link
141
                 * (not a new client). Add one to the link count */
142
                clink->client = VXI11_CLIENT_ADDRESS[device_no];
143
                ret = vxi11_open_link(ip, &(clink->client), &(clink->link), device);
144
//              printf("Found an ip address, copying client from VXI11_CLIENT_ADDRESS[%d]\n",device_no);
145
                VXI11_LINK_COUNT[device_no]++;
146
//              printf("Have just incremented VXI11_LINK_COUNT[%d], it's now %d\n",device_no,VXI11_LINK_COUNT[device_no]);
147
                }
148
//      printf("after creating link, clink->link = %ld\n", clink->link);
149
        return ret;
150
        }
151
 
152
/* This is a wrapper function, used for the situations where there is only one
153
 * "device" per client. This is the case for most (if not all) VXI11
154
 * instruments; however, it is _not_ the case for devices such as LAN to GPIB
155
 * gateways. These are single clients that communicate to many instruments
156
 * (devices). In order to differentiate between them, we need to pass a device
157
 * name. This gets used in the vxi11_open_link() fn, as the link_parms.device
158
 * value. */
159
int     vxi11_open_device(const char *ip, CLINK *clink) {
160
        char device[6];
161
        strncpy(device,"inst0",6);
162
        return vxi11_open_device(ip, clink, device);
163
        }
164
 
165
 
166
 
167
/* CLOSE FUNCTION *
168
 * ============== */
169
 
170
/* Use this function from user land to close a device and/or sever a link. Can
171
 * be used multiple times for the same device (the library will keep track).*/
172
int     vxi11_close_device(const char *ip, CLINK *clink) {
173
int     l,ret;
174
int     device_no = -1;
175
 
176
        /* Which instrument are we referring to? */
177
        for (l=0; l<VXI11_MAX_CLIENTS; l++){
178
                if (strcmp(ip,VXI11_IP_ADDRESS[l]) == 0 ) {
179
                        device_no=l;
180
                        }
181
                }
182
        /* Something's up if we can't find the IP address! */
183
        if (device_no == -1) {
184
                printf("vxi11_close_device: error: I have no record of you ever opening device\n");
185
                printf("                    with IP address %s\n",ip);
186
                ret = -4;
187
                }
188
        else {  /* Found the IP, there's more than one link to that instrument,
189
                 * so keep track and just close the link */
190
                if (VXI11_LINK_COUNT[device_no] > 1 ) {
191
                        ret = vxi11_close_link(ip,clink->client, clink->link);
192
                        VXI11_LINK_COUNT[device_no]--;
193
                        }
194
                /* Found the IP, it's the last link, so close the device (link
195
                 * AND client) */
196
                else {
197
                        ret = vxi11_close_device(ip, clink->client, clink->link);
198
                        /* Remove the IP address, so that if we re-open the same device
199
                         * we do it properly */
200
                        memset(VXI11_IP_ADDRESS[device_no], 0, 20);
201
                        }
202
                }
203
        return ret;
204
        }
205
 
206
 
207
/* SEND FUNCTIONS *
208
 * ============== */
209
 
210
/* A _lot_ of the time we are sending text strings, and can safely rely on
211
 * strlen(cmd). */
212
int     vxi11_send(CLINK *clink, const char *cmd) {
213
        return vxi11_send(clink, cmd, strlen(cmd));
214
        }
215
 
216
/* We still need the version of the function where the length is set explicitly
217
 * though, for when we are sending fixed length data blocks. */
218
int     vxi11_send(CLINK *clink, const char *cmd, unsigned long len) {
219
        return vxi11_send(clink->client, clink->link, cmd, len);
220
        }
221
 
222
 
223
/* RECEIVE FUNCTIONS *
224
 * ================= */
225
 
226
/* Lazy wrapper for when I can't be bothered to specify a read timeout */
227
long    vxi11_receive(CLINK *clink, char *buffer, unsigned long len) {
228
        return vxi11_receive(clink, buffer, len, VXI11_READ_TIMEOUT);
229
        }
230
 
231
long    vxi11_receive(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) {
232
        return vxi11_receive(clink->client, clink->link, buffer, len, timeout);
233
        }
234
 
235
 
236
 
237
/*****************************************************************************
238
 * USEFUL ADDITIONAL HIGHER LEVER USER FUNCTIONS - USE THESE FROM YOUR       *
239
 * PROGRAMS OR INSTRUMENT LIBRARIES                                          *
240
 *****************************************************************************/
241
 
242
/* SEND FIXED LENGTH DATA BLOCK FUNCTION *
243
 * ===================================== */
244
int     vxi11_send_data_block(CLINK *clink, const char *cmd, char *buffer, unsigned long len) {
245
char    *out_buffer;
246
int     cmd_len=strlen(cmd);
247
int     ret;
248
 
249
        out_buffer=new char[cmd_len+10+len];
250
        sprintf(out_buffer,"%s#8%08lu",cmd,len);
251
        memcpy(out_buffer+cmd_len+10,buffer,(unsigned long) len);
252
        ret = vxi11_send(clink, out_buffer, (unsigned long) (cmd_len+10+len));
253
        delete[] out_buffer;
254
        return ret;
255
        }
256
 
257
 
258
/* RECEIVE FIXED LENGTH DATA BLOCK FUNCTION *
259
 * ======================================== */
260
 
261
/* This function reads a response in the form of a definite-length block, such
262
 * as when you ask for waveform data. The data is returned in the following
263
 * format:
264
 *   #800001000<1000 bytes of data>
265
 *   ||\______/
266
 *   ||    |
267
 *   ||    \---- number of bytes of data
268
 *   |\--------- number of digits that follow (in this case 8, with leading 0's)
269
 *   \---------- always starts with #
270
 */
271
long    vxi11_receive_data_block(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) {
272
/* I'm not sure what the maximum length of this header is, I'll assume it's
273
 * 11 (#9 + 9 digits) */
274
unsigned long   necessary_buffer_size;
275
char            *in_buffer;
276
int             ret;
277
int             ndigits;
278
unsigned long   returned_bytes;
279
int             l;
280
char            scan_cmd[20];
281
        necessary_buffer_size=len+12;
282
        in_buffer=new char[necessary_buffer_size];
283
        ret=vxi11_receive(clink, in_buffer, necessary_buffer_size, timeout);
284
        if (ret < 0) return ret;
285
        if (in_buffer[0] != '#') {
286
                printf("vxi11_user: data block error: data block does not begin with '#'\n");
287
                printf("First 20 characters received were: '");
288
                for(l=0;l<20;l++) {
289
                        printf("%c",in_buffer[l]);
290
                        }
291
                printf("'\n");
292
                return -3;
293
                }
294
 
295
        /* first find out how many digits */
296
        sscanf(in_buffer,"#%1d",&ndigits);
297
        /* some instruments, if there is a problem acquiring the data, return only "#0" */
298
        if (ndigits > 0) {
299
                /* now that we know, we can convert the next <ndigits> bytes into an unsigned long */
300
                sprintf(scan_cmd,"#%%1d%%%dlu",ndigits);
301
                sscanf(in_buffer,scan_cmd,&ndigits,&returned_bytes);
302
                memcpy(buffer, in_buffer+(ndigits+2), returned_bytes);
303
                delete[] in_buffer;
304
                return (long) returned_bytes;
305
                }
306
        else return 0;
307
        }
308
 
309
 
310
/* SEND AND RECEIVE FUNCTION *
311
 * ========================= */
312
 
313
/* This is mainly a useful function for the overloaded vxi11_obtain_value()
314
 * fn's, but is also handy and useful for user and library use */
315
long    vxi11_send_and_receive(CLINK *clink, const char *cmd, char *buf, unsigned long buf_len, unsigned long timeout) {
316
int     ret;
317
long    bytes_returned;
318
        do {
319
                ret = vxi11_send(clink, cmd);
320
                if (ret != 0) {
321
                        if (ret != -VXI11_NULL_WRITE_RESP) {
322
                                printf("Error: vxi11_send_and_receive: could not send cmd.\n");
323
                                printf("       The function vxi11_send returned %d. ",ret);
324
                                return -1;
325
                                }
326
                        else printf("(Info: VXI11_NULL_WRITE_RESP in vxi11_send_and_receive, resending query)\n");
327
                        }
328
 
329
                bytes_returned = vxi11_receive(clink, buf, buf_len, timeout);
330
                if (bytes_returned <= 0) {
331
                        if (bytes_returned >-VXI11_NULL_READ_RESP) {
332
                                printf("Error: vxi11_send_and_receive: problem reading reply.\n");
333
                                printf("       The function vxi11_receive returned %ld. ",bytes_returned);
334
                                return -2;
335
                                }
336
                        else printf("(Info: VXI11_NULL_READ_RESP in vxi11_send_and_receive, resending query)\n");
337
                        }
338
                } while (bytes_returned == -VXI11_NULL_READ_RESP || ret == -VXI11_NULL_WRITE_RESP);
339
        return 0;
340
        }
341
 
342
 
343
/* FUNCTIONS TO RETURN A LONG INTEGER VALUE SENT AS RESPONSE TO A QUERY *
344
 * ==================================================================== */
345
long    vxi11_obtain_long_value(CLINK *clink, const char *cmd, unsigned long timeout) {
346
char    buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */
347
        memset(buf, 0, 50);
348
        if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) {
349
                printf("Returning 0\n");
350
                return 0;
351
                }
352
        return strtol(buf, (char **)NULL, 10);
353
        }
354
 
355
/* Lazy wrapper function with default read timeout */
356
long    vxi11_obtain_long_value(CLINK *clink, const char *cmd) {
357
        return vxi11_obtain_long_value(clink, cmd, VXI11_READ_TIMEOUT);
358
        }
359
 
360
 
361
/* FUNCTIONS TO RETURN A DOUBLE FLOAT VALUE SENT AS RESPONSE TO A QUERY *
362
 * ==================================================================== */
363
double  vxi11_obtain_double_value(CLINK *clink, const char *cmd, unsigned long timeout) {
364
char    buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */
365
double  val;
366
        memset(buf, 0, 50);
367
        if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) {
368
                printf("Returning 0.0\n");
369
                return 0.0;
370
                }
371
        val = strtod(buf, (char **)NULL);
372
        return val;
373
        }
374
 
375
/* Lazy wrapper function with default read timeout */
376
double  vxi11_obtain_double_value(CLINK *clink, const char *cmd) {
377
        return vxi11_obtain_double_value(clink, cmd, VXI11_READ_TIMEOUT);
378
        }
379
 
380
 
381
/*****************************************************************************
382
 * CORE FUNCTIONS - YOU SHOULDN'T NEED TO USE THESE FROM YOUR PROGRAMS OR    *
383
 * INSTRUMENT LIBRARIES                                                      *
384
 *****************************************************************************/
385
 
386
/* OPEN FUNCTIONS *
387
 * ============== */
388
int     vxi11_open_device(const char *ip, CLIENT **client, VXI11_LINK **link, char *device) {
389
 
390
        *client = clnt_create(ip, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
391
 
392
        if (*client == NULL) {
393
                clnt_pcreateerror(ip);
394
                return -1;
395
                }
396
 
397
        return vxi11_open_link(ip, client, link, device);
398
        }
399
 
400
int     vxi11_open_link(const char *ip, CLIENT **client, VXI11_LINK **link, char *device) {
401
 
402
Create_LinkParms link_parms;
403
 
404
        /* Set link parameters */
405
        link_parms.clientId     = (long) *client;
406
        link_parms.lockDevice   = 0;
407
        link_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT;
408
        link_parms.device       = device;
409
 
410
        *link = (Create_LinkResp *) calloc(1, sizeof(Create_LinkResp));
411
 
412
        if (create_link_1(&link_parms, *link, *client) != RPC_SUCCESS) {
413
                clnt_perror(*client, ip);
414
                return -2;
415
                }
416
        return 0;
417
        }
418
 
419
 
420
/* CLOSE FUNCTIONS *
421
 * =============== */
422
int     vxi11_close_device(const char *ip, CLIENT *client, VXI11_LINK *link) {
423
int     ret;
424
 
425
        ret = vxi11_close_link(ip, client, link);
426
 
427
        clnt_destroy(client);
428
 
429
        return ret;
430
        }
431
 
432
int     vxi11_close_link(const char *ip, CLIENT *client, VXI11_LINK *link) {
433
Device_Error dev_error;
434
        memset(&dev_error, 0, sizeof(dev_error));
435
 
436
        if (destroy_link_1(&link->lid, &dev_error, client) != RPC_SUCCESS) {
437
                clnt_perror(client,ip);
438
                return -1;
439
                }
440
 
441
        return 0;
442
        }
443
 
444
 
445
/* SEND FUNCTIONS *
446
 * ============== */
447
 
448
/* A _lot_ of the time we are sending text strings, and can safely rely on
449
 * strlen(cmd). */
450
int     vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd) {
451
        return vxi11_send(client, link, cmd, strlen(cmd));
452
        }
453
 
454
/* We still need the version of the function where the length is set explicitly
455
 * though, for when we are sending fixed length data blocks. */
456
int     vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd, unsigned long len) {
457
Device_WriteParms write_parms;
458
unsigned int    bytes_left = len;
459
char    *send_cmd;
460
 
461
        send_cmd = new char[len];
462
        memcpy(send_cmd, cmd, len);
463
 
464
        write_parms.lid                 = link->lid;
465
        write_parms.io_timeout          = VXI11_DEFAULT_TIMEOUT;
466
        write_parms.lock_timeout        = VXI11_DEFAULT_TIMEOUT;
467
 
468
/* We can only write (link->maxRecvSize) bytes at a time, so we sit in a loop,
469
 * writing a chunk at a time, until we're done. */
470
 
471
        do {
472
                Device_WriteResp write_resp;
473
                memset(&write_resp, 0, sizeof(write_resp));
474
 
475
                if (bytes_left <= link->maxRecvSize) {
476
                        write_parms.flags               = 8;
477
                        write_parms.data.data_len       = bytes_left;
478
                        }
479
                else {
480
                        write_parms.flags               = 0;
481
                        /* We need to check that maxRecvSize is a sane value (ie >0). Believe it
482
                         * or not, on some versions of Agilent Infiniium scope firmware the scope
483
                         * returned "0", which breaks Rule B.6.3 of the VXI-11 protocol. Nevertheless
484
                         * we need to catch this, otherwise the program just hangs. */
485
                        if (link->maxRecvSize > 0) {
486
                                write_parms.data.data_len       = link->maxRecvSize;
487
                                }
488
                        else {
489
                                write_parms.data.data_len       = 4096; /* pretty much anything should be able to cope with 4kB */
490
                                }
491
                        }
492
                write_parms.data.data_val       = send_cmd + (len - bytes_left);
493
 
494
                if(device_write_1(&write_parms, &write_resp, client) != RPC_SUCCESS) {
495
                        delete[] send_cmd;
496
                        return -VXI11_NULL_WRITE_RESP; /* The instrument did not acknowledge the write, just completely
497
                                                          dropped it. There was no vxi11 comms error as such, the
498
                                                          instrument is just being rude. Usually occurs when the instrument
499
                                                          is busy. If we don't check this first, then the following
500
                                                          line causes a seg fault */
501
                        }
502
                if (write_resp.error != 0) {
503
                        printf("vxi11_user: write error: %d\n", (int)write_resp.error);
504
                        delete[] send_cmd;
505
                        return -(write_resp.error);
506
                        }
507
                bytes_left -= write_resp.size;
508
                } while (bytes_left > 0);
509
 
510
        delete[] send_cmd;
511
        return 0;
512
        }
513
 
514
 
515
/* RECEIVE FUNCTIONS *
516
 * ================= */
517
 
518
// It appeared that this function wasn't correctly dealing with more data available than specified in len.
519
// This patch attempts to fix this issue.       RDP 2007/8/13
520
 
521
/* wrapper, for default timeout */ long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len) { return vxi11_receive(client, link, buffer, len, VXI11_READ_TIMEOUT);
522
        }
523
 
524
#define RCV_END_BIT     0x04    // An end indicator has been read
525
#define RCV_CHR_BIT     0x02    // A termchr is set in flags and a character which matches termChar is transferred
526
#define RCV_REQCNT_BIT  0x01    // requestSize bytes have been transferred.  This includes a request size of zero.
527
 
528
long    vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len, unsigned long timeout) {
529
Device_ReadParms read_parms;
530
Device_ReadResp  read_resp;
531
unsigned long   curr_pos = 0;
532
 
533
        read_parms.lid                  = link->lid;
534
        read_parms.requestSize          = len;
535
        read_parms.io_timeout           = timeout;      /* in ms */
536
        read_parms.lock_timeout         = timeout;      /* in ms */
537
        read_parms.flags                = 0;
538
        read_parms.termChar             = 0;
539
 
540
        do {
541
                memset(&read_resp, 0, sizeof(read_resp));
542
 
543
                read_resp.data.data_val = buffer + curr_pos;
544
                read_parms.requestSize = len    - curr_pos;     // Never request more total data than originally specified in len
545
 
546
                if(device_read_1(&read_parms, &read_resp, client) != RPC_SUCCESS) {
547
                        return -VXI11_NULL_READ_RESP; /* there is nothing to read. Usually occurs after sending a query
548
                                                         which times out on the instrument. If we don't check this first,
549
                                                         then the following line causes a seg fault */
550
                        }
551
                if (read_resp.error != 0) {
552
                        /* Read failed for reason specified in error code.
553
                        *  (From published VXI-11 protocol, section B.5.2)
554
                        *  0    no error
555
                        *  1    syntax error
556
                        *  3    device not accessible
557
                        *  4    invalid link identifier
558
                        *  5    parameter error
559
                        *  6    channel not established
560
                        *  8    operation not supported
561
                        *  9    out of resources
562
                        *  11   device locked by another link
563
                        *  12   no lock held by this link
564
                        *  15   I/O timeout
565
                        *  17   I/O error
566
                        *  21   invalid address
567
                        *  23   abort
568
                        *  29   channel already established
569
                        */
570
 
571
                        printf("vxi11_user: read error: %d\n", (int)read_resp.error);
572
                        return -(read_resp.error);
573
                        }
574
 
575
                if((curr_pos + read_resp.data.data_len) <= len) {
576
                        curr_pos += read_resp.data.data_len;
577
                        }
578
                if( (read_resp.reason & RCV_END_BIT) || (read_resp.reason & RCV_CHR_BIT) ) {
579
                        break;
580
                        }
581
                else if( curr_pos == len ) {
582
                        printf("xvi11_user: read error: buffer too small. Read %d bytes without hitting terminator.\n", (int)curr_pos );
583
                        return -100;
584
                        }
585
                } while(1);
586
        return (curr_pos); /*actual number of bytes received*/
587
 
588
        }
589