├── config.mk ├── .gitignore ├── python ├── setup.py └── vxi11.py ├── library ├── linker.version ├── Makefile ├── vxi11_user.h ├── vxi11.x └── vxi11_user.c ├── Makefile ├── utils ├── Makefile ├── vxi11_send.c └── vxi11_cmd.c ├── CMakeLists.txt ├── README.md ├── CHANGELOG.txt └── GNU_General_Public_License.txt /config.mk: -------------------------------------------------------------------------------- 1 | CFLAGS=-g 2 | LDFLAGS= 3 | 4 | INSTALL=install 5 | MAKE=make 6 | 7 | prefix=/usr/local 8 | 9 | SOVERSION=1 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | vxi11.h 3 | vxi11_cmd 4 | vxi11_clnt.c 5 | vxi11_svc.c 6 | vxi11_xdr.c 7 | TAGS 8 | vxi11_test.cc 9 | vxi11_test.cc 10 | docs 11 | libvxi11.so.0 12 | vxi11_send 13 | *.o 14 | *.pyc 15 | .pc/ 16 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | setup(name='vxi11', 3 | version='1.12', 4 | description='Communication with instruments over VISA/VXI11', 5 | url='http://github.com/applied-optics/vxi11', 6 | license='GPL 2', 7 | py_modules=['vxi11'] 8 | ) 9 | -------------------------------------------------------------------------------- /library/linker.version: -------------------------------------------------------------------------------- 1 | /* Linker version script - currently used here primarily to control which 2 | * symbols are exported. 3 | */ 4 | 5 | VXI11_2.0 { 6 | global: 7 | vxi11_close_device; 8 | vxi11_lib_version; 9 | vxi11_obtain_double_value; 10 | vxi11_obtain_double_value_timeout; 11 | vxi11_obtain_long_value; 12 | vxi11_obtain_long_value_timeout; 13 | vxi11_open_device; 14 | vxi11_receive; 15 | vxi11_receive_data_block; 16 | vxi11_receive_timeout; 17 | vxi11_send; 18 | vxi11_send_and_receive; 19 | vxi11_send_data_block; 20 | vxi11_send_printf; 21 | local: *; 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=2.0 2 | 3 | include config.mk 4 | 5 | DIRS=library utils 6 | 7 | .PHONY : all clean install 8 | 9 | all : 10 | for d in ${DIRS}; do $(MAKE) -C $${d}; done 11 | 12 | clean : 13 | for d in ${DIRS}; do $(MAKE) -C $${d} clean; done 14 | 15 | install : all 16 | for d in ${DIRS}; do $(MAKE) -C $${d} install; done 17 | 18 | dist : distclean 19 | mkdir vxi11-$(VERSION) 20 | cp -pr library utils vxi11-$(VERSION)/ 21 | cp -p config.mk Makefile CMakeLists.txt CHANGELOG.txt README.md GNU_General_Public_License.txt vxi11-$(VERSION)/ 22 | tar -zcf vxi11-$(VERSION).tar.gz vxi11-$(VERSION) 23 | 24 | distclean : clean 25 | rm -rf vxi11-$(VERSION) 26 | rm -f vxi11-$(VERSION).tar.gz 27 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | .PHONY : all install clean 4 | 5 | CFLAGS:=${CFLAGS} -I../library 6 | 7 | all : vxi11_cmd vxi11_send 8 | 9 | vxi11_cmd: vxi11_cmd.o ../library/libvxi11.so.${SOVERSION} 10 | $(CC) -o $@ $^ $(LDFLAGS) 11 | 12 | vxi11_cmd.o: vxi11_cmd.c ../library/vxi11_user.c ../library/vxi11.h 13 | $(CC) $(CFLAGS) -c $< -o $@ 14 | 15 | vxi11_send: vxi11_send.o ../library/libvxi11.so.${SOVERSION} 16 | $(CC) -o $@ $^ $(LDFLAGS) 17 | 18 | vxi11_send.o: vxi11_send.c ../library/vxi11_user.c ../library/vxi11.h 19 | $(CC) $(CFLAGS) -c $< -o $@ 20 | 21 | clean: 22 | rm -f *.o vxi11_cmd vxi11_send 23 | 24 | install: all 25 | $(INSTALL) -d $(DESTDIR)$(prefix)/bin/ 26 | $(INSTALL) vxi11_cmd $(DESTDIR)$(prefix)/bin/ 27 | $(INSTALL) vxi11_send $(DESTDIR)$(prefix)/bin/ 28 | 29 | -------------------------------------------------------------------------------- /library/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | .PHONY : all install clean dist distclean 4 | 5 | UNAME:=$(shell uname -s) 6 | 7 | ifneq ($(UNAME),SunOS) 8 | LDFLAGS:=$(LDFLAGS) -Wl,--version-script=linker.version 9 | endif 10 | 11 | all : libvxi11.so.${SOVERSION} 12 | 13 | libvxi11.so.${SOVERSION} : vxi11_user.o vxi11_clnt.o vxi11_xdr.o 14 | $(CC) $(LDFLAGS) -shared -Wl,-soname,libvxi11.so.${SOVERSION} $^ -o $@ 15 | 16 | vxi11_user.o: vxi11_user.c vxi11.h 17 | $(CC) -fPIC $(CFLAGS) -c $< -o $@ 18 | 19 | vxi11_clnt.o : vxi11_clnt.c 20 | $(CC) -fPIC $(CFLAGS) -c $< -o $@ 21 | 22 | vxi11_xdr.o : vxi11_xdr.c 23 | $(CC) -fPIC $(CFLAGS) -c $< -o $@ 24 | 25 | vxi11.h vxi11_clnt.c vxi11_xdr.c : vxi11.x 26 | rpcgen -M vxi11.x 27 | 28 | TAGS: $(wildcard *.c) $(wildcard *.h) $(wildcard *.c) 29 | etags $^ 30 | 31 | clean: 32 | rm -f *.o libvxi11.so.${SOVERSION} vxi11.h vxi11_svc.c vxi11_xdr.c vxi11_clnt.c TAGS 33 | 34 | install: all 35 | $(INSTALL) -d $(DESTDIR)$(prefix)/lib${LIB_SUFFIX}/ 36 | $(INSTALL) libvxi11.so.${SOVERSION} $(DESTDIR)$(prefix)/lib${LIB_SUFFIX}/ 37 | ln -sf libvxi11.so.${SOVERSION} $(DESTDIR)$(prefix)/lib${LIB_SUFFIX}/libvxi11.so 38 | $(INSTALL) -d $(DESTDIR)$(prefix)/include/ 39 | $(INSTALL) vxi11_user.h $(DESTDIR)$(prefix)/include/ 40 | 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For compiling on Windows. 2 | 3 | project(vxi11) 4 | 5 | cmake_minimum_required(VERSION 2.6) 6 | 7 | set (VERSION 1.10) 8 | 9 | if (NOT WIN32) 10 | add_custom_command(OUTPUT ${vxi11_SOURCE_DIR}/vxi11.h 11 | ${vxi11_SOURCE_DIR}/vxi11_clnt.c 12 | ${vxi11_SOURCE_DIR}/vxi11_xdr.c 13 | ${vxi11_SOURCE_DIR}/vxi11_svc.c 14 | PRE_BUILD 15 | COMMAND rpcgen -M ${vxi11_SOURCE_DIR}/vxi11.x 16 | MAIN_DEPENDENCY ${vxi11_SOURCE_DIR}/vxi11.x 17 | COMMENT "Generating RPC code") 18 | endif (NOT WIN32) 19 | 20 | # ================================================== 21 | # Shared library for vxi11 22 | # ================================================== 23 | 24 | set(vxi11_SRCS library/vxi11_user.c library/vxi11_user.h) 25 | if (WIN32) 26 | include_directories(C:\\VXIpnp\\WINNT\\include) 27 | link_directories(C:\\VXIpnp\\WINNT\\lib\\msc) 28 | else (WIN32) 29 | set(vxi11_SRCS ${vxi11_SRCS} library/vxi11.h library/vxi11_clnt.c 30 | library/vxi11_xdr.c library/vxi11.x) 31 | endif (WIN32) 32 | 33 | 34 | add_library(vxi11 SHARED ${vxi11_SRCS}) 35 | 36 | set_target_properties(vxi11 PROPERTIES 37 | VERSION 0.${VERSION} 38 | SOVERSION 0 39 | ) 40 | 41 | if(WIN32) 42 | target_link_libraries(vxi11 visa32) 43 | endif(WIN32) 44 | 45 | if (CYGWIN) 46 | include_directories(/usr/include/tirpc) 47 | target_link_libraries(vxi11 tirpc) 48 | endif (CYGWIN) 49 | 50 | # ================================================== 51 | # Command line utility 52 | # ================================================== 53 | 54 | add_executable(vxi11_cmd utils/vxi11_cmd.c) 55 | target_link_libraries(vxi11_cmd vxi11) 56 | 57 | add_executable(vxi11_send utils/vxi11_send.c) 58 | target_link_libraries(vxi11_send vxi11) 59 | -------------------------------------------------------------------------------- /utils/vxi11_send.c: -------------------------------------------------------------------------------- 1 | /* vxi11_send.c 2 | * Copyright (C) 2006 Steve D. Sharples 3 | * 4 | * A simple interactive utility that allows you to send a single command to 5 | * a device enabled with the VXI11 RPC ethernet protocol. Uses the files 6 | * generated by rpcgen vxi11.x, and the vxi11_user.h user libraries. 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 26 | #include 27 | #include 28 | 29 | #include "vxi11_user.h" 30 | 31 | #ifdef WIN32 32 | #define strncasecmp(a, b, c) stricmp(a, b) 33 | #endif 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | 38 | static char *device_ip; 39 | char cmd[256]; 40 | VXI11_CLINK *clink; 41 | 42 | if (argc < 2) { 43 | printf("usage: %s your.inst.ip.addr command\n", argv[0]); 44 | exit(1); 45 | } 46 | 47 | device_ip = argv[1]; 48 | if(vxi11_open_device(&clink, device_ip, NULL)){ 49 | printf("Error: could not open device %s, quitting\n", 50 | device_ip); 51 | exit(2); 52 | } 53 | 54 | memset(cmd, 0, 256); // initialize command string 55 | strncpy(cmd, argv[2], 256); 56 | vxi11_send(clink, cmd, strlen(cmd)); 57 | vxi11_close_device(clink, device_ip); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /utils/vxi11_cmd.c: -------------------------------------------------------------------------------- 1 | /* vxi11_cmd.c 2 | * Copyright (C) 2006 Steve D. Sharples 3 | * 4 | * A simple interactive utility that allows you to send commands and queries to 5 | * a device enabled with the VXI11 RPC ethernet protocol. Uses the files 6 | * generated by rpcgen vxi11.x, and the vxi11_user.h user libraries. 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 26 | #include 27 | #include 28 | 29 | #include "vxi11_user.h" 30 | #define BUF_LEN 100000 31 | 32 | #ifdef WIN32 33 | #define strncasecmp(a, b, c) stricmp(a, b) 34 | #endif 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | 39 | char *device_ip; 40 | char *device_name = NULL; 41 | char cmd[256]; 42 | char buf[BUF_LEN]; 43 | int ret; 44 | long bytes_returned; 45 | VXI11_CLINK *clink; 46 | 47 | if (argc < 2) { 48 | printf("usage: %s your.inst.ip.addr [device_name]\n", argv[0]); 49 | exit(1); 50 | } 51 | 52 | device_ip = argv[1]; 53 | if (argc > 2) { 54 | device_name = argv[2]; 55 | } 56 | if(vxi11_open_device(&clink, device_ip, device_name)){ 57 | printf("Error: could not open device %s, quitting\n", 58 | device_ip); 59 | exit(2); 60 | } 61 | 62 | while (1) { 63 | memset(cmd, 0, 256); // initialize command string 64 | memset(buf, 0, BUF_LEN); // initialize buffer 65 | printf("Input command or query ('q' to exit): "); 66 | fgets(cmd, 256, stdin); 67 | cmd[strlen(cmd) - 1] = 0; // just gets rid of the \n 68 | if (strncasecmp(cmd, "q", 1) == 0) { 69 | break; 70 | } 71 | 72 | if (vxi11_send(clink, cmd, strlen(cmd)) < 0) { 73 | break; 74 | } 75 | if (strstr(cmd, "?") != 0) { 76 | bytes_returned = vxi11_receive(clink, buf, BUF_LEN); 77 | if (bytes_returned > 0) { 78 | printf("%s\n", buf); 79 | } else if (bytes_returned == -15) { 80 | printf("*** [ NOTHING RECEIVED ] ***\n"); 81 | } else { 82 | break; 83 | } 84 | } 85 | } 86 | 87 | ret = vxi11_close_device(clink, device_ip); 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RPC PROTOCOL FOR COMMUNICATING WITH VXI11-ENABLED DEVICES OVER ETHERNET FROM LINUX 2 | ================================================================================== 3 | 4 | (including instruments such as oscilloscopes, by manufacturers such as 5 | Agilent and Tektronix, amongst others). 6 | 7 | By Steve D. Sharples, June 2006. 8 | 9 | 10 | Background 11 | ---------- 12 | 13 | This is a collection of source code that will allow you to talk to ethernet- 14 | enabled instruments that use the VXI11 protocol, from Linux. This includes 15 | a wide range of instruments (including oscilloscopes, logic analysers, 16 | function generators etc) by a wide range of manufacturers (including 17 | Tektronix and Agilent to name just a couple). An interactive "send and 18 | receive" utility is included as an example. 19 | 20 | You may want to build on to this libraries for your specific instruments - 21 | I'm currently working on libraries for talking to Agilent Infiniium scopes, 22 | and will probably do the same for Tektronix scopes too. Basically if you've 23 | got a Programmer's Reference for your instrument, and this code, you should 24 | be able to cobble something together. 25 | 26 | This collection of code has been produced because I grew frustrated at how 27 | difficult it seemed to be to do a relatively simple task. None of the 28 | major manufacturers had any "out of the box" Linux solutions to talking to 29 | their instruments (although often I would talk to technical folks who would 30 | try their best to help). One of the solutions offered was to use something 31 | called NI VISA; parts of this are closed source, it was enormous, and I had 32 | worries about legacy issues with changing PC hardware. 33 | 34 | Via Guy McBride at Agilent, I obtained a copy of a vxi11.x RPC file similar 35 | to the one included here (although no-one at Agilent seemed to know or care 36 | where it came from). After lots of searching on the information superhighway 37 | I located what I believe is the original source (or something like it); see 38 | the section on vxi11.x below. This source seems to have literally been written 39 | from the published VXI11 protocol. I also received from Agilent a simple 40 | example program that showed you how to use the protocol; working from this 41 | and the (open) source that uses the vxi11.x that is included here, I wrote 42 | `vxi11_cmd` and the user libraries. 43 | 44 | 45 | Source code 46 | ----------- 47 | 48 | This package consists of a user library, `libvxi11`, two command line 49 | utilities, `vxi11_cmd` and `vxi11_send`, and a Python wrapper for libvxi11. 50 | 51 | To compile, run `make`, then and `make install` to install. 52 | 53 | See `library/vxi11_user.h` for the functions provided by the library. 54 | 55 | 56 | Utilities 57 | --------- 58 | 59 | `vxi11_cmd` is a simple interactive utility that allows you to send commands 60 | and queries to your VXI11 enabled instrument. You will need to consult the 61 | reference manual for your device to find the appropriate commands. You could 62 | start by sending `*IDN?`. 63 | 64 | `vxi11_send` is a simple interactive utility that allows you to send a single 65 | command to your VXI11 enabled instrument. 66 | 67 | 68 | License 69 | ------- 70 | 71 | library/vxi11.x is covered by its own license, see the file for more details. 72 | 73 | Fairly obvious. All programs, source, readme files etc NOT covered by any 74 | other license (e.g. vxi11.x, which is covered by its own open source 75 | license) are covered by the GNU GPL version 2 or later. 76 | 77 | These programs are free software; you can redistribute it and/or 78 | modify it under the terms of the GNU General Public License 79 | as published by the Free Software Foundation; either version 2 80 | of the License, or (at your option) any later version. 81 | 82 | These programs are distributed in the hope that they will be useful, 83 | but WITHOUT ANY WARRANTY; without even the implied warranty of 84 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 85 | GNU General Public License for more details. 86 | 87 | You should have received a copy of the GNU General Public License 88 | along with this program; if not, write to the Free Software 89 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 90 | 91 | The author's email address is steve.no.spam.sharples@nottingham.ac.uk 92 | (you can work it out!) 93 | -------------------------------------------------------------------------------- /python/vxi11.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Roger A. Light 2 | # 3 | # Python wrapper to libvxi11. 4 | 5 | # User library for opening, closing, sending to and receiving from 6 | # a device enabled with the VXI11 RPC ethernet protocol. Uses the files 7 | # generated by rpcgen vxi11.x. 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # as published by the Free Software Foundation; either version 2 12 | # of the License, or (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 | 23 | from ctypes import * 24 | import ctypes.util 25 | 26 | DEFAULT_TIMEOUT = 10000 27 | READ_TIMEOUT = 2000 28 | NULL_READ_RESP = 50 29 | NULL_WRITE_RESP = 51 30 | 31 | 32 | class Vxi11(object): 33 | def __init__(self, address, device="inst0"): 34 | if address is None or address == "": 35 | raise ValueError("address must be defined") 36 | 37 | self._clink = c_void_p() 38 | self._address = address 39 | self._device = device 40 | if address: 41 | a = c_char_p(address.encode()) 42 | else: 43 | a = None 44 | if device: 45 | d = c_char_p(device.encode()) 46 | else: 47 | d = None 48 | if(_vxi11_open_device(byref(self._clink), a, d)): 49 | raise IOError("unable to open device at address "+address) 50 | 51 | def __del__(self): 52 | self.close() 53 | 54 | def close(self): 55 | if self._clink: 56 | if self._address: 57 | a = c_char_p(self._address.encode()) 58 | else: 59 | a = None 60 | _vxi11_close_device(self._clink, a) 61 | self._clink = None 62 | self._address = None 63 | self._device = None 64 | 65 | def send(self, cmd): 66 | c = cmd.encode() 67 | rc = _vxi11_send(self._clink, c_char_p(c), len(c)) 68 | return rc 69 | 70 | def receive(self, max_length=1024, timeout=READ_TIMEOUT): 71 | buf = create_string_buffer(max_length) 72 | rc = _vxi11_receive_timeout(self._clink, buf, max_length, timeout) 73 | if rc < 0: 74 | return (rc, None) 75 | else: 76 | return (rc, buf.value) 77 | 78 | def send_data_block(self, cmd, buf): 79 | if _vxi11_send_data_block(self._clink, cmd.encode(), buf, len(buf)): 80 | raise IOError("error sending to the device: "+str(rc)) 81 | return 1 82 | 83 | def receive_data_block(self, max_length=1024, timeout=READ_TIMEOUT): 84 | buf = create_string_buffer(max_length) 85 | rc = _vxi11_receive_data_block(self._clink, buf, max_length, timeout) 86 | if rc < 0: 87 | return (rc, None) 88 | else: 89 | return (rc, buf.value) 90 | 91 | def send_and_receive(self, cmd, max_length=1024, timeout=READ_TIMEOUT): 92 | buf = create_string_buffer(max_length) 93 | c = cmd.encode() 94 | rc = _vxi11_send_and_receive(self._clink, c_char_p(c), buf, max_length, timeout) 95 | if rc < 0: 96 | return (rc, None) 97 | else: 98 | return (rc, buf.value) 99 | 100 | def obtain_long_value(self, cmd, timeout=READ_TIMEOUT): 101 | return _vxi11_obtain_long_value_timeout(self._clink, cmd, timeout) 102 | 103 | def obtain_double_value(self, cmd, timeout=READ_TIMEOUT): 104 | return _vxi11_obtain_double_value_timeout(self._clink, cmd, timeout) 105 | 106 | 107 | _libvxi11 = cdll.LoadLibrary(ctypes.util.find_library("vxi11")) 108 | 109 | _vxi11_open_device = _libvxi11.vxi11_open_device 110 | _vxi11_open_device.argtypes = [POINTER(c_void_p), c_char_p, c_char_p] 111 | _vxi11_open_device.restype = c_int 112 | 113 | _vxi11_close_device = _libvxi11.vxi11_close_device 114 | _vxi11_close_device.argtypes = [c_void_p, c_char_p] 115 | _vxi11_close_device.restype = c_int 116 | 117 | _vxi11_send = _libvxi11.vxi11_send 118 | _vxi11_send.argtypes = [c_void_p, c_char_p, c_size_t] 119 | _vxi11_send.restype = c_int 120 | 121 | _vxi11_receive = _libvxi11.vxi11_receive 122 | _vxi11_receive.argtypes = [c_void_p, c_char_p, c_size_t, c_ulong] 123 | _vxi11_receive.restype = c_ssize_t 124 | 125 | _vxi11_send_data_block = _libvxi11.vxi11_send_data_block 126 | _vxi11_send_data_block.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t] 127 | _vxi11_send_data_block.restype = c_int 128 | 129 | _vxi11_receive_data_block = _libvxi11.vxi11_receive_data_block 130 | _vxi11_receive_data_block.argtypes = [c_void_p, c_char_p, c_size_t, c_ulong] 131 | _vxi11_receive_data_block.restype = c_ssize_t 132 | 133 | _vxi11_send_and_receive = _libvxi11.vxi11_send_and_receive 134 | _vxi11_send_and_receive.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t, c_ulong] 135 | _vxi11_send_and_receive.restype = c_int 136 | 137 | _vxi11_obtain_long_value_timeout = _libvxi11.vxi11_obtain_long_value_timeout 138 | _vxi11_obtain_long_value_timeout.argtypes = [c_void_p, c_char_p, c_ulong] 139 | _vxi11_obtain_long_value_timeout.restype = c_long 140 | 141 | _vxi11_obtain_double_value_timeout = _libvxi11.vxi11_obtain_double_value_timeout 142 | _vxi11_obtain_double_value_timeout.argtypes = [c_void_p, c_char_p, c_ulong] 143 | _vxi11_obtain_double_value_timeout.restype = c_double 144 | 145 | 146 | -------------------------------------------------------------------------------- /library/vxi11_user.h: -------------------------------------------------------------------------------- 1 | /* vxi11_user.h 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 | #ifndef _VXI11_USER_H_ 26 | #define _VXI11_USER_H_ 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #ifdef WIN32 33 | # ifdef vxi11_EXPORTS 34 | # define vx_EXPORT __declspec(dllexport) 35 | # else 36 | # define vx_EXPORT __declspec(dllimport) 37 | # endif 38 | #else 39 | # define vx_EXPORT 40 | # define __stdcall 41 | #endif 42 | 43 | #include 44 | 45 | 46 | #define LIBVXI11_MAJOR 2 47 | #define LIBVXI11_MINOR 0 48 | #define LIBVXI11_REVISION 0 49 | /* LIBVXI11_VERSION_NUMBER looks like 2002001 for e.g. version 2.2.1. */ 50 | #define LIBVXI11_VERSION_NUMBER (LIBVXI11_MAJOR*1000000+LIBVXI11_MINOR*1000+LIBVXI11_REVISION) 51 | 52 | 53 | typedef struct _VXI11_CLINK VXI11_CLINK; 54 | 55 | /* Default timeout value to use, in ms. */ 56 | #define VXI11_DEFAULT_TIMEOUT 10000 57 | 58 | /* Read timeout to use, in ms. */ 59 | #define VXI11_READ_TIMEOUT 2000 60 | 61 | /* vxi11_receive() return value if a query times out ON THE INSTRUMENT (and so 62 | * we have to resend the query). */ 63 | #define VXI11_NULL_READ_RESP 50 64 | 65 | /* vxi11_send() return value if a sent command times out ON THE INSTRUMENT. */ 66 | #define VXI11_NULL_WRITE_RESP 51 67 | 68 | 69 | /* Function: vxi11_library_version 70 | * 71 | * Return the version of the current library. 72 | * 73 | * Parameters: 74 | * major - an integer pointer. If not NULL, the major version of the 75 | * library will be returned in this variable. 76 | * minor - an integer pointer. If not NULL, the minor version of the 77 | * library will be returned in this variable. 78 | * revision - an integer pointer. If not NULL, the revision of the library will 79 | * be returned in this variable. 80 | * 81 | * Returns: 82 | * LIBVXI11_VERSION_NUMBER, which is a unique number based on the major, 83 | * minor and revision values. 84 | */ 85 | vx_EXPORT int vxi11_lib_version(int *major, int *minor, int *revision); 86 | 87 | 88 | /* Function: vxi11_open_device 89 | * 90 | * Open a connection to an instrument. 91 | * 92 | * Parameters: 93 | * clink - pointer to a VXI11_CLINK pointer, will be initialised on a 94 | * successful connection. 95 | * address - the IP address or (where supported) USB address for the 96 | * instrument to connect to. 97 | * device - some instruments have multiple interfaces, this allows you to 98 | * specify which to connect to. Set to NULL to use the default of 99 | * "inst0". 100 | * 101 | * Returns: 102 | * 0 - on success 103 | * 1 - on failure. clink will not be a valid pointer. 104 | */ 105 | vx_EXPORT int vxi11_open_device(VXI11_CLINK **clink, const char *address, char *device); 106 | 107 | 108 | /* Function: vxi11_close_device 109 | * 110 | * Parameters: 111 | * clink - a valid VXI11_CLINK pointer. 112 | * address - the IP address or (where supported) USB address for the 113 | * instrument. 114 | * 115 | * Returns: 116 | * 0 - on success 117 | */ 118 | vx_EXPORT int vxi11_close_device(VXI11_CLINK *clink, const char *address); 119 | 120 | 121 | /* Function: vxi11_send 122 | * 123 | * Send data to an instrument. 124 | * 125 | * Parameters: 126 | * clink - a valid VXI11_CLINK pointer. 127 | * cmd - the command to send as an array of bytes 128 | * len - the length of cmd 129 | * 130 | * Returns: 131 | * 0 - on success 132 | * 1 - on out of memory 133 | * -VXI11_NULL_WRITE_RESP - on send timeout (retry is acceptable) 134 | */ 135 | vx_EXPORT int vxi11_send(VXI11_CLINK *clink, const char *cmd, size_t len); 136 | 137 | 138 | /* Function: vxi11_send_printf 139 | * 140 | * Send data to an instrument. Convenience function when sending text. 141 | * 142 | * Parameters: 143 | * clink - a valid VXI11_CLINK pointer. 144 | * format - printf style format specifier. 145 | * 146 | * Returns: 147 | * 0 - on success 148 | * 1 - on out of memory 149 | * -VXI11_NULL_WRITE_RESP - on send timeout (retry is acceptable) 150 | */ 151 | vx_EXPORT int vxi11_send_printf(VXI11_CLINK *clink, const char *format, ...); 152 | 153 | 154 | /* Function: vxi11_receive 155 | * 156 | * Receive data from an instrument. Uses VXI11_READ_TIMEOUT as the timeout. 157 | * 158 | * Parameters: 159 | * clink - a valid VXI11_CLINK pointer. 160 | * buffer - valid memory location in which to receive data. 161 | * len - number of bytes requested - buffer must be at least this large 162 | * 163 | * Returns: 164 | * Number of bytes read - on success 165 | * -VXI11_NULL_READ_RESP - on timeout 166 | * -100 - on "buffer too small" 167 | */ 168 | vx_EXPORT ssize_t vxi11_receive(VXI11_CLINK *clink, char *buffer, size_t len); 169 | 170 | 171 | /* Function: vxi11_receive_timeout 172 | * 173 | * Receive data from an instrument. Own timeout can be specified. 174 | * 175 | * Parameters: 176 | * clink - a valid VXI11_CLINK pointer. 177 | * buffer - valid memory location in which to receive data. 178 | * len - number of bytes requested - buffer must be at least this large 179 | * timeout - the number of milliseconds to wait before returning if no data is 180 | * received. 181 | * 182 | * Returns: 183 | * Number of bytes read - on success 184 | * -VXI11_NULL_READ_RESP - on timeout 185 | * -100 - on "buffer too small" 186 | */ 187 | vx_EXPORT ssize_t vxi11_receive_timeout(VXI11_CLINK *clink, char *buffer, size_t len, unsigned long timeout); 188 | 189 | 190 | /* Function: vxi11_send_data_block 191 | * 192 | * Utility function to send a command and a data block. 193 | * 194 | * Parameters: 195 | * clink - a valid VXI11_CLINK pointer. 196 | * cmd - text command to send 197 | * buffer - data to send 198 | * len - length of buffer 199 | * 200 | * Returns: 201 | * 0 - on success 202 | * 1 - on out of memory 203 | * -VXI11_NULL_WRITE_RESP - on send timeout (retry is acceptable) 204 | */ 205 | vx_EXPORT int vxi11_send_data_block(VXI11_CLINK *clink, const char *cmd, char *buffer, size_t len); 206 | 207 | 208 | /* Function: vxi11_receive_data_block 209 | * 210 | * This function reads a response in the form of a definite-length block, such 211 | * as when you ask for waveform data. The data is returned in the following 212 | * format: 213 | * #800001000<1000 bytes of data> 214 | * ||\______/ 215 | * || | 216 | * || \---- number of bytes of data 217 | * |\--------- number of digits that follow (in this case 8, with leading 0's) 218 | * \---------- always starts with # 219 | * 220 | * Parameters: 221 | * clink - a valid VXI11_CLINK pointer. 222 | * buffer - valid memory location in which to receive data. 223 | * len - number of bytes requested - buffer must be at least this large 224 | * timeout - the number of milliseconds to wait before returning if no data is 225 | * received. 226 | * 227 | * Returns: 228 | * Number of bytes read - on success 229 | * -VXI11_NULL_READ_RESP - on timeout 230 | * -100 - on "buffer too small" 231 | */ 232 | vx_EXPORT ssize_t vxi11_receive_data_block(VXI11_CLINK *clink, char *buffer, size_t len, unsigned long timeout); 233 | 234 | 235 | /* Function: vxi11_send_and_receive 236 | * 237 | * Utility function to send a command and receive a response. 238 | * 239 | * Parameters: 240 | * clink - a valid VXI11_CLINK pointer. 241 | * cmd - text command to send 242 | * buffer - valid memory location in which to receive data. 243 | * len - number of bytes requested - buffer must be at least this large 244 | * timeout - the number of milliseconds to wait before returning if no data is received. 245 | * 246 | * Returns: 247 | * 0 - on success 248 | * -1 - on write failure 249 | * -2 - on read failure 250 | */ 251 | vx_EXPORT int vxi11_send_and_receive(VXI11_CLINK *clink, const char *cmd, char *buf, size_t len, unsigned long timeout); 252 | 253 | 254 | /* Function: vxi11_obtain_long_value 255 | * 256 | * Utility function to receive a long integer. Uses VXI11_READ_TIMEOUT as the 257 | * timeout. 258 | * 259 | * Parameters: 260 | * clink - a valid VXI11_CLINK pointer. 261 | * cmd - text command to send 262 | * 263 | * Returns: 264 | * long integer value, or 0 on failure 265 | */ 266 | vx_EXPORT long vxi11_obtain_long_value(VXI11_CLINK *clink, const char *cmd); 267 | 268 | 269 | /* Function: vxi11_obtain_long_value_timeout 270 | * 271 | * Utility function to receive a long integer, with a user specified timeout. 272 | * 273 | * Parameters: 274 | * clink - a valid VXI11_CLINK pointer. 275 | * cmd - text command to send 276 | * timeout - the number of milliseconds to wait before returning if no data is 277 | * received. 278 | * 279 | * Returns: 280 | * long integer value, or 0 on failure 281 | */ 282 | vx_EXPORT long vxi11_obtain_long_value_timeout(VXI11_CLINK *clink, const char *cmd, unsigned long timeout); 283 | 284 | 285 | /* Function: vxi11_obtain_double_value_timeout 286 | * 287 | * Utility function to receive a double precision float Uses VXI11_READ_TIMEOUT 288 | * as the timeout. 289 | * 290 | * Parameters: 291 | * clink - a valid VXI11_CLINK pointer. 292 | * cmd - text command to send 293 | * 294 | * Returns: 295 | * double value, or 0.0 on failure 296 | */ 297 | vx_EXPORT double vxi11_obtain_double_value(VXI11_CLINK *clink, const char *cmd); 298 | 299 | 300 | /* Function: vxi11_obtain_double_value_timeout 301 | * 302 | * Utility function to receive a double precision float, with a user specified 303 | * timeout. 304 | * 305 | * Parameters: 306 | * clink - a valid VXI11_CLINK pointer. 307 | * cmd - text command to send 308 | * timeout - the number of milliseconds to wait before returning if no data is 309 | * received. 310 | * 311 | * Returns: 312 | * double value, or 0.0 on failure 313 | */ 314 | vx_EXPORT double vxi11_obtain_double_value_timeout(VXI11_CLINK *clink, const char *cmd, unsigned long timeout); 315 | 316 | #ifdef __cplusplus 317 | } 318 | #endif 319 | 320 | #endif 321 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | vxi11 2.0 - 2015-06-26 3 | 4 | * Change to semantic versioning (bumped major number to note this change). 5 | * Add vxi11_lib_version() 6 | * Documentation is now in vxi11_user.h 7 | * Added Python wrapper for shared library. 8 | * Symbols exported from the library are now restricted. 9 | * Bump SO version of library, this should be a stable interface now. 10 | 11 | 12 | ------------------------------------------------------------------------------ 13 | vxi11_1.11 - 2014-06-12 14 | 15 | vxi11_user code is now compiled as a shared library. 16 | 17 | Old split argument CLIENT and VXI11_LINK functions have been merged into the 18 | single VXI11_CLINK argument functions. 19 | 20 | The wrapper functions for default timeouts have been removed and replaced by 21 | default arguments on the actual functions. 22 | 23 | vxi11_open_device() now requires a VXI11_CLINK** so that the memory allocation 24 | can be handled internally. This allows the end user to only need to have 25 | vxi11_user.h rather than all of the vxi11* headers. 26 | 27 | The global array to keep track of currently connected clients has been 28 | replaced with a singly linked list and so the maximum connection limit has 29 | been removed. 30 | 31 | A CMake build script has been included - this includes support for adding the 32 | required dependencies for compiling on Cygwin. 33 | 34 | Everything is now compiled as C rather than C++ to allow use in a wider 35 | variety of software. This has meant the polymorphism and functions with 36 | default arguments have been removed. 37 | 38 | Added vxi11_send_sprintf(). 39 | 40 | ------------------------------------------------------------------------------ 41 | vxi11_1.10 - 9/09/2010 42 | 43 | Bug fix (thanks to Stephan Mahr): in vxi11_close(), remove the IP address 44 | from the global array that keeps track of them so that if the same device 45 | is opened again, then a new client is created, rather than it attempting 46 | to use the old one (which was destroyed on the previous close). 47 | 48 | ------------------------------------------------------------------------------ 49 | vxi11_1.09 - 7/06/2010 50 | 51 | Moved over to bazaar VCS (from RCS). 52 | 53 | Makefile cleanups. Fixed signed/unsigned comparisons. Use consistent (and 54 | sane) struct separator spacing in code. 55 | 56 | Fix int casting on printf statements to fix new compiler warnings/errors 57 | (thanks to Shouri Chatterjee for pointing this out). 58 | 59 | ------------------------------------------------------------------------------ 60 | vxi11_1.08 - 3/09/2009 61 | 62 | Added a sanity check for link->maxRecvSize to make sure it's >0. This gets 63 | around a bug in some versions of the Agilent Infiniium scope software. 64 | 65 | Changed the erroneous strncpy() to memcpy() in vxi11_send, as we could be 66 | sending binary data (not just strings). 67 | 68 | Changed a lot of char *'s to const char *'s in an attempt to get rid of 69 | pedantic gcc compiler warnings. 70 | 71 | ------------------------------------------------------------------------------ 72 | vxi11_1.07 - 9/10/2007 73 | 74 | Minor change to vxi11_receive_data_block(), this fn now copes with instruments 75 | that return just "#0" (for whatever reason). Suggestion by Jarek Sadowski, 76 | gratefully received. 77 | 78 | ------------------------------------------------------------------------------ 79 | vxi11_1.06 - 31/08/2007 80 | 81 | Bug fix in vxi11_receive(), to ensure that no more than "len" bytes are ever 82 | received (and so avoiding a segmentation fault). This was a bug introduced in 83 | release 1.04 whilst making some other changes to the vxi11_receive() fn. 84 | 85 | Many thanks to Rob Penny for spotting the bug and providing a patch. 86 | 87 | ------------------------------------------------------------------------------ 88 | vxi11_1.05 - 11/07/2007 89 | 90 | Added the ability to specify a "device name" when calling vxi11_open_device(). 91 | For regular VXI11-based instruments, such as scopes and AFGs, the device name 92 | is usually "hard wired" to be "inst0", and up to now this has been hard wired 93 | into the vxi11_user code. However, devices such as LAN to GPIB gateways need 94 | some way of distinguishing between different devices... they are a single 95 | client (one IP address), with multiple devices. 96 | 97 | The vxi11_user fn, vxi11_open_device(), now takes a third argument 98 | (char *device). 99 | This gets passed to the core vxi11_open_device() fn (the one that deals with 100 | separate clients and links), and the core vxi11_open_link() fn; these two 101 | core functions have also had an extra parameter added accordingly. In order 102 | to not break the API, a wrapper function is provided in the form of the 103 | original vxi11_open_device() fn, that just takes 2 arguments 104 | (char *ip, CLINK *clink), this then passes "inst0" as the device argument. 105 | Backwards-compatible wrappers for the core functions have NOT been provided. 106 | These are generally not used from userland anyway. Hopefully this won't 107 | upset anyone! 108 | 109 | vxi11_cmd, the simple test utility, has also been updated. You can now, 110 | optionally, pass the device_name as a second argument (after the ip 111 | address). The source has been renamed to vxi11_cmd.cc (from vxi11_cmd.c), as 112 | it is C++ code not C. 113 | 114 | Some minor tidying up in vxi11_user.h 115 | 116 | With thanks to Oliver Schulz for bringing LAN to GPIB gateways to my 117 | attention, for suggesting changes to the vxi11_user library to allow them to 118 | be accommodated, and for tidying some things up. 119 | 120 | ------------------------------------------------------------------------------ 121 | vxi11_1.04 - 10/07/2007 122 | 123 | Patch applied, which was kindly provided by Robert Larice. This sorts out 124 | the confusion (on my part) about the structures returned by the rpcgen 125 | generated *_1() functions... these are statically allocated temporary structs, 126 | apparently. In the words of Robert Larice: 127 | 128 | ****** 129 | Hello Dr. Sharples, 130 | 131 | I'm sending some patches for your nice gem "vxi11_1.03" 132 | 133 | In the source code there were some strange comments, concerning 134 | a commented free() around ... Manfred S. ... 135 | and some notes, suggesting you had trouble to get more than one link 136 | working. 137 | 138 | I think thats caused by some misuse of the rpcgen generated subroutines. 139 | 1) those rpcgen generated *_1 functions returned pointers to 140 | statically allocated temporary structs. 141 | those where meant to be instantly copied to the user's space, 142 | which wasn't done 143 | thus instead of 144 | Device_ReadResp *read_resp; 145 | read_resp = device_read_1(...) 146 | one should have written someting like: 147 | Device_ReadResp *read_resp; 148 | read_resp = malloc(...) 149 | memcpy(read_resp, device_read_1(...), ...) 150 | 2) but a better fix is to use the rpcgen -M Flag 151 | which allows to pass the memory space as a third argument 152 | so one can write 153 | Device_ReadResp *read_resp; 154 | read_resp = malloc(...) 155 | device_read_1(..., read_resp, ...) 156 | furthermore this is now automatically thread save 157 | 3) the rpcgen function device_read_1 158 | expects a target buffer to be passed via read_resp 159 | which was not done. 160 | 4) the return value of vxi11_receive() was computed incorrectly 161 | 5) minor, Makefile typo's 162 | CFLAGS versus 163 | CLFAGS 164 | 165 | ****** 166 | 167 | Robert didn't have more than one device to try the patch with, but I've just 168 | tried it and everything seems fine. So I've removed all references to the 169 | VXI11_ENABLE_MULTIPLE_CLIENTS global variable, and removed the call to 170 | vxi11_open_link() from the vxi11_send() fn. There has been an associated 171 | tidying of functions, and removal of some comments. 172 | 173 | Thanks once again to Robert Larice for the patch and the explanation! 174 | 175 | ------------------------------------------------------------------------------ 176 | vxi11_1.03 - 29/01/2007 177 | 178 | Some bug-fixes (thanks to Manfred S.), and extra awareness of the 179 | possibility that instruments could time out after receiving a query WITHOUT 180 | causing an error condition. In some cases (prior to these changes) this 181 | could have resulted in a segmentation fault. 182 | 183 | Specifically: 184 | 185 | (1) removed call to ANSI free() fn in vxi11_receive, which according to 186 | Manfred S. "is not necessary and wrong (crashes)". 187 | 188 | (2) added extra check in vxi11_receive() to see if read_resp==NULL. 189 | read_resp can apparently be NULL if (eg) you send an instrument a 190 | query, but the instrument is so busy with something else for so long 191 | that it forgets the original query. So this extra check is for that 192 | situation, and vxi11_receive returns -VXI11_NULL_READ_RESP to the 193 | calling function. 194 | 195 | (3) vxi11_send_and_receive() is now aware of the possibility of being 196 | returned -VXI11_NULL_READ_RESP. If so, it re-sends the query, until 197 | either getting a "regular" read error (read_resp->error!=0) or a 198 | successful read. 199 | 200 | (4) Similar to (2)... added extra check in vxi11_send() to see if 201 | write_resp==NULL. If so, return -VXI11_NULL_WRITE_RESP. As with (3), 202 | send_and_receive() is now aware of this possibility. 203 | 204 | ------------------------------------------------------------------------------ 205 | vxi11_1.02 - 25/08/2006 206 | 207 | Important changes to the core vxi11_send() function, which should be 208 | invisible to the user. 209 | 210 | For those interested, the function now takes note of the value of 211 | link->maxRecvSize, which is the maximum number of bytes that the vxi11 212 | intrument you're talking to can receive in one go. For many instruments 213 | this may be a few kB, which isn't a problem for sending short commands; 214 | however, sending large chunks of data (for example sending waveforms 215 | to instruments) may exceed this maxRecvSize. The core vxi11_send() function 216 | has been re-written to ensure that only a maximum of [maxRecvSize] bytes are 217 | written in one go... the function sits in a loop until all the message/ 218 | data is written. 219 | 220 | Also tidied up some of the return values (specifically with regard to 221 | vxi11_send() and vxi11_send_data_block() ). 222 | 223 | ------------------------------------------------------------------------------ 224 | vxi11_1.01 - 06/07/2006 225 | 226 | Fair few changes since v1.00, all in vxi11_user.c and vxi11_user.h 227 | 228 | Found I was having problems talking to multiple links on the same 229 | client, if I created a different client for each one. So introduced 230 | a few global variables to keep track of all the ip addresses of 231 | clients that the library is asked to create, and only creating new 232 | clients if the ip address is different. This puts a limit of how 233 | many unique ip addresses (clients) a single process can connect to. 234 | Set this value at 256 (should hopefully be enough!). 235 | 236 | Next I found that talking to different clients on different ip 237 | addresses didn't work. It turns out that create_link_1() creates 238 | a static structure. This this link is associated with a given 239 | client (and hence a given IP address), then the only way I could 240 | think of making things work was to add a call to an 241 | vxi11_open_link() function before each send command (no idea what 242 | this adds to overheads and it's very messy!) - at least I was 243 | able to get this to only happen when we are using more than one 244 | client/ip address. 245 | 246 | Also, while I was at it, I re-ordered the functions a little - 247 | starts with core user functions, extra user functions, then core 248 | library functions at the end. Added a few more comments. Tidied 249 | up. Left some debugging info in, but commented out. 250 | 251 | ------------------------------------------------------------------------------ 252 | vxi11_1.00 - 23/06/2006 253 | 254 | Initial release. 255 | 256 | ------------------------------------------------------------------------------ 257 | 258 | -------------------------------------------------------------------------------- /library/vxi11.x: -------------------------------------------------------------------------------- 1 | /* This file, vxi11.x, is the amalgamation of vxi11core.rpcl and vxi11intr.rpcl 2 | * which are part of the asynDriver (R4-5) EPICS module, which, at time of 3 | * writing, is available from: 4 | * http://www.aps.anl.gov/epics/modules/soft/asyn/index.html 5 | * More general information about EPICS is available from: 6 | * http://www.aps.anl.gov/epics/ 7 | * This code is open source, and is covered under the copyright notice and 8 | * software license agreement shown below, and also at: 9 | * http://www.aps.anl.gov/epics/license/open.php 10 | * 11 | * In order to comply with section 4.3 of the software license agreement, here 12 | * is a PROMINENT NOTICE OF CHNAGES TO THE SOFTWARE 13 | * =========================================== 14 | * (1) This file, vxi11.x, is the concatenation of the files vxi11core.rpcl and 15 | * vxi11intr.rpcl 16 | * (2) Tab spacing has been tidied up 17 | * 18 | * It is intended as a lightweight base for the vxi11 rpc protocol. If you 19 | * run rpcgen on this file, it will generate C files and headers, from which 20 | * it is relatively simple to write C programs to communicate with a range 21 | * of ethernet-enabled instruments, such as oscilloscopes and function 22 | * generated by manufacturers such as Agilent and Tektronix (amongst many 23 | * others). 24 | * 25 | * For what it's worth, this concatenation was done by Steve Sharples at 26 | * the University of Nottingham, UK, on 1 June 2006. 27 | * 28 | * Copyright notice and software license agreement follow, then the 29 | * original comments from vxi11core.rpcl etc. 30 | * 31 | ****************************************************************************** 32 | * Copyright © 2006 . All 33 | * rights reserved. 34 | ****************************************************************************** 35 | * 36 | ****************************************************************************** 37 | * vxi11.x is distributed subject to the following license conditions: 38 | * SOFTWARE LICENSE AGREEMENT 39 | * Software: vxi11.x 40 | * 41 | * 1. The "Software", below, refers to vxi11.x (in either source code, or 42 | * binary form and accompanying documentation). Each licensee is addressed 43 | * as "you" or "Licensee." 44 | * 45 | * 2. The copyright holders shown above and their third-party licensors hereby 46 | * grant Licensee a royalty-free nonexclusive license, subject to the 47 | * limitations stated herein and U.S. Government license rights. 48 | * 49 | * 3. You may modify and make a copy or copies of the Software for use within 50 | * your organization, if you meet the following conditions: 51 | * 1. Copies in source code must include the copyright notice and this 52 | * Software License Agreement. 53 | * 2. Copies in binary form must include the copyright notice and this 54 | * Software License Agreement in the documentation and/or other 55 | * materials provided with the copy. 56 | * 57 | * 4. You may modify a copy or copies of the Software or any portion of it, 58 | * thus forming a work based on the Software, and distribute copies of such 59 | * work outside your organization, if you meet all of the following 60 | * conditions: 61 | * 1. Copies in source code must include the copyright notice and this 62 | * Software License Agreement; 63 | * 2. Copies in binary form must include the copyright notice and this 64 | * Software License Agreement in the documentation and/or other 65 | * materials provided with the copy; 66 | * 3. Modified copies and works based on the Software must carry 67 | * prominent notices stating that you changed specified portions of 68 | * the Software. 69 | * 70 | * 5. Portions of the Software resulted from work developed under a U.S. 71 | * Government contract and are subject to the following license: the 72 | * Government is granted for itself and others acting on its behalf a 73 | * paid-up, nonexclusive, irrevocable worldwide license in this computer 74 | * software to reproduce, prepare derivative works, and perform publicly 75 | * and display publicly. 76 | * 77 | * 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF 78 | * ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE UNITED 79 | * STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR EMPLOYEES: (1) 80 | * DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 81 | * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 82 | * PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY 83 | * OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF THE 84 | * SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE 85 | * PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION 86 | * UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. 87 | * 88 | * 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR 89 | * THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF 90 | * ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, 91 | * CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, 92 | * INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY 93 | * REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF 94 | * CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, 95 | * EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE POSSIBILITY OF SUCH 96 | * LOSS OR DAMAGES. 97 | ****************************************************************************** 98 | */ 99 | 100 | /****************************************************************************** 101 | * 102 | * vxi11core.rpcl 103 | * 104 | * This file is best viewed with a tabwidth of 4 105 | * 106 | ****************************************************************************** 107 | * 108 | * TODO: 109 | * 110 | ****************************************************************************** 111 | * 112 | * Original Author: someone from VXIbus Consortium 113 | * Current Author: Benjamin Franksen 114 | * Date: 03-06-97 115 | * 116 | * RPCL description of the core- and abort-channel of the TCP/IP Instrument 117 | * Protocol Specification. 118 | * 119 | * 120 | * Modification Log: 121 | * ----------------- 122 | * .00 03-06-97 bfr created this file 123 | * 124 | ****************************************************************************** 125 | * 126 | * Notes: 127 | * 128 | * This stuff is literally from 129 | * 130 | * VXI-11, Ref 1.0 : TCP/IP Instrument Protocol Specification 131 | * 132 | */ 133 | 134 | typedef long Device_Link; 135 | 136 | enum Device_AddrFamily 137 | { 138 | DEVICE_TCP, 139 | DEVICE_UDP 140 | }; 141 | 142 | typedef long Device_Flags; 143 | 144 | typedef long Device_ErrorCode; 145 | 146 | struct Device_Error 147 | { 148 | Device_ErrorCode error; 149 | }; 150 | 151 | struct Create_LinkParms 152 | { 153 | long clientId; /* implementation specific value */ 154 | bool lockDevice; /* attempt to lock the device */ 155 | unsigned long lock_timeout; /* time to wait for lock */ 156 | string device<>; /* name of device */ 157 | }; 158 | struct Create_LinkResp 159 | { 160 | Device_ErrorCode error; 161 | Device_Link lid; 162 | unsigned short abortPort; /* for the abort RPC */ 163 | unsigned long maxRecvSize; /* max # of bytes accepted on write */ 164 | }; 165 | struct Device_WriteParms 166 | { 167 | Device_Link lid; /* link id from create_link */ 168 | unsigned long io_timeout; /* time to wait for I/O */ 169 | unsigned long lock_timeout; /* time to wait for lock */ 170 | Device_Flags flags; /* flags with options */ 171 | opaque data<>; /* the data length and the data itself */ 172 | }; 173 | struct Device_WriteResp 174 | { 175 | Device_ErrorCode error; 176 | unsigned long size; /* # of bytes written */ 177 | }; 178 | struct Device_ReadParms 179 | { 180 | Device_Link lid; /* link id from create_link */ 181 | unsigned long requestSize; /* # of bytes requested */ 182 | unsigned long io_timeout; /* time to wait for I/O */ 183 | unsigned long lock_timeout; /* time to wait for lock */ 184 | Device_Flags flags; /* flags with options */ 185 | char termChar; /* valid if flags & termchrset */ 186 | }; 187 | struct Device_ReadResp 188 | { 189 | Device_ErrorCode error; 190 | long reason; /* why read completed */ 191 | opaque data<>; /* the data length and the data itself */ 192 | }; 193 | struct Device_ReadStbResp 194 | { 195 | Device_ErrorCode error; 196 | unsigned char stb; /* the returned status byte */ 197 | }; 198 | struct Device_GenericParms 199 | { 200 | Device_Link lid; /* link id from create_link */ 201 | Device_Flags flags; /* flags with options */ 202 | unsigned long lock_timeout; /* time to wait for lock */ 203 | unsigned long io_timeout; /* time to wait for I/O */ 204 | }; 205 | struct Device_RemoteFunc 206 | { 207 | unsigned long hostAddr; /* host servicing interrupt */ 208 | unsigned long hostPort; /* valid port # on client */ 209 | unsigned long progNum; /* DEVICE_INTR */ 210 | unsigned long progVers; /* DEVICE_INTR_VERSION */ 211 | Device_AddrFamily progFamily; /* DEVICE_UDP | DEVICE_TCP */ 212 | }; 213 | struct Device_EnableSrqParms 214 | { 215 | Device_Link lid; /* link id from create_link */ 216 | bool enable; /* enable or disable intr's */ 217 | opaque handle<40>; /* host specific data */ 218 | }; 219 | struct Device_LockParms 220 | { 221 | Device_Link lid; /* link id from create_link */ 222 | Device_Flags flags; /* contains the waitlock flag */ 223 | unsigned long lock_timeout; /* time to wait for lock */ 224 | }; 225 | struct Device_DocmdParms 226 | { 227 | Device_Link lid; /* link id from create_link */ 228 | Device_Flags flags; /* flags with options */ 229 | unsigned long io_timeout; /* time to wait for I/O */ 230 | unsigned long lock_timeout; /* time to wait for lock */ 231 | long cmd; /* which command to execute */ 232 | bool network_order; /* client's byte order */ 233 | long datasize; /* size of individual data elements */ 234 | opaque data_in<>; /* docmd data parameters */ 235 | }; 236 | struct Device_DocmdResp 237 | { 238 | Device_ErrorCode error; 239 | opaque data_out<>; /* returned data parameters */ 240 | }; 241 | 242 | program DEVICE_ASYNC 243 | { 244 | version DEVICE_ASYNC_VERSION 245 | { 246 | Device_Error device_abort (Device_Link) = 1; 247 | } = 1; 248 | } = 0x0607B0; 249 | 250 | program DEVICE_CORE 251 | { 252 | version DEVICE_CORE_VERSION 253 | { 254 | Create_LinkResp create_link (Create_LinkParms) = 10; 255 | Device_WriteResp device_write (Device_WriteParms) = 11; 256 | Device_ReadResp device_read (Device_ReadParms) = 12; 257 | Device_ReadStbResp device_readstb (Device_GenericParms) = 13; 258 | Device_Error device_trigger (Device_GenericParms) = 14; 259 | Device_Error device_clear (Device_GenericParms) = 15; 260 | Device_Error device_remote (Device_GenericParms) = 16; 261 | Device_Error device_local (Device_GenericParms) = 17; 262 | Device_Error device_lock (Device_LockParms) = 18; 263 | Device_Error device_unlock (Device_Link) = 19; 264 | Device_Error device_enable_srq (Device_EnableSrqParms) = 20; 265 | Device_DocmdResp device_docmd (Device_DocmdParms) = 22; 266 | Device_Error destroy_link (Device_Link) = 23; 267 | Device_Error create_intr_chan (Device_RemoteFunc) = 25; 268 | Device_Error destroy_intr_chan (void) = 26; 269 | } = 1; 270 | } = 0x0607AF; 271 | 272 | /****************************************************************************** 273 | * 274 | * vxi11intr.rpcl 275 | * 276 | * This file is best viewed with a tabwidth of 4 277 | * 278 | ****************************************************************************** 279 | * 280 | * TODO: 281 | * 282 | ****************************************************************************** 283 | * 284 | * Original Author: someone from VXIbus Consortium 285 | * Current Author: Benjamin Franksen 286 | * Date: 03-06-97 287 | * 288 | * RPCL description of the intr-channel of the TCP/IP Instrument Protocol 289 | * Specification. 290 | * 291 | * 292 | * Modification Log: 293 | * ----------------- 294 | * .00 03-06-97 bfr created this file 295 | * 296 | ****************************************************************************** 297 | * 298 | * Notes: 299 | * 300 | * This stuff is literally from 301 | * 302 | * "VXI-11, Ref 1.0 : TCP/IP Instrument Protocol Specification" 303 | * 304 | */ 305 | 306 | struct Device_SrqParms 307 | { 308 | opaque handle<>; 309 | }; 310 | 311 | program DEVICE_INTR 312 | { 313 | version DEVICE_INTR_VERSION 314 | { 315 | void device_intr_srq (Device_SrqParms) = 30; 316 | } = 1; 317 | } = 0x0607B1; 318 | -------------------------------------------------------------------------------- /GNU_General_Public_License.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /library/vxi11_user.c: -------------------------------------------------------------------------------- 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 26 | #include 27 | #include 28 | #include 29 | 30 | #include "vxi11_user.h" 31 | 32 | #ifdef WIN32 33 | # include 34 | #else 35 | # include 36 | # include "vxi11.h" 37 | #endif 38 | 39 | #define VXI11_CLIENT CLIENT 40 | #define VXI11_LINK Create_LinkResp 41 | 42 | struct _VXI11_CLINK { 43 | #ifdef WIN32 44 | ViSession rm; 45 | ViSession session; 46 | #else 47 | VXI11_CLIENT *client; 48 | VXI11_LINK *link; 49 | #endif 50 | }; 51 | 52 | /***************************************************************************** 53 | * GENERAL NOTES 54 | ***************************************************************************** 55 | 56 | * Global variables. Keep track of multiple links per client. We need this 57 | * because: 58 | * - we'd like the library to be able to cope with multiple links to a given 59 | * client AND multiple links to multiple clients 60 | * - we'd like to just refer to a client/link ("clink") as a single 61 | * entity from user land, we don't want to worry about different 62 | * initialisation procedures, depending on whether it's an instrument 63 | * with the same address or not 64 | */ 65 | 66 | struct _vxi11_client_t { 67 | struct _vxi11_client_t *next; 68 | char address[20]; 69 | #ifndef WIN32 70 | CLIENT *client_address; 71 | #endif 72 | int link_count; 73 | }; 74 | 75 | static struct _vxi11_client_t *VXI11_CLIENTS = NULL; 76 | 77 | /* Internal function declarations. */ 78 | static int _vxi11_open_link(VXI11_CLINK * clink, const char *address, 79 | char *device); 80 | static int _vxi11_close_link(VXI11_CLINK * clink, const char *address); 81 | 82 | 83 | int vxi11_lib_version(int *major, int *minor, int *revision) 84 | { 85 | if(major) *major = LIBVXI11_MAJOR; 86 | if(minor) *minor = LIBVXI11_MINOR; 87 | if(revision) *revision = LIBVXI11_REVISION; 88 | return LIBVXI11_VERSION_NUMBER; 89 | } 90 | 91 | 92 | /***************************************************************************** 93 | * KEY USER FUNCTIONS - USE THESE FROM YOUR PROGRAMS OR INSTRUMENT LIBRARIES * 94 | *****************************************************************************/ 95 | 96 | /* OPEN FUNCTIONS * 97 | * ============== */ 98 | 99 | /* Use this function from user land to open a device and create a link. Can be 100 | * used multiple times for the same device (the library will keep track).*/ 101 | int vxi11_open_device(VXI11_CLINK **clink, const char *address, char *device) 102 | { 103 | #ifdef WIN32 104 | ViStatus status; 105 | char buf[256]; 106 | #else 107 | int ret; 108 | struct _vxi11_client_t *tail, *client = NULL; 109 | #endif 110 | char default_device[6] = "inst0"; 111 | char *use_device; 112 | 113 | if(device){ 114 | use_device = device; 115 | }else{ 116 | use_device = default_device; 117 | } 118 | 119 | *clink = (VXI11_CLINK *) calloc(1, sizeof(VXI11_CLINK)); 120 | if (!(*clink)) { 121 | return 1; 122 | } 123 | 124 | #ifdef WIN32 125 | status = viOpenDefaultRM(&clink->rm); 126 | if (status != VI_SUCCESS) { 127 | viStatusDesc(NULL, status, buf); 128 | printf("%s\n", buf); 129 | free(*clink); 130 | *clink = NULL; 131 | return 1; 132 | } 133 | viOpen(clink->rm, (char *)address, VI_NULL, VI_NULL, &clink->session); 134 | if (status != VI_SUCCESS) { 135 | viStatusDesc(clink->rm, status, buf); 136 | printf("%s\n", buf); 137 | free(*clink); 138 | *clink = NULL; 139 | return 1; 140 | } 141 | #else 142 | /* Have a look to see if we've already initialised an instrument with 143 | * this address */ 144 | tail = VXI11_CLIENTS; 145 | while (tail) { 146 | if (strcmp(address, tail->address) == 0) { 147 | client = tail; 148 | break; 149 | } 150 | tail = tail->next; 151 | } 152 | 153 | /* Couldn't find a match, must be a new address */ 154 | if (!client) { 155 | /* Create a new client, keep a note of where the client pointer 156 | * is, for this address. Because it's a new client, this 157 | * must be link number 1. Keep track of how many devices we've 158 | * opened so we don't run out of storage space. */ 159 | client = (struct _vxi11_client_t *)calloc(1, sizeof(struct _vxi11_client_t)); 160 | if (!client) { 161 | free(*clink); 162 | *clink = NULL; 163 | return 1; 164 | } 165 | 166 | (*clink)->client = 167 | clnt_create(address, DEVICE_CORE, DEVICE_CORE_VERSION, 168 | "tcp"); 169 | 170 | if ((*clink)->client == NULL) { 171 | clnt_pcreateerror(address); 172 | free(client); 173 | free(*clink); 174 | *clink = NULL; 175 | return 1; 176 | } 177 | ret = _vxi11_open_link(*clink, address, use_device); 178 | if (ret != 0) { 179 | clnt_destroy((*clink)->client); 180 | free(client); 181 | free(*clink); 182 | *clink = NULL; 183 | return 1; 184 | } 185 | 186 | strncpy(client->address, address, 20); 187 | client->client_address = (*clink)->client; 188 | client->link_count = 1; 189 | client->next = VXI11_CLIENTS; 190 | VXI11_CLIENTS = client; 191 | } else { 192 | /* Copy the client pointer address. Just establish a new link 193 | * not a new client). Add one to the link count */ 194 | (*clink)->client = client->client_address; 195 | ret = _vxi11_open_link((*clink), address, use_device); 196 | client->link_count++; 197 | } 198 | #endif 199 | return 0; 200 | } 201 | 202 | /* CLOSE FUNCTION * 203 | * ============== */ 204 | 205 | /* Use this function from user land to close a device and/or sever a link. Can 206 | * be used multiple times for the same device (the library will keep track).*/ 207 | int vxi11_close_device(VXI11_CLINK * clink, const char *address) 208 | { 209 | int ret = 0; 210 | #ifdef WIN32 211 | viClose(clink->session); 212 | viClose(clink->rm); 213 | #else 214 | struct _vxi11_client_t *tail, *last = NULL, *client = NULL; 215 | 216 | /* Which instrument are we referring to? */ 217 | tail = VXI11_CLIENTS; 218 | while (tail) { 219 | if (strncmp(address, tail->address, 20) == 0) { 220 | client = tail; 221 | break; 222 | } 223 | last = tail; 224 | tail = tail->next; 225 | } 226 | 227 | /* Something's up if we can't find the address! */ 228 | if (!client) { 229 | printf 230 | ("vxi11_close_device: error: I have no record of you ever opening device\n"); 231 | printf(" with address %s\n", address); 232 | ret = -4; 233 | } else { /* Found the address, there's more than one link to that instrument, 234 | * so keep track and just close the link */ 235 | if (client->link_count > 1) { 236 | ret = _vxi11_close_link(clink, address); 237 | client->link_count--; 238 | } 239 | /* Found the address, it's the last link, so close the device (link 240 | * AND client) */ 241 | else { 242 | ret = _vxi11_close_link(clink, address); 243 | clnt_destroy(clink->client); 244 | 245 | if (last) { 246 | last->next = client->next; 247 | } else { 248 | VXI11_CLIENTS = client->next; 249 | } 250 | } 251 | } 252 | #endif 253 | free(clink); 254 | return ret; 255 | } 256 | 257 | /* SEND FUNCTIONS * 258 | * ============== */ 259 | 260 | int vxi11_send_printf(VXI11_CLINK * clink, const char *format, ...) 261 | { 262 | int len; 263 | char *s; 264 | int rc; 265 | va_list va; 266 | 267 | len = strlen(format) + 500; 268 | 269 | s = malloc(len*sizeof(char)); 270 | if(!s){ 271 | return -1; 272 | } 273 | 274 | va_start(va, format); 275 | rc = vsnprintf(s, len, format, va); 276 | va_end(va); 277 | if(rc < 0){ 278 | free(s); 279 | return rc; 280 | } 281 | s[len-1] = '\0'; /* Ensure string is null terminated. */ 282 | 283 | return vxi11_send(clink, s, strlen(s)); 284 | } 285 | 286 | int vxi11_send(VXI11_CLINK * clink, const char *cmd, size_t len) 287 | { 288 | #ifdef WIN32 289 | ViStatus status; 290 | char buf[256]; 291 | unsigned char *send_cmd; 292 | #else 293 | Device_WriteParms write_parms; 294 | char *send_cmd; 295 | #endif 296 | size_t bytes_left = len; 297 | ssize_t write_count; 298 | 299 | #ifdef WIN32 300 | send_cmd = (unsigned char *)malloc(len); 301 | if (!send_cmd) { 302 | return 1; 303 | } 304 | memcpy(send_cmd, cmd, len); 305 | 306 | while (bytes_left > 0) { 307 | status = 308 | viWrite(clink->session, send_cmd + (len - bytes_left), 309 | bytes_left, &write_count); 310 | if (status == VI_SUCCESS) { 311 | bytes_left -= write_count; 312 | } else { 313 | free(send_cmd); 314 | viStatusDesc(clink->session, status, buf); 315 | printf("%s\n", buf); 316 | return status; 317 | } 318 | } 319 | #else 320 | send_cmd = (char *)malloc(len); 321 | if (!send_cmd) { 322 | return 1; 323 | } 324 | memcpy(send_cmd, cmd, len); 325 | 326 | write_parms.lid = clink->link->lid; 327 | write_parms.io_timeout = VXI11_DEFAULT_TIMEOUT; 328 | write_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT; 329 | 330 | /* We can only write (link->maxRecvSize) bytes at a time, so we sit in a loop, 331 | * writing a chunk at a time, until we're done. */ 332 | 333 | do { 334 | Device_WriteResp write_resp; 335 | memset(&write_resp, 0, sizeof(write_resp)); 336 | 337 | if (bytes_left <= clink->link->maxRecvSize) { 338 | write_parms.flags = 8; 339 | write_parms.data.data_len = bytes_left; 340 | } else { 341 | write_parms.flags = 0; 342 | /* We need to check that maxRecvSize is a sane value (ie >0). Believe it 343 | * or not, on some versions of Agilent Infiniium scope firmware the scope 344 | * returned "0", which breaks Rule B.6.3 of the VXI-11 protocol. Nevertheless 345 | * we need to catch this, otherwise the program just hangs. */ 346 | if (clink->link->maxRecvSize > 0) { 347 | write_parms.data.data_len = 348 | clink->link->maxRecvSize; 349 | } else { 350 | write_parms.data.data_len = 4096; /* pretty much anything should be able to cope with 4kB */ 351 | } 352 | } 353 | write_parms.data.data_val = send_cmd + (len - bytes_left); 354 | 355 | if (device_write_1(&write_parms, &write_resp, clink->client) != 356 | RPC_SUCCESS) { 357 | free(send_cmd); 358 | return -VXI11_NULL_WRITE_RESP; /* The instrument did not acknowledge the write, just completely 359 | dropped it. There was no vxi11 comms error as such, the 360 | instrument is just being rude. Usually occurs when the instrument 361 | is busy. If we don't check this first, then the following 362 | line causes a seg fault */ 363 | } 364 | if (write_resp.error != 0) { 365 | printf("vxi11_user: write error: %d\n", 366 | (int)write_resp.error); 367 | free(send_cmd); 368 | return -(write_resp.error); 369 | } 370 | bytes_left -= write_resp.size; 371 | } while (bytes_left > 0); 372 | #endif 373 | free(send_cmd); 374 | 375 | return 0; 376 | } 377 | 378 | /* RECEIVE FUNCTIONS * 379 | * ================= */ 380 | 381 | #define RCV_END_BIT 0x04 // An end indicator has been read 382 | #define RCV_CHR_BIT 0x02 // A termchr is set in flags and a character which matches termChar is transferred 383 | #define RCV_REQCNT_BIT 0x01 // requestSize bytes have been transferred. This includes a request size of zero. 384 | 385 | ssize_t vxi11_receive(VXI11_CLINK * clink, char *buffer, size_t len) 386 | { 387 | return vxi11_receive_timeout(clink, buffer, len, VXI11_READ_TIMEOUT); 388 | } 389 | 390 | ssize_t vxi11_receive_timeout(VXI11_CLINK * clink, char *buffer, size_t len, 391 | unsigned long timeout) 392 | { 393 | size_t curr_pos = 0; 394 | #ifdef WIN32 395 | viRead(clink->session, (unsigned char *)buffer, len, &curr_pos); 396 | #else 397 | Device_ReadParms read_parms; 398 | Device_ReadResp read_resp; 399 | 400 | read_parms.lid = clink->link->lid; 401 | read_parms.requestSize = len; 402 | read_parms.io_timeout = timeout; /* in ms */ 403 | read_parms.lock_timeout = timeout; /* in ms */ 404 | read_parms.flags = 0; 405 | read_parms.termChar = 0; 406 | 407 | do { 408 | memset(&read_resp, 0, sizeof(read_resp)); 409 | 410 | read_resp.data.data_val = buffer + curr_pos; 411 | read_parms.requestSize = len - curr_pos; // Never request more total data than originally specified in len 412 | 413 | if (device_read_1(&read_parms, &read_resp, clink->client) != RPC_SUCCESS) { 414 | return -VXI11_NULL_READ_RESP; /* there is nothing to read. Usually occurs after sending a query 415 | which times out on the instrument. If we don't check this first, 416 | then the following line causes a seg fault */ 417 | } 418 | if (read_resp.error != 0) { 419 | /* Read failed for reason specified in error code. 420 | * (From published VXI-11 protocol, section B.5.2) 421 | * 0 no error 422 | * 1 syntax error 423 | * 3 device not accessible 424 | * 4 invalid link identifier 425 | * 5 parameter error 426 | * 6 channel not established 427 | * 8 operation not supported 428 | * 9 out of resources 429 | * 11 device locked by another link 430 | * 12 no lock held by this link 431 | * 15 I/O timeout 432 | * 17 I/O error 433 | * 21 invalid address 434 | * 23 abort 435 | * 29 channel already established 436 | */ 437 | 438 | printf("vxi11_user: read error: %d\n", (int)read_resp.error); 439 | return -(read_resp.error); 440 | } 441 | 442 | if ((curr_pos + read_resp.data.data_len) <= len) { 443 | curr_pos += read_resp.data.data_len; 444 | } 445 | if ((read_resp.reason & RCV_END_BIT) || (read_resp.reason & RCV_CHR_BIT)) { 446 | break; 447 | } else if (curr_pos == len) { 448 | printf("xvi11_user: read error: buffer too small. Read %d bytes without hitting terminator.\n", 449 | (int)curr_pos); 450 | return -100; 451 | } 452 | } while (1); 453 | #endif 454 | return (curr_pos); /*actual number of bytes received */ 455 | } 456 | 457 | /***************************************************************************** 458 | * USEFUL ADDITIONAL HIGHER LEVER USER FUNCTIONS - USE THESE FROM YOUR * 459 | * PROGRAMS OR INSTRUMENT LIBRARIES * 460 | *****************************************************************************/ 461 | 462 | /* SEND FIXED LENGTH DATA BLOCK FUNCTION * 463 | * ===================================== */ 464 | int vxi11_send_data_block(VXI11_CLINK * clink, const char *cmd, char *buffer, 465 | size_t len) 466 | { 467 | char *out_buffer; 468 | size_t cmd_len = strlen(cmd); 469 | int ret; 470 | 471 | out_buffer = (char *)malloc(cmd_len + 10 + len); 472 | if (!out_buffer) { 473 | return 1; 474 | } 475 | sprintf(out_buffer, "%s#8%08lu", cmd, len); 476 | memcpy(out_buffer + cmd_len + 10, buffer, len); 477 | ret = vxi11_send(clink, out_buffer, cmd_len + 10 + len); 478 | free(out_buffer); 479 | return ret; 480 | } 481 | 482 | /* RECEIVE FIXED LENGTH DATA BLOCK FUNCTION * 483 | * ======================================== */ 484 | 485 | /* This function reads a response in the form of a definite-length block, such 486 | * as when you ask for waveform data. The data is returned in the following 487 | * format: 488 | * #800001000<1000 bytes of data> 489 | * ||\______/ 490 | * || | 491 | * || \---- number of bytes of data 492 | * |\--------- number of digits that follow (in this case 8, with leading 0's) 493 | * \---------- always starts with # 494 | */ 495 | ssize_t vxi11_receive_data_block(VXI11_CLINK * clink, char *buffer, 496 | size_t len, unsigned long timeout) 497 | { 498 | /* I'm not sure what the maximum length of this header is, I'll assume it's 499 | * 11 (#9 + 9 digits) */ 500 | size_t necessary_buffer_size; 501 | char *in_buffer; 502 | int ret; 503 | int ndigits; 504 | size_t returned_bytes; 505 | int l; 506 | char scan_cmd[20]; 507 | necessary_buffer_size = len + 12; 508 | in_buffer = (char *)malloc(necessary_buffer_size); 509 | if (!in_buffer) { 510 | return -1; 511 | } 512 | ret = vxi11_receive_timeout(clink, in_buffer, necessary_buffer_size, timeout); 513 | if (ret < 0) { 514 | return ret; 515 | } 516 | if (in_buffer[0] != '#') { 517 | printf("vxi11_user: data block error: data block does not begin with '#'\n"); 518 | printf("First 20 characters received were: '"); 519 | for (l = 0; l < 20; l++) { 520 | printf("%c", in_buffer[l]); 521 | } 522 | printf("'\n"); 523 | return -3; 524 | } 525 | 526 | /* first find out how many digits */ 527 | sscanf(in_buffer, "#%1d", &ndigits); 528 | /* some instruments, if there is a problem acquiring the data, return only "#0" */ 529 | if (ndigits > 0) { 530 | /* now that we know, we can convert the next bytes into an unsigned long */ 531 | sprintf(scan_cmd, "#%%1d%%%dlu", ndigits); 532 | sscanf(in_buffer, scan_cmd, &ndigits, &returned_bytes); 533 | memcpy(buffer, in_buffer + (ndigits + 2), returned_bytes); 534 | free(in_buffer); 535 | return (ssize_t )returned_bytes; 536 | } else { 537 | return 0; 538 | } 539 | } 540 | 541 | /* SEND AND RECEIVE FUNCTION * 542 | * ========================= */ 543 | 544 | /* This is mainly a useful function for the overloaded vxi11_obtain_value() 545 | * fn's, but is also handy and useful for user and library use */ 546 | int vxi11_send_and_receive(VXI11_CLINK * clink, const char *cmd, char *buf, 547 | size_t len, unsigned long timeout) 548 | { 549 | int ret; 550 | ssize_t bytes_returned; 551 | do { 552 | ret = vxi11_send(clink, cmd, strlen(cmd)); 553 | if (ret != 0) { 554 | if (ret != -VXI11_NULL_WRITE_RESP) { 555 | printf 556 | ("Error: vxi11_send_and_receive: could not send cmd.\n"); 557 | printf 558 | (" The function vxi11_send returned %d. ", 559 | ret); 560 | return -1; 561 | } else { 562 | printf("(Info: VXI11_NULL_WRITE_RESP in vxi11_send_and_receive, resending query)\n"); 563 | } 564 | } 565 | 566 | bytes_returned = vxi11_receive_timeout(clink, buf, len, timeout); 567 | if (bytes_returned <= 0) { 568 | if (bytes_returned > -VXI11_NULL_READ_RESP) { 569 | printf 570 | ("Error: vxi11_send_and_receive: problem reading reply.\n"); 571 | printf 572 | (" The function vxi11_receive returned %ld. ", 573 | bytes_returned); 574 | return -2; 575 | } else { 576 | printf("(Info: VXI11_NULL_READ_RESP in vxi11_send_and_receive, resending query)\n"); 577 | } 578 | } 579 | } while (bytes_returned == -VXI11_NULL_READ_RESP || ret == -VXI11_NULL_WRITE_RESP); 580 | return 0; 581 | } 582 | 583 | /* FUNCTIONS TO RETURN A LONG INTEGER VALUE SENT AS RESPONSE TO A QUERY * 584 | * ==================================================================== */ 585 | long vxi11_obtain_long_value(VXI11_CLINK * clink, const char *cmd) 586 | { 587 | return vxi11_obtain_long_value_timeout(clink, cmd, VXI11_READ_TIMEOUT); 588 | } 589 | 590 | long vxi11_obtain_long_value_timeout(VXI11_CLINK * clink, const char *cmd, 591 | unsigned long timeout) 592 | { 593 | char buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */ 594 | memset(buf, 0, 50); 595 | if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) { 596 | printf("Returning 0\n"); 597 | return 0; 598 | } 599 | return strtol(buf, (char **)NULL, 10); 600 | } 601 | 602 | /* FUNCTIONS TO RETURN A DOUBLE FLOAT VALUE SENT AS RESPONSE TO A QUERY * 603 | * ==================================================================== */ 604 | double vxi11_obtain_double_value(VXI11_CLINK * clink, const char *cmd) 605 | { 606 | return vxi11_obtain_double_value_timeout(clink, cmd, VXI11_READ_TIMEOUT); 607 | } 608 | 609 | double vxi11_obtain_double_value_timeout(VXI11_CLINK * clink, const char *cmd, 610 | unsigned long timeout) 611 | { 612 | char buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */ 613 | double val; 614 | memset(buf, 0, 50); 615 | if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) { 616 | printf("Returning 0.0\n"); 617 | return 0.0; 618 | } 619 | val = strtod(buf, (char **)NULL); 620 | return val; 621 | } 622 | 623 | /***************************************************************************** 624 | * CORE FUNCTIONS - YOU SHOULDN'T NEED TO USE THESE FROM YOUR PROGRAMS OR * 625 | * INSTRUMENT LIBRARIES * 626 | *****************************************************************************/ 627 | 628 | /* OPEN FUNCTIONS * 629 | * ============== */ 630 | 631 | static int _vxi11_open_link(VXI11_CLINK * clink, const char *address, 632 | char *device) 633 | { 634 | #ifndef WIN32 635 | Create_LinkParms link_parms; 636 | 637 | /* Set link parameters */ 638 | link_parms.clientId = (long)clink->client; 639 | link_parms.lockDevice = 0; 640 | link_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT; 641 | link_parms.device = device; 642 | 643 | clink->link = (Create_LinkResp *) calloc(1, sizeof(Create_LinkResp)); 644 | 645 | if (create_link_1(&link_parms, clink->link, clink->client) != 646 | RPC_SUCCESS) { 647 | clnt_perror(clink->client, address); 648 | return -2; 649 | } 650 | #endif 651 | return 0; 652 | } 653 | 654 | /* CLOSE FUNCTIONS * 655 | * =============== */ 656 | 657 | static int _vxi11_close_link(VXI11_CLINK * clink, const char *address) 658 | { 659 | #ifndef WIN32 660 | Device_Error dev_error; 661 | memset(&dev_error, 0, sizeof(dev_error)); 662 | 663 | if (destroy_link_1(&clink->link->lid, &dev_error, clink->client) != 664 | RPC_SUCCESS) { 665 | clnt_perror(clink->client, address); 666 | return -1; 667 | } 668 | #endif 669 | return 0; 670 | } 671 | --------------------------------------------------------------------------------