42using Device_Link = long;
43using Device_Flags = long;
44using Device_ErrorCode = long;
47 Device_ErrorCode error;
53 unsigned long lock_timeout;
58 Device_ErrorCode error;
60 unsigned short abortPort;
61 unsigned long maxRecvSize;
66 unsigned long io_timeout;
67 unsigned long lock_timeout;
70 unsigned int data_len;
76 Device_ErrorCode error;
82 unsigned long requestSize;
83 unsigned long io_timeout;
84 unsigned long lock_timeout;
90 Device_ErrorCode error;
93 unsigned int data_len;
98constexpr int CREATE_LINK = 10;
99constexpr int DEVICE_WRITE = 11;
100constexpr int DEVICE_READ = 12;
101constexpr int DESTROY_LINK = 23;
103constexpr int VXI11_DEFAULT_TIMEOUT = 10000;
104constexpr int VXI11_READ_TIMEOUT = 2000;
105using VXI11_CLIENT = CLIENT;
107constexpr int VXI11_MAX_CLIENTS = 256;
108constexpr int VXI11_NULL_READ_RESP = 50;
109constexpr int VXI11_NULL_WRITE_RESP = 51;
112 VXI11_CLIENT *client;
116constexpr int DEVICE_CORE = 0x0607AF;
117constexpr int DEVICE_CORE_VERSION = 1;
118constexpr int RCV_END_BIT = 0x04;
119constexpr int RCV_CHR_BIT = 0x02;
121char VXI11_IP_ADDRESS[VXI11_MAX_CLIENTS][20];
122CLIENT *VXI11_CLIENT_ADDRESS[VXI11_MAX_CLIENTS];
123int VXI11_DEVICE_NO = 0;
124int VXI11_LINK_COUNT[VXI11_MAX_CLIENTS] = {0};
126static struct timeval TIMEOUT = {25, 0};
128constexpr int BUF_LEN = 1000000;
131bool sc(
const char *con,
const char *var);
133int vxi11_open_device(
const char *ip,
CLINK *clink);
134int vxi11_open_device(
const char *ip,
CLINK *clink,
const char *device);
135int vxi11_open_device(
const char *ip, CLIENT **client,
VXI11_LINK **link,
const char *device);
136int vxi11_open_link(
const char *ip, CLIENT **client,
VXI11_LINK **link,
const char *device);
137int vxi11_send(
CLINK *clink,
const char *cmd);
138int vxi11_send(
CLINK *clink,
const char *cmd,
unsigned long len);
139int vxi11_send(CLIENT *client,
VXI11_LINK *link,
const char *cmd);
140int vxi11_send(CLIENT *client,
VXI11_LINK *link,
const char *cmd,
unsigned long len);
141int vxi11_close_device(
const char *ip,
CLINK *clink);
142int vxi11_close_device(
const char *ip, CLIENT *client,
VXI11_LINK *link);
143int vxi11_close_link(
const char *ip, CLIENT *client,
VXI11_LINK *link);
144double vxi11_obtain_double_value(
CLINK *clink,
const char *cmd);
145double vxi11_obtain_double_value(
CLINK *clink,
const char *cmd,
unsigned long timeout);
146long vxi11_send_and_receive(
CLINK *clink,
const char *cmd,
char *buf,
unsigned long buf_len,
unsigned long timeout);
147long vxi11_receive(
CLINK *clink,
char *buffer,
unsigned long len);
148long vxi11_receive(CLIENT *client,
VXI11_LINK *link,
char *buffer,
unsigned long len,
unsigned long timeout);
149long vxi11_receive(
CLINK *clink,
char *buffer,
unsigned long len,
unsigned long timeout);
150long vxi11_obtain_long_value(
CLINK *clink,
const char *cmd,
unsigned long timeout);
151long vxi11_obtain_long_value(
CLINK *clink,
const char *cmd);
152long vxi11_receive_data_block(
CLINK *clink,
char *buffer,
unsigned long len,
unsigned long timeout);
157enum clnt_stat destroy_link_1(Device_Link *argp,
Device_Error *clnt_res, CLIENT *clnt);
163bool_t xdr_Device_ErrorCode(XDR *xdrs, Device_ErrorCode *objp);
164bool_t xdr_Device_Link(XDR *xdrs, Device_Link *objp);
167bool_t xdr_Device_Flags(XDR *xdrs, Device_Flags *objp);
172int main(
int argc,
char **argv) {
173 const char *progname = argv[0];
174 const char *serverIP =
nullptr;
175 char comm[256] = {0};
176 long bytes_returned = 0;
178 bool got_comm =
false;
179 bool got_help =
false;
182 char outputbuf[BUF_LEN] = {0};
185 while (index < argc) {
186 if (sc(argv[index],
"-ip") || sc(argv[index],
"-ip_address") || sc(argv[index],
"-IP")) {
187 if (++index < argc) {
188 serverIP = argv[index];
193 if (sc(argv[index],
"-command") || sc(argv[index],
"-c") || sc(argv[index],
"-comm")) {
194 if (++index < argc) {
195 std::snprintf(comm,
sizeof(comm),
"%s", argv[index]);
201 if (sc(argv[index],
"-h") || sc(argv[index],
"-help")) {
209 if (!got_ip || !got_comm || got_help) {
210 if (!got_ip || !got_comm) {
211 std::fprintf(stderr,
"Error: Missing required arguments.\n\n");
213 std::printf(
"Usage: %s [OPTIONS]\n\n", progname);
214 std::printf(
"Options:\n");
215 std::printf(
" -ip, -ip_address, -IP IP address of scope (e.g., 128.243.74.232)\n");
216 std::printf(
" -c, -command, -comm Command or query to send\n");
217 std::printf(
" -h, -help Display this help message\n\n");
218 std::printf(
"Documentation:\n");
219 std::printf(
" http://cp.literature.agilent.com/litweb/pdf/54855-97017.pdf\n");
225 if (vxi11_open_device(serverIP, clink) != 0) {
226 std::fprintf(stderr,
"Error: Failed to open device at IP %s.\n", serverIP);
232 if (vxi11_send(clink, comm) != 0) {
233 std::fprintf(stderr,
"Error: Failed to send command '%s' to device.\n", comm);
234 vxi11_close_device(serverIP, clink);
240 if (std::strchr(comm,
'?') !=
nullptr) {
241 bytes_returned = vxi11_receive(clink, outputbuf, BUF_LEN);
242 vxi11_close_device(serverIP, clink);
244 if (bytes_returned > 0) {
245 std::printf(
"%s\n", outputbuf);
246 }
else if (bytes_returned == -VXI11_NULL_READ_RESP) {
247 std::fprintf(stderr,
"Error: Nothing received after sending scope command '%s'.\n", comm);
251 std::fprintf(stderr,
"Error: Failed to receive response for command '%s'.\n", comm);
256 vxi11_close_device(serverIP, clink);
264bool sc(
const char *con,
const char *var) {
265 return std::strcmp(con, var) == 0;
268int vxi11_open_device(
const char *ip,
CLINK *clink) {
269 const char device[] =
"inst0";
270 return vxi11_open_device(ip, clink, device);
273int vxi11_open_device(
const char *ip, CLIENT **client,
VXI11_LINK **link,
const char *device) {
275 *client = clnt_create(
reinterpret_cast<char *
>(ip), DEVICE_CORE, DEVICE_CORE_VERSION,
"tcp");
277 *client = clnt_create(ip, DEVICE_CORE, DEVICE_CORE_VERSION,
"tcp");
280 if (*client ==
nullptr) {
282 clnt_pcreateerror(
reinterpret_cast<char *
>(ip));
284 clnt_pcreateerror(ip);
289 return vxi11_open_link(ip, client, link, device);
292int vxi11_open_device(
const char *ip,
CLINK *clink,
const char *device) {
296 for (
int l = 0; l < VXI11_MAX_CLIENTS; l++) {
297 if (std::strcmp(ip, VXI11_IP_ADDRESS[l]) == 0) {
304 if (VXI11_DEVICE_NO >= VXI11_MAX_CLIENTS) {
305 std::fprintf(stderr,
"Error: Maximum of %d clients allowed.\n", VXI11_MAX_CLIENTS);
306 ret = -VXI11_MAX_CLIENTS;
308 ret = vxi11_open_device(ip, &(clink->client), &(clink->link), device);
309 std::strncpy(VXI11_IP_ADDRESS[VXI11_DEVICE_NO], ip,
sizeof(VXI11_IP_ADDRESS[VXI11_DEVICE_NO]) - 1);
310 VXI11_IP_ADDRESS[VXI11_DEVICE_NO][
sizeof(VXI11_IP_ADDRESS[VXI11_DEVICE_NO]) - 1] =
'\0';
311 VXI11_CLIENT_ADDRESS[VXI11_DEVICE_NO] = clink->client;
312 VXI11_LINK_COUNT[VXI11_DEVICE_NO] = 1;
316 clink->client = VXI11_CLIENT_ADDRESS[device_no];
317 ret = vxi11_open_link(ip, &(clink->client), &(clink->link), device);
318 VXI11_LINK_COUNT[device_no]++;
323int vxi11_open_link(
const char *ip, CLIENT **client,
VXI11_LINK **link,
const char *device) {
327 link_parms.clientId =
reinterpret_cast<long>(*client);
328 link_parms.lockDevice =
false;
329 link_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT;
330 link_parms.device =
const_cast<char *
>(device);
334 if (create_link_1(&link_parms, *link, *client) != RPC_SUCCESS) {
336 clnt_perror(*client,
reinterpret_cast<char *
>(ip));
338 clnt_perror(*client, ip);
346 return clnt_call(clnt, CREATE_LINK,
347 reinterpret_cast<xdrproc_t
>(xdr_Create_LinkParms),
reinterpret_cast<caddr_t
>(argp),
348 reinterpret_cast<xdrproc_t
>(xdr_Create_LinkResp),
reinterpret_cast<caddr_t
>(clnt_res),
353#if defined(SOLARIS) && !defined(_LP64)
359 if (xdrs->x_op == XDR_ENCODE) {
360 buf =
reinterpret_cast<int32_t *
>(XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT));
361 if (buf ==
nullptr) {
362 if (!xdr_long(xdrs, &objp->clientId))
364 if (!xdr_bool(xdrs, &objp->lockDevice))
366 if (!xdr_u_long(xdrs, &objp->lock_timeout))
369 IXDR_PUT_INT32(buf, objp->clientId);
370 IXDR_PUT_BOOL(buf, objp->lockDevice);
371 IXDR_PUT_U_INT32(buf, objp->lock_timeout);
373 if (!xdr_string(xdrs, &objp->device, ~0))
376 }
else if (xdrs->x_op == XDR_DECODE) {
377 buf =
reinterpret_cast<int32_t *
>(XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT));
378 if (buf ==
nullptr) {
379 if (!xdr_long(xdrs, &objp->clientId))
381 if (!xdr_bool(xdrs, &objp->lockDevice))
383 if (!xdr_u_long(xdrs, &objp->lock_timeout))
386 objp->clientId = IXDR_GET_INT32(buf);
387 objp->lockDevice = IXDR_GET_BOOL(buf);
388 objp->lock_timeout = IXDR_GET_U_INT32(buf);
390 if (!xdr_string(xdrs, &objp->device, ~0))
395 if (!xdr_long(xdrs, &objp->clientId))
397 if (!xdr_bool(xdrs, &objp->lockDevice))
399 if (!xdr_u_long(xdrs, &objp->lock_timeout))
401 if (!xdr_string(xdrs, &objp->device, ~0))
407 if (!xdr_Device_ErrorCode(xdrs, &objp->error))
409 if (!xdr_Device_Link(xdrs, &objp->lid))
411 if (!xdr_u_short(xdrs, &objp->abortPort))
413 if (!xdr_u_long(xdrs, &objp->maxRecvSize))
418bool_t xdr_Device_ErrorCode(XDR *xdrs, Device_ErrorCode *objp) {
419 return xdr_long(xdrs, objp);
422bool_t xdr_Device_Link(XDR *xdrs, Device_Link *objp) {
423 return xdr_long(xdrs, objp);
426int vxi11_send(
CLINK *clink,
const char *cmd) {
427 return vxi11_send(clink, cmd, std::strlen(cmd));
430int vxi11_send(
CLINK *clink,
const char *cmd,
unsigned long len) {
431 return vxi11_send(clink->client, clink->link, cmd, len);
434int vxi11_send(CLIENT *client,
VXI11_LINK *link,
const char *cmd) {
435 return vxi11_send(client, link, cmd, std::strlen(cmd));
438int vxi11_send(CLIENT *client,
VXI11_LINK *link,
const char *cmd,
unsigned long len) {
440 int bytes_left =
static_cast<int>(len);
441 char *send_cmd =
new char[len];
442 std::memcpy(send_cmd, cmd, len);
444 write_parms.lid = link->lid;
445 write_parms.io_timeout = VXI11_DEFAULT_TIMEOUT;
446 write_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT;
449 while (bytes_left > 0) {
452 if (
static_cast<unsigned int>(bytes_left) <= link->maxRecvSize) {
453 write_parms.flags = 8;
454 write_parms.data.data_len = bytes_left;
456 write_parms.flags = 0;
457 write_parms.data.data_len = (link->maxRecvSize > 0) ? link->maxRecvSize : 4096;
459 write_parms.data.data_val = send_cmd + (len - bytes_left);
461 if (device_write_1(&write_parms, &write_resp, client) != RPC_SUCCESS) {
463 return -VXI11_NULL_WRITE_RESP;
465 if (write_resp.error != 0) {
466 std::fprintf(stderr,
"vxi11_user: write error: %ld\n", write_resp.error);
468 return -(write_resp.error);
470 bytes_left -= write_resp.size;
478 return clnt_call(clnt, DEVICE_WRITE,
479 reinterpret_cast<xdrproc_t
>(xdr_Device_WriteParms),
reinterpret_cast<caddr_t
>(argp),
480 reinterpret_cast<xdrproc_t
>(xdr_Device_WriteResp),
reinterpret_cast<caddr_t
>(clnt_res),
485 if (!xdr_Device_Link(xdrs, &objp->lid))
487 if (!xdr_u_long(xdrs, &objp->io_timeout))
489 if (!xdr_u_long(xdrs, &objp->lock_timeout))
491 if (!xdr_Device_Flags(xdrs, &objp->flags))
493 if (!xdr_bytes(xdrs,
reinterpret_cast<char **
>(&objp->data.data_val),
reinterpret_cast<u_int *
>(&objp->data.data_len), ~0))
499 if (!xdr_Device_ErrorCode(xdrs, &objp->error))
501 if (!xdr_u_long(xdrs, &objp->size))
506bool_t xdr_Device_Flags(XDR *xdrs, Device_Flags *objp) {
507 return xdr_long(xdrs, objp);
510int vxi11_close_device(
const char *ip,
CLINK *clink) {
515 for (
int l = 0; l < VXI11_MAX_CLIENTS; l++) {
516 if (std::strcmp(ip, VXI11_IP_ADDRESS[l]) == 0) {
522 if (device_no == -1) {
523 std::fprintf(stderr,
"vxi11_close_device: error: No record of opening device with IP address %s.\n", ip);
526 if (VXI11_LINK_COUNT[device_no] > 1) {
527 ret = vxi11_close_link(ip, clink->client, clink->link);
528 VXI11_LINK_COUNT[device_no]--;
530 ret = vxi11_close_device(ip, clink->client, clink->link);
536int vxi11_close_device(
const char *ip, CLIENT *client,
VXI11_LINK *link) {
537 int ret = vxi11_close_link(ip, client, link);
538 clnt_destroy(client);
542int vxi11_close_link(
const char *ip, CLIENT *client,
VXI11_LINK *link) {
545 if (destroy_link_1(&link->lid, &dev_error, client) != RPC_SUCCESS) {
547 clnt_perror(client,
reinterpret_cast<char *
>(ip));
549 clnt_perror(client, ip);
557enum clnt_stat destroy_link_1(Device_Link *argp,
Device_Error *clnt_res, CLIENT *clnt) {
558 return clnt_call(clnt, DESTROY_LINK,
559 reinterpret_cast<xdrproc_t
>(xdr_Device_Link),
reinterpret_cast<caddr_t
>(argp),
560 reinterpret_cast<xdrproc_t
>(xdr_Device_Error),
reinterpret_cast<caddr_t
>(clnt_res),
565 return xdr_Device_ErrorCode(xdrs, &objp->error);
568double vxi11_obtain_double_value(
CLINK *clink,
const char *cmd) {
569 return vxi11_obtain_double_value(clink, cmd, VXI11_READ_TIMEOUT);
572double vxi11_obtain_double_value(
CLINK *clink,
const char *cmd,
unsigned long timeout) {
574 if (vxi11_send_and_receive(clink, cmd, buf,
sizeof(buf), timeout) != 0) {
575 std::fprintf(stderr,
"Warning: Failed to obtain double value. Returning 0.0.\n");
578 return std::strtod(buf,
nullptr);
581long vxi11_send_and_receive(
CLINK *clink,
const char *cmd,
char *buf,
unsigned long buf_len,
unsigned long timeout) {
585 ret = vxi11_send(clink, cmd);
587 if (ret != -VXI11_NULL_WRITE_RESP) {
588 std::fprintf(stderr,
"Error: vxi11_send_and_receive: Could not send command '%s'. Return code: %d.\n", cmd, ret);
591 std::printf(
"(Info: VXI11_NULL_WRITE_RESP in vxi11_send_and_receive, resending query)\n");
595 bytes_returned = vxi11_receive(clink, buf, buf_len, timeout);
596 if (bytes_returned <= 0) {
597 if (bytes_returned > -VXI11_NULL_READ_RESP) {
598 std::fprintf(stderr,
"Error: vxi11_send_and_receive: Problem reading reply. Return code: %ld.\n", bytes_returned);
601 std::printf(
"(Info: VXI11_NULL_READ_RESP in vxi11_send_and_receive, resending query)\n");
604 }
while (bytes_returned == -VXI11_NULL_READ_RESP || ret == -VXI11_NULL_WRITE_RESP);
608long vxi11_receive(CLIENT *client,
VXI11_LINK *link,
char *buffer,
unsigned long len,
unsigned long timeout) {
613 read_parms.lid = link->lid;
614 read_parms.requestSize = len;
615 read_parms.io_timeout = timeout;
616 read_parms.lock_timeout = timeout;
617 read_parms.flags = 0;
618 read_parms.termChar = 0;
622 read_resp.data.data_val = buffer + curr_pos;
623 read_parms.requestSize = len - curr_pos;
625 if (device_read_1(&read_parms, &read_resp, client) != RPC_SUCCESS) {
626 return -VXI11_NULL_READ_RESP;
628 if (read_resp.error != 0) {
629 std::fprintf(stderr,
"vxi11_user: read error: %ld\n", read_resp.error);
630 return -(read_resp.error);
633 if ((
unsigned long)(curr_pos + read_resp.data.data_len) <= len) {
634 curr_pos += read_resp.data.data_len;
636 if ((read_resp.reason & RCV_END_BIT) || (read_resp.reason & RCV_CHR_BIT)) {
638 }
else if ((
unsigned long)curr_pos == len) {
639 std::fprintf(stderr,
"vxi11_user: read error: Buffer too small. Read %ld bytes without hitting terminator.\n", curr_pos);
646long vxi11_receive(
CLINK *clink,
char *buffer,
unsigned long len) {
647 return vxi11_receive(clink, buffer, len, VXI11_READ_TIMEOUT);
650long vxi11_receive(
CLINK *clink,
char *buffer,
unsigned long len,
unsigned long timeout) {
651 return vxi11_receive(clink->client, clink->link, buffer, len, timeout);
655 return clnt_call(clnt, DEVICE_READ,
656 reinterpret_cast<xdrproc_t
>(xdr_Device_ReadParms),
reinterpret_cast<caddr_t
>(argp),
657 reinterpret_cast<xdrproc_t
>(xdr_Device_ReadResp),
reinterpret_cast<caddr_t
>(clnt_res),
662#if defined(SOLARIS) && !defined(_LP64)
668 if (xdrs->x_op == XDR_ENCODE) {
669 if (!xdr_Device_Link(xdrs, &objp->lid))
671 buf =
reinterpret_cast<int32_t *
>(XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT));
672 if (buf ==
nullptr) {
673 if (!xdr_u_long(xdrs, &objp->requestSize))
675 if (!xdr_u_long(xdrs, &objp->io_timeout))
677 if (!xdr_u_long(xdrs, &objp->lock_timeout))
680 IXDR_PUT_U_INT32(buf, objp->requestSize);
681 IXDR_PUT_U_INT32(buf, objp->io_timeout);
682 IXDR_PUT_U_INT32(buf, objp->lock_timeout);
684 if (!xdr_Device_Flags(xdrs, &objp->flags))
686 if (!xdr_char(xdrs, &objp->termChar))
689 }
else if (xdrs->x_op == XDR_DECODE) {
690 if (!xdr_Device_Link(xdrs, &objp->lid))
692 buf =
reinterpret_cast<int32_t *
>(XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT));
693 if (buf ==
nullptr) {
694 if (!xdr_u_long(xdrs, &objp->requestSize))
696 if (!xdr_u_long(xdrs, &objp->io_timeout))
698 if (!xdr_u_long(xdrs, &objp->lock_timeout))
701 objp->requestSize = IXDR_GET_U_INT32(buf);
702 objp->io_timeout = IXDR_GET_U_INT32(buf);
703 objp->lock_timeout = IXDR_GET_U_INT32(buf);
705 if (!xdr_Device_Flags(xdrs, &objp->flags))
707 if (!xdr_char(xdrs, &objp->termChar))
712 if (!xdr_Device_Link(xdrs, &objp->lid))
714 if (!xdr_u_long(xdrs, &objp->requestSize))
716 if (!xdr_u_long(xdrs, &objp->io_timeout))
718 if (!xdr_u_long(xdrs, &objp->lock_timeout))
720 if (!xdr_Device_Flags(xdrs, &objp->flags))
722 if (!xdr_char(xdrs, &objp->termChar))
728 if (!xdr_Device_ErrorCode(xdrs, &objp->error))
730 if (!xdr_long(xdrs, &objp->reason))
732 if (!xdr_bytes(xdrs,
reinterpret_cast<char **
>(&objp->data.data_val),
reinterpret_cast<u_int *
>(&objp->data.data_len), ~0))
737long vxi11_obtain_long_value(
CLINK *clink,
const char *cmd,
unsigned long timeout) {
739 if (vxi11_send_and_receive(clink, cmd, buf,
sizeof(buf), timeout) != 0) {
740 std::fprintf(stderr,
"Warning: Failed to obtain long value. Returning 0.\n");
743 return std::strtol(buf,
nullptr, 10);
747long vxi11_obtain_long_value(
CLINK *clink,
const char *cmd) {
748 return vxi11_obtain_long_value(clink, cmd, VXI11_READ_TIMEOUT);
751long vxi11_receive_data_block(
CLINK *clink,
char *buffer,
unsigned long len,
unsigned long timeout) {
753 unsigned long necessary_buffer_size = len + 12;
754 char *in_buffer =
new char[necessary_buffer_size];
755 long ret = vxi11_receive(clink, in_buffer, necessary_buffer_size, timeout);
760 if (in_buffer[0] !=
'#') {
761 std::fprintf(stderr,
"vxi11_user: data block error: Data block does not begin with '#'.\n");
762 std::fprintf(stderr,
"First 20 characters received were: '");
763 for (
size_t l = 0; l < 20 && l < (size_t)necessary_buffer_size; l++) {
764 std::fprintf(stderr,
"%c", in_buffer[l]);
766 std::fprintf(stderr,
"'\n");
773 sscanf(in_buffer,
"#%1d", &ndigits);
779 std::snprintf(scan_cmd,
sizeof(scan_cmd),
"#%%1d%%%dlu", ndigits);
780 unsigned long returned_bytes = 0;
781 sscanf(in_buffer, scan_cmd, &ndigits, &returned_bytes);
782 std::memcpy(buffer, in_buffer + (ndigits + 2), returned_bytes);
784 return static_cast<long>(returned_bytes);