From 479f09aee8db7045f680295568aa2f9400c26114 Mon Sep 17 00:00:00 2001 From: Claudio Scafuri <claudio.scafuri@elettra.eu> Date: Thu, 28 May 2020 10:29:04 +0200 Subject: [PATCH] first import from elelttra local cvs repo devel/utils/libvxi11 release_02 --- .gitignore | 9 + CHANGELOG.txt | 218 ++++++++++ GNU_General_Public_License.txt | 340 ++++++++++++++++ Makefile | 68 ++++ README.md | 25 +- README.txt | 98 +++++ vxi11.x | 317 +++++++++++++++ vxi11_cmd.cc | 83 ++++ vxi11_user.cc | 723 +++++++++++++++++++++++++++++++++ vxi11_user.h | 87 ++++ 10 files changed, 1966 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 CHANGELOG.txt create mode 100644 GNU_General_Public_License.txt create mode 100644 Makefile create mode 100644 README.txt create mode 100644 vxi11.x create mode 100644 vxi11_cmd.cc create mode 100644 vxi11_user.cc create mode 100644 vxi11_user.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ed5462 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.o +*.so* +*.a +TAGS +vxi11_cmd +vxi11.h +vxi11_svc.c +vxi11_xdr.c +vxi11_clnt.c diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 0000000..230d9dc --- /dev/null +++ b/CHANGELOG.txt @@ -0,0 +1,218 @@ +------------------------------------------------------------------------------ +vxi11_1.10 - 9/09/2010 + +Bug fix (thanks to Stephan Mahr): in vxi11_close(), remove the IP address +from the global array that keeps track of them so that if the same device +is opened again, then a new client is created, rather than it attempting +to use the old one (which was destroyed on the previous close). + +------------------------------------------------------------------------------ +vxi11_1.09 - 7/06/2010 + +Moved over to bazaar VCS (from RCS). + +Makefile cleanups. Fixed signed/unsigned comparisons. Use consistent (and +sane) struct separator spacing in code. + +Fix int casting on printf statements to fix new compiler warnings/errors +(thanks to Shouri Chatterjee for pointing this out). + +------------------------------------------------------------------------------ +vxi11_1.08 - 3/09/2009 + +Added a sanity check for link->maxRecvSize to make sure it's >0. This gets +around a bug in some versions of the Agilent Infiniium scope software. + +Changed the erroneous strncpy() to memcpy() in vxi11_send, as we could be +sending binary data (not just strings). + +Changed a lot of char *'s to const char *'s in an attempt to get rid of +pedantic gcc compiler warnings. + +------------------------------------------------------------------------------ +vxi11_1.07 - 9/10/2007 + +Minor change to vxi11_receive_data_block(), this fn now copes with instruments +that return just "#0" (for whatever reason). Suggestion by Jarek Sadowski, +gratefully received. + +------------------------------------------------------------------------------ +vxi11_1.06 - 31/08/2007 + +Bug fix in vxi11_receive(), to ensure that no more than "len" bytes are ever +received (and so avoiding a segmentation fault). This was a bug introduced in +release 1.04 whilst making some other changes to the vxi11_receive() fn. + +Many thanks to Rob Penny for spotting the bug and providing a patch. + +------------------------------------------------------------------------------ +vxi11_1.05 - 11/07/2007 + +Added the ability to specify a "device name" when calling vxi11_open_device(). +For regular VXI11-based instruments, such as scopes and AFGs, the device name +is usually "hard wired" to be "inst0", and up to now this has been hard wired +into the vxi11_user code. However, devices such as LAN to GPIB gateways need +some way of distinguishing between different devices... they are a single +client (one IP address), with multiple devices. + +The vxi11_user fn, vxi11_open_device(), now takes a third argument +(char *device). +This gets passed to the core vxi11_open_device() fn (the one that deals with +separate clients and links), and the core vxi11_open_link() fn; these two +core functions have also had an extra parameter added accordingly. In order +to not break the API, a wrapper function is provided in the form of the +original vxi11_open_device() fn, that just takes 2 arguments +(char *ip, CLINK *clink), this then passes "inst0" as the device argument. +Backwards-compatible wrappers for the core functions have NOT been provided. +These are generally not used from userland anyway. Hopefully this won't +upset anyone! + +vxi11_cmd, the simple test utility, has also been updated. You can now, +optionally, pass the device_name as a second argument (after the ip +address). The source has been renamed to vxi11_cmd.cc (from vxi11_cmd.c), as +it is C++ code not C. + +Some minor tidying up in vxi11_user.h + +With thanks to Oliver Schulz for bringing LAN to GPIB gateways to my +attention, for suggesting changes to the vxi11_user library to allow them to +be accommodated, and for tidying some things up. + +------------------------------------------------------------------------------ +vxi11_1.04 - 10/07/2007 + +Patch applied, which was kindly provided by Robert Larice. This sorts out +the confusion (on my part) about the structures returned by the rpcgen +generated *_1() functions... these are statically allocated temporary structs, +apparently. In the words of Robert Larice: + +****** +Hello Dr. Sharples, + + I'm sending some patches for your nice gem "vxi11_1.03" + + In the source code there were some strange comments, concerning + a commented free() around ... Manfred S. ... + and some notes, suggesting you had trouble to get more than one link + working. + + I think thats caused by some misuse of the rpcgen generated subroutines. + 1) those rpcgen generated *_1 functions returned pointers to + statically allocated temporary structs. + those where meant to be instantly copied to the user's space, + which wasn't done + thus instead of + Device_ReadResp *read_resp; + read_resp = device_read_1(...) + one should have written someting like: + Device_ReadResp *read_resp; + read_resp = malloc(...) + memcpy(read_resp, device_read_1(...), ...) + 2) but a better fix is to use the rpcgen -M Flag + which allows to pass the memory space as a third argument + so one can write + Device_ReadResp *read_resp; + read_resp = malloc(...) + device_read_1(..., read_resp, ...) + furthermore this is now automatically thread save + 3) the rpcgen function device_read_1 + expects a target buffer to be passed via read_resp + which was not done. + 4) the return value of vxi11_receive() was computed incorrectly + 5) minor, Makefile typo's + CFLAGS versus + CLFAGS + +****** + +Robert didn't have more than one device to try the patch with, but I've just +tried it and everything seems fine. So I've removed all references to the +VXI11_ENABLE_MULTIPLE_CLIENTS global variable, and removed the call to +vxi11_open_link() from the vxi11_send() fn. There has been an associated +tidying of functions, and removal of some comments. + +Thanks once again to Robert Larice for the patch and the explanation! + +------------------------------------------------------------------------------ +vxi11_1.03 - 29/01/2007 + +Some bug-fixes (thanks to Manfred S.), and extra awareness of the +possibility that instruments could time out after receiving a query WITHOUT +causing an error condition. In some cases (prior to these changes) this +could have resulted in a segmentation fault. + +Specifically: + +(1) removed call to ANSI free() fn in vxi11_receive, which according to + Manfred S. "is not necessary and wrong (crashes)". + +(2) added extra check in vxi11_receive() to see if read_resp==NULL. + read_resp can apparently be NULL if (eg) you send an instrument a + query, but the instrument is so busy with something else for so long + that it forgets the original query. So this extra check is for that + situation, and vxi11_receive returns -VXI11_NULL_READ_RESP to the + calling function. + +(3) vxi11_send_and_receive() is now aware of the possibility of being + returned -VXI11_NULL_READ_RESP. If so, it re-sends the query, until + either getting a "regular" read error (read_resp->error!=0) or a + successful read. + +(4) Similar to (2)... added extra check in vxi11_send() to see if + write_resp==NULL. If so, return -VXI11_NULL_WRITE_RESP. As with (3), + send_and_receive() is now aware of this possibility. + +------------------------------------------------------------------------------ +vxi11_1.02 - 25/08/2006 + +Important changes to the core vxi11_send() function, which should be +invisible to the user. + +For those interested, the function now takes note of the value of +link->maxRecvSize, which is the maximum number of bytes that the vxi11 +intrument you're talking to can receive in one go. For many instruments +this may be a few kB, which isn't a problem for sending short commands; +however, sending large chunks of data (for example sending waveforms +to instruments) may exceed this maxRecvSize. The core vxi11_send() function +has been re-written to ensure that only a maximum of [maxRecvSize] bytes are +written in one go... the function sits in a loop until all the message/ +data is written. + +Also tidied up some of the return values (specifically with regard to +vxi11_send() and vxi11_send_data_block() ). + +------------------------------------------------------------------------------ +vxi11_1.01 - 06/07/2006 + +Fair few changes since v1.00, all in vxi11_user.c and vxi11_user.h + +Found I was having problems talking to multiple links on the same +client, if I created a different client for each one. So introduced +a few global variables to keep track of all the ip addresses of +clients that the library is asked to create, and only creating new +clients if the ip address is different. This puts a limit of how +many unique ip addresses (clients) a single process can connect to. +Set this value at 256 (should hopefully be enough!). + +Next I found that talking to different clients on different ip +addresses didn't work. It turns out that create_link_1() creates +a static structure. This this link is associated with a given +client (and hence a given IP address), then the only way I could +think of making things work was to add a call to an +vxi11_open_link() function before each send command (no idea what +this adds to overheads and it's very messy!) - at least I was +able to get this to only happen when we are using more than one +client/ip address. + +Also, while I was at it, I re-ordered the functions a little - +starts with core user functions, extra user functions, then core +library functions at the end. Added a few more comments. Tidied +up. Left some debugging info in, but commented out. + +------------------------------------------------------------------------------ +vxi11_1.00 - 23/06/2006 + +Initial release. + +------------------------------------------------------------------------------ + diff --git a/GNU_General_Public_License.txt b/GNU_General_Public_License.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/GNU_General_Public_License.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f150c8e --- /dev/null +++ b/Makefile @@ -0,0 +1,68 @@ +VERSION=1.08 + +#CFLAGS = -Wall -g +#CFLAGS = -g +CFLAGS = -fPIC -DRELEASE='"N$Name: release_01 $ "' +INSTALL = install +prefix = /usr/local +CXX = g++ + + +############################################## +# support for shared libray versioning +# +LFLAGS_SONAME = -Wl,-soname, +LFLAGS_RPATH = -Wl,-rpath, +SHLDFLAGS = -shared -fPIC +BASELIBNAME = libvxi11 +SHLIB_SUFFIX = so + +# release numbers for libraries +# + LIBVERSION = 1 + LIBRELEASE = 0 + LIBSUBRELEASE = 8 +# + +LIBRARY = $(BASELIBNAME).a +DT_SONAME = $(BASELIBNAME).$(SHLIB_SUFFIX).$(LIBVERSION) +DT_SHLIB = $(BASELIBNAME).$(SHLIB_SUFFIX).$(LIBVERSION).$(LIBRELEASE).$(LIBSUBRELEASE) +SHLIB = $(BASELIBNAME).$(SHLIB_SUFFIX) + + +.PHONY : install clean dist distclean + +vxi11_cmd: vxi11_cmd.o vxi11_user.o vxi11_clnt.o vxi11_xdr.o +# $(CXX) $(CFLAGS) -o $@ $^ + $(CXX) vxi11_cmd.o vxi11_user.o vxi11_clnt.o vxi11_xdr.o $(SHLDFLAGS) $(LFLAGS_SONAME)$(DT_SONAME) -o $(DT_SHLIB) + ln -sf $(DT_SHLIB) $(SHLIB) + ln -sf $(SHLIB) $(DT_SONAME) +# ar rcs libvxi11.a vxi11_user.o vxi11_clnt.o vxi11_xdr.o + +vxi11_cmd.o: vxi11_cmd.cc vxi11_user.cc vxi11.h + $(CXX) $(CFLAGS) -fPIC -c $< -o $@ + +vxi11_user.o: vxi11_user.cc vxi11.h + $(CXX) $(CFLAGS) -fPIC -c $< -o $@ + +vxi11.h vxi11_clnt.c vxi11_xdr.c : vxi11.x + rpcgen -M vxi11.x + +TAGS: $(wildcard *.c) $(wildcard *.h) $(wildcard *.cc) + etags $^ + +clean: + rm -f *.o *.so* vxi11_cmd vxi11.h vxi11_svc.c vxi11_xdr.c vxi11_clnt.c TAGS + +install: vxi11_cmd + $(INSTALL) vxi11_cmd $(DESTDIR)$(prefix)/bin/ + +dist : distclean + mkdir vxi11-$(VERSION) + cp -p vxi11_cmd.cc vxi11_user.cc vxi11_user.h vxi11.x vxi11-$(VERSION)/ + cp -p Makefile CHANGELOG.txt README.txt GNU_General_Public_License.txt vxi11-$(VERSION)/ + tar -zcf vxi11-$(VERSION).tar.gz vxi11-$(VERSION) + +distclean : + rm -rf vxi11-$(VERSION) + rm -f vxi11-$(VERSION).tar.gz diff --git a/README.md b/README.md index 38b1a7a..7a55c5e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,26 @@ # libvx11 -VX-11 Instrument access library +VXI-11 Instrument access library -Elettra local copy \ No newline at end of file +Elettra local copy + +# requirements + +rpcgen + +# build + +## History + + +202i0-05-28: project created on gitlab, derived from CVS release_02 + + +## Credits +Graziano Scalamera +Elettra-Sincrotrone Trieste S.C.p.A. di interesse nazionale +Strada Statale 14 - km 163,5 in AREA Science Park +34149 Basovizza, Trieste ITALY + +## License +GPL2 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..a75fda3 --- /dev/null +++ b/README.txt @@ -0,0 +1,98 @@ +RPC PROTOCOL FOR COMMUNICATING WITH VXI11-ENABLED DEVICES OVER ETHERNET FROM LINUX +================================================================================== +(including instruments such as oscilloscopes, by manufacturers such as +Agilent and Tektronix, amongst others). + +By Steve D. Sharples, June 2006. + +This is a collection of source code that will allow you to talk to ethernet- +enabled instruments that use the VXI11 protocol, from Linux. This includes +a wide range of instruments (including oscilloscopes, logic analysers, +function generators etc) by a wide range of manufacturers (including +Tektronix and Agilent to name just a couple). An interactive "send and +receive" utility is included as an example. + +You may want to build on to this libraries for your specific instruments - +I'm currently working on libraries for talking to Agilent Infiniium scopes, +and will probably do the same for Tektronix scopes too. Basically if you've +got a Programmer's Reference for your instrument, and this code, you should +be able to cobble something together. + +This collection of code has been produced because I grew frustrated at how +difficult it seemed to be to do a relatively simple task. None of the +major manufacturers had any "out of the box" Linux solutions to talking to +their instruments (although often I would talk to technical folks who would +try their best to help). One of the solutions offered was to use something +called NI VISA; parts of this are closed source, it was enormous, and I had +worries about legacy issues with changing PC hardware. + +Via Guy McBride at Agilent, I obtained a copy of a vxi11.x RPC file similar +to the one included here (although no-one at Agilent seemed to know or care +where it came from). After lots of searching on the information superhighway +I located what I believe is the original source (or something like it); see +the section on vxi11.x below. This source seems to have literally been written +from the published VXI11 protocol. I also received from Agilent a simple +example program that showed you how to use the protocol; working from this +and the (open) source that uses the vxi11.x that is included here, I wrote +vxi11_cmd and the user libraries. + +This collection of source code consists of: + +(1) vxi11.x +This file, vxi11.x, is the amalgamation of vxi11core.rpcl and vxi11intr.rpcl +which are part of the asynDriver (R4-5) EPICS module, which, at time of +writing, is available from: +http://www.aps.anl.gov/epics/modules/soft/asyn/index.html +More general information about EPICS is available from: +http://www.aps.anl.gov/epics/ +This code is open source, and is covered under the copyright notice and +software license agreement shown below, and also at: +http://www.aps.anl.gov/epics/license/open.php + +It is intended as a lightweight base for the vxi11 rpc protocol. If you +run rpcgen on this file, it will generate C files and headers, from which +it is relatively simple to write C programs to communicate with a range +of ethernet-enabled instruments, such as oscilloscopes and function +generators by manufacturers such as Agilent and Tektronix (amongst many +others). + +(2) vxi11_user.cc (and vxi11_user.h) +These are (fairly) friendly user libraries. At the core are 4 key functions: +vxi11_open(), vxi11_close(), vxi11_send() and vxi11_receive(). These allow +you to talk to your device. There are also some other functions that I +considered to be generally useful (send_and_receive, functions for sending +and receiving fixed length data blocks etc) that are all non-instrument- +specific. + +(3) vxi11_cmd.c +This is a fairly simple interactive utility that allows you to send +commands and queries to your vxi11-enabled instrument, which you +locate by way of IP address. I recommend you start with *IDN? It shows you +how the vxi11_user library works + +(4) Makefile +Type "make" to compile the source above. Type "make clean" to remove +old object files and ./vxi11_cmd. Type "make install" to copy +./vxi11_cmd to /usr/local/bin/ + +(5) GNU_General_Public_License.txt +Fairly obvious. All programs, source, readme files etc NOT covered by any +other license (e.g. vxi11.x, which is covered by its own open source +license) are covered by this license. + +These programs are free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +These programs are distributed in the hope that they will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +The author's email address is steve.no.spam.sharples@nottingham.ac.uk +(you can work it out!) diff --git a/vxi11.x b/vxi11.x new file mode 100644 index 0000000..27f1293 --- /dev/null +++ b/vxi11.x @@ -0,0 +1,317 @@ +/* This file, vxi11.x, is the amalgamation of vxi11core.rpcl and vxi11intr.rpcl + * which are part of the asynDriver (R4-5) EPICS module, which, at time of + * writing, is available from: + * http://www.aps.anl.gov/epics/modules/soft/asyn/index.html + * More general information about EPICS is available from: + * http://www.aps.anl.gov/epics/ + * This code is open source, and is covered under the copyright notice and + * software license agreement shown below, and also at: + * http://www.aps.anl.gov/epics/license/open.php + * + * In order to comply with section 4.3 of the software license agreement, here + * is a PROMINENT NOTICE OF CHNAGES TO THE SOFTWARE + * =========================================== + * (1) This file, vxi11.x, is the concatenation of the files vxi11core.rpcl and + * vxi11intr.rpcl + * (2) Tab spacing has been tidied up + * + * It is intended as a lightweight base for the vxi11 rpc protocol. If you + * run rpcgen on this file, it will generate C files and headers, from which + * it is relatively simple to write C programs to communicate with a range + * of ethernet-enabled instruments, such as oscilloscopes and function + * generated by manufacturers such as Agilent and Tektronix (amongst many + * others). + * + * For what it's worth, this concatenation was done by Steve Sharples at + * the University of Nottingham, UK, on 1 June 2006. + * + * Copyright notice and software license agreement follow, then the + * original comments from vxi11core.rpcl etc. + * + ****************************************************************************** + * Copyright © 2006 <University of Chicago and other copyright holders>. All + * rights reserved. + ****************************************************************************** + * + ****************************************************************************** + * vxi11.x is distributed subject to the following license conditions: + * SOFTWARE LICENSE AGREEMENT + * Software: vxi11.x + * + * 1. The "Software", below, refers to vxi11.x (in either source code, or + * binary form and accompanying documentation). Each licensee is addressed + * as "you" or "Licensee." + * + * 2. The copyright holders shown above and their third-party licensors hereby + * grant Licensee a royalty-free nonexclusive license, subject to the + * limitations stated herein and U.S. Government license rights. + * + * 3. You may modify and make a copy or copies of the Software for use within + * your organization, if you meet the following conditions: + * 1. Copies in source code must include the copyright notice and this + * Software License Agreement. + * 2. Copies in binary form must include the copyright notice and this + * Software License Agreement in the documentation and/or other + * materials provided with the copy. + * + * 4. You may modify a copy or copies of the Software or any portion of it, + * thus forming a work based on the Software, and distribute copies of such + * work outside your organization, if you meet all of the following + * conditions: + * 1. Copies in source code must include the copyright notice and this + * Software License Agreement; + * 2. Copies in binary form must include the copyright notice and this + * Software License Agreement in the documentation and/or other + * materials provided with the copy; + * 3. Modified copies and works based on the Software must carry + * prominent notices stating that you changed specified portions of + * the Software. + * + * 5. Portions of the Software resulted from work developed under a U.S. + * Government contract and are subject to the following license: the + * Government is granted for itself and others acting on its behalf a + * paid-up, nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, and perform publicly + * and display publicly. + * + * 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF + * ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE UNITED + * STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR EMPLOYEES: (1) + * DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY + * OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF THE + * SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE SOFTWARE WOULD NOT INFRINGE + * PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION + * UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL BE CORRECTED. + * + * 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR + * THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF + * ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, + * CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, + * INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY + * REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF + * CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, + * EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE POSSIBILITY OF SUCH + * LOSS OR DAMAGES. + ****************************************************************************** + */ + +/****************************************************************************** + * + * vxi11core.rpcl + * + * This file is best viewed with a tabwidth of 4 + * + ****************************************************************************** + * + * TODO: + * + ****************************************************************************** + * + * Original Author: someone from VXIbus Consortium + * Current Author: Benjamin Franksen + * Date: 03-06-97 + * + * RPCL description of the core- and abort-channel of the TCP/IP Instrument + * Protocol Specification. + * + * + * Modification Log: + * ----------------- + * .00 03-06-97 bfr created this file + * + ****************************************************************************** + * + * Notes: + * + * This stuff is literally from + * + * VXI-11, Ref 1.0 : TCP/IP Instrument Protocol Specification + * + */ + +typedef long Device_Link; + +enum Device_AddrFamily +{ + DEVICE_TCP, + DEVICE_UDP +}; + +typedef long Device_Flags; + +typedef long Device_ErrorCode; + +struct Device_Error +{ + Device_ErrorCode error; +}; + +struct Create_LinkParms +{ + long clientId; /* implementation specific value */ + bool lockDevice; /* attempt to lock the device */ + unsigned long lock_timeout; /* time to wait for lock */ + string device<>; /* name of device */ +}; +struct Create_LinkResp +{ + Device_ErrorCode error; + Device_Link lid; + unsigned short abortPort; /* for the abort RPC */ + unsigned long maxRecvSize; /* max # of bytes accepted on write */ +}; +struct Device_WriteParms +{ + Device_Link lid; /* link id from create_link */ + unsigned long io_timeout; /* time to wait for I/O */ + unsigned long lock_timeout; /* time to wait for lock */ + Device_Flags flags; /* flags with options */ + opaque data<>; /* the data length and the data itself */ +}; +struct Device_WriteResp +{ + Device_ErrorCode error; + unsigned long size; /* # of bytes written */ +}; +struct Device_ReadParms +{ + Device_Link lid; /* link id from create_link */ + unsigned long requestSize; /* # of bytes requested */ + unsigned long io_timeout; /* time to wait for I/O */ + unsigned long lock_timeout; /* time to wait for lock */ + Device_Flags flags; /* flags with options */ + char termChar; /* valid if flags & termchrset */ +}; +struct Device_ReadResp +{ + Device_ErrorCode error; + long reason; /* why read completed */ + opaque data<>; /* the data length and the data itself */ +}; +struct Device_ReadStbResp +{ + Device_ErrorCode error; + unsigned char stb; /* the returned status byte */ +}; +struct Device_GenericParms +{ + Device_Link lid; /* link id from create_link */ + Device_Flags flags; /* flags with options */ + unsigned long lock_timeout; /* time to wait for lock */ + unsigned long io_timeout; /* time to wait for I/O */ +}; +struct Device_RemoteFunc +{ + unsigned long hostAddr; /* host servicing interrupt */ + unsigned long hostPort; /* valid port # on client */ + unsigned long progNum; /* DEVICE_INTR */ + unsigned long progVers; /* DEVICE_INTR_VERSION */ + Device_AddrFamily progFamily; /* DEVICE_UDP | DEVICE_TCP */ +}; +struct Device_EnableSrqParms +{ + Device_Link lid; /* link id from create_link */ + bool enable; /* enable or disable intr's */ + opaque handle<40>; /* host specific data */ +}; +struct Device_LockParms +{ + Device_Link lid; /* link id from create_link */ + Device_Flags flags; /* contains the waitlock flag */ + unsigned long lock_timeout; /* time to wait for lock */ +}; +struct Device_DocmdParms +{ + Device_Link lid; /* link id from create_link */ + Device_Flags flags; /* flags with options */ + unsigned long io_timeout; /* time to wait for I/O */ + unsigned long lock_timeout; /* time to wait for lock */ + long cmd; /* which command to execute */ + bool network_order; /* client's byte order */ + long datasize; /* size of individual data elements */ + opaque data_in<>; /* docmd data parameters */ +}; +struct Device_DocmdResp +{ + Device_ErrorCode error; + opaque data_out<>; /* returned data parameters */ +}; + +program DEVICE_ASYNC +{ + version DEVICE_ASYNC_VERSION + { + Device_Error device_abort (Device_Link) = 1; + } = 1; +} = 0x0607B0; + +program DEVICE_CORE +{ + version DEVICE_CORE_VERSION + { + Create_LinkResp create_link (Create_LinkParms) = 10; + Device_WriteResp device_write (Device_WriteParms) = 11; + Device_ReadResp device_read (Device_ReadParms) = 12; + Device_ReadStbResp device_readstb (Device_GenericParms) = 13; + Device_Error device_trigger (Device_GenericParms) = 14; + Device_Error device_clear (Device_GenericParms) = 15; + Device_Error device_remote (Device_GenericParms) = 16; + Device_Error device_local (Device_GenericParms) = 17; + Device_Error device_lock (Device_LockParms) = 18; + Device_Error device_unlock (Device_Link) = 19; + Device_Error device_enable_srq (Device_EnableSrqParms) = 20; + Device_DocmdResp device_docmd (Device_DocmdParms) = 22; + Device_Error destroy_link (Device_Link) = 23; + Device_Error create_intr_chan (Device_RemoteFunc) = 25; + Device_Error destroy_intr_chan (void) = 26; + } = 1; +} = 0x0607AF; + +/****************************************************************************** + * + * vxi11intr.rpcl + * + * This file is best viewed with a tabwidth of 4 + * + ****************************************************************************** + * + * TODO: + * + ****************************************************************************** + * + * Original Author: someone from VXIbus Consortium + * Current Author: Benjamin Franksen + * Date: 03-06-97 + * + * RPCL description of the intr-channel of the TCP/IP Instrument Protocol + * Specification. + * + * + * Modification Log: + * ----------------- + * .00 03-06-97 bfr created this file + * + ****************************************************************************** + * + * Notes: + * + * This stuff is literally from + * + * "VXI-11, Ref 1.0 : TCP/IP Instrument Protocol Specification" + * + */ + +struct Device_SrqParms +{ + opaque handle<>; +}; + +program DEVICE_INTR +{ + version DEVICE_INTR_VERSION + { + void device_intr_srq (Device_SrqParms) = 30; + } = 1; +} = 0x0607B1; diff --git a/vxi11_cmd.cc b/vxi11_cmd.cc new file mode 100644 index 0000000..503f5d6 --- /dev/null +++ b/vxi11_cmd.cc @@ -0,0 +1,83 @@ +/* vxi11_cmd.c + * Copyright (C) 2006 Steve D. Sharples + * + * A simple interactive utility that allows you to send commands and queries to + * a device enabled with the VXI11 RPC ethernet protocol. Uses the files + * generated by rpcgen vxi11.x, and the vxi11_user.h user libraries. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The author's email address is steve.sharples@nottingham.ac.uk + */ + +#include "vxi11_user.h" +#define BUF_LEN 100000 + +int main(int argc, char *argv[]) { + +static char *device_ip; +static char *device_name; +char cmd[256]; +char buf[BUF_LEN]; +int ret; +long bytes_returned; +CLINK *clink; + + clink = new CLINK; + + if (argc < 2) { + printf("usage: %s your.inst.ip.addr [device_name]\n",argv[0]); + exit(1); + } + + device_ip = argv[1]; + if (argc > 2) { + device_name = argv[2]; + ret=vxi11_open_device(device_ip,clink,device_name); + } + else { + ret=vxi11_open_device(device_ip,clink); + } + + if (ret != 0) { + printf("Error: could not open device %s, quitting\n",device_ip); + exit(2); + } + + while(1){ + memset(cmd, 0, 256); // initialize command string + memset(buf, 0, BUF_LEN); // initialize buffer + printf("Input command or query ('q' to exit): "); + fgets(cmd,256,stdin); + cmd[strlen(cmd)-1] = 0; // just gets rid of the \n + if (strncasecmp(cmd, "q",1) == 0) break; + + if (vxi11_send(clink, cmd) < 0) break; + if (strstr(cmd, "?") != 0) { + bytes_returned = vxi11_receive(clink, buf, BUF_LEN); + if (bytes_returned > 0) { + printf("%s\n",buf); + } + else if (bytes_returned == -15) { + printf("*** [ NOTHING RECEIVED ] ***\n"); + } + else break; + } + } + + ret=vxi11_close_device(device_ip,clink); + return 0; + } + diff --git a/vxi11_user.cc b/vxi11_user.cc new file mode 100644 index 0000000..decc902 --- /dev/null +++ b/vxi11_user.cc @@ -0,0 +1,723 @@ +/* vxi11_user.cc + * Copyright (C) 2006 Steve D. Sharples + * + * User library for opening, closing, sending to and receiving from + * a device enabled with the VXI11 RPC ethernet protocol. Uses the files + * generated by rpcgen vxi11.x. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The author's email address is steve.sharples@nottingham.ac.uk + */ + +#include "vxi11_user.h" + +/***************************************************************************** + * GENERAL NOTES + ***************************************************************************** + * + * There are four functions at the heart of this library: + * + * int vxi11_open_device(char *ip, CLIENT **client, VXI11_LINK **link) + * int vxi11_close_device(char *ip, CLIENT *client, VXI11_LINK *link) + * int vxi11_send(CLIENT *client, VXI11_LINK *link, char *cmd, unsigned long len) + * long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len, unsigned long timeout) + * + * Note that all 4 of these use separate client and link structures. All the + * other functions are built on these four core functions, and the first layer + * of abstraction is to combine the CLIENT and VXI11_LINK structures into a + * single entity, which I've called a CLINK. For the send and receive + * functions, this is just a simple wrapper. For the open and close functions + * it's a bit more complicated, because we somehow have to keep track of + * whether we've already opened a device with the same IP address before (in + * which case we need to recycle a previously created client), or whether + * we've still got any other links to a given IP address left when we are + * asked to close a clink (in which case we can sever the link, but have to + * keep the client open). This is so the person using this library from + * userland does not have to keep track of whether they are talking to a + * different physical instrument or not each time they establish a connection. + * + * So the base functions that the user will probably want to use are: + * + * int vxi11_open_device(char *ip, CLINK *clink) + * int vxi11_close_device(char *ip, CLINK *clink) + * int vxi11_send(CLINK *clink, char *cmd, unsigned long len) + * --- or --- (if sending just text) + * int vxi11_send(CLINK *clink, char *cmd) + * long vxi11_receive(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) + * + * There are then useful (to me, anyway) more specific functions built on top + * of these: + * + * int vxi11_send_data_block(CLINK *clink, char *cmd, char *buffer, unsigned long len) + * long vxi11_receive_data_block(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) + * long vxi11_send_and_receive(CLINK *clink, char *cmd, char *buf, unsigned long buf_len, unsigned long timeout) + * long vxi11_obtain_long_value(CLINK *clink, char *cmd, unsigned long timeout) + * double vxi11_obtain_double_value(CLINK *clink, char *cmd, unsigned long timeout) + * + * (then there are some shorthand wrappers for the above without specifying + * the timeout due to sheer laziness---explore yourself) + */ + + +/* Global variables. Keep track of multiple links per client. We need this + * because: + * - we'd like the library to be able to cope with multiple links to a given + * client AND multiple links to multiple clients + * - we'd like to just refer to a client/link ("clink") as a single + * entity from user land, we don't want to worry about different + * initialisation procedures, depending on whether it's an instrument + * with the same IP address or not + */ + +#include <math.h> //for NAN +//#define _DEBUG + +char VXI11_IP_ADDRESS[VXI11_MAX_CLIENTS][20]; +CLIENT *VXI11_CLIENT_ADDRESS[VXI11_MAX_CLIENTS]; +int VXI11_DEVICE_NO = 0; +int VXI11_LINK_COUNT[VXI11_MAX_CLIENTS]; + +const char version_string[] = "$Build: @buildID@ " RELEASE " $"; + +/***************************************************************************** + * KEY USER FUNCTIONS - USE THESE FROM YOUR PROGRAMS OR INSTRUMENT LIBRARIES * + *****************************************************************************/ + +/* OPEN FUNCTIONS * + * ============== */ + +/* Use this function from user land to open a device and create a link. Can be + * used multiple times for the same device (the library will keep track).*/ +int vxi11_open_device(const char *ip, CLINK *clink, char *device) { +int ret; +int l; +int device_no=-1; + +// printf("before doing anything, clink->link = %ld\n", clink->link); + /* Have a look to see if we've already initialised an instrument with + * this IP address */ + for (l=0; l<VXI11_MAX_CLIENTS; l++){ + if (strcmp(ip,VXI11_IP_ADDRESS[l]) == 0 ) { + device_no=l; +// printf("Open function, search, found ip address %s, device no %d\n",ip,device_no); +#ifdef _DEBUG + printf("%s: Open function, search, found ip address %s, now ip[%d]=%s device no %d\n",__func__,ip,l,VXI11_IP_ADDRESS[l],device_no); +#endif + } + } + + /* Couldn't find a match, must be a new IP address */ + if (device_no < 0) { + /* Uh-oh, we're out of storage space. Increase the #define + * for VXI11_MAX_CLIENTS in vxi11_user.h */ + if (VXI11_DEVICE_NO >= VXI11_MAX_CLIENTS) { +#ifdef _DEBUG + printf("Error: maximum of %d clients allowed\n",VXI11_MAX_CLIENTS); +#endif + ret = -VXI11_MAX_CLIENTS; + } + /* Create a new client, keep a note of where the client pointer + * is, for this IP address. Because it's a new client, this + * must be link number 1. Keep track of how many devices we've + * opened so we don't run out of storage space. */ + else { + ret = vxi11_open_device(ip, &(clink->client), &(clink->link), device); +#ifdef _DEBUG + printf("%s: after vxi11_open_device clink=0x%x clink->client=0x%x clink->link=0x%x device num=%d\n",__func__,clink,clink->client,clink->link,VXI11_DEVICE_NO); +#endif + strncpy(VXI11_IP_ADDRESS[VXI11_DEVICE_NO],ip,20); + VXI11_CLIENT_ADDRESS[VXI11_DEVICE_NO] = clink->client; + VXI11_LINK_COUNT[VXI11_DEVICE_NO]=1; + //printf("Open function, could not find ip address %s.\n",ip); + //printf("So now, VXI11_IP_ADDRESS[%d]=%s,\n",VXI11_DEVICE_NO,VXI11_IP_ADDRESS[VXI11_DEVICE_NO]); + //printf("VXI11_CLIENT_ADDRESS[%d]=%ld,\n",VXI11_DEVICE_NO,VXI11_CLIENT_ADDRESS[VXI11_DEVICE_NO]); + //printf(" clink->client=%ld,\n",clink->client); + //printf("VXI11_LINK_COUNT[%d]=%d.\n",VXI11_DEVICE_NO,VXI11_LINK_COUNT[VXI11_DEVICE_NO]); + VXI11_DEVICE_NO++; + } + } + /* already got a client for this IP address */ + else { + /* Copy the client pointer address. Just establish a new link + * (not a new client). Add one to the link count */ + clink->client = VXI11_CLIENT_ADDRESS[device_no]; + ret = vxi11_open_link(ip, &(clink->client), &(clink->link), device); + //printf("Found an ip address, copying client from VXI11_CLIENT_ADDRESS[%d]\n",device_no); + VXI11_LINK_COUNT[device_no]++; + //printf("Have just incremented VXI11_LINK_COUNT[%d], it's now %d\n",device_no,VXI11_LINK_COUNT[device_no]); + } +// printf("after creating link, clink->link = %ld\n", clink->link); + return ret; + } + +/* This is a wrapper function, used for the situations where there is only one + * "device" per client. This is the case for most (if not all) VXI11 + * instruments; however, it is _not_ the case for devices such as LAN to GPIB + * gateways. These are single clients that communicate to many instruments + * (devices). In order to differentiate between them, we need to pass a device + * name. This gets used in the vxi11_open_link() fn, as the link_parms.device + * value. */ +int vxi11_open_device(const char *ip, CLINK *clink) { + char device[6]; + strncpy(device,"inst0",6); + return vxi11_open_device(ip, clink, device); + } + + + +/* CLOSE FUNCTION * + * ============== */ + +/* Use this function from user land to close a device and/or sever a link. Can + * be used multiple times for the same device (the library will keep track).*/ +int vxi11_close_device(const char *ip, CLINK *clink) { +int l,ret; +int device_no = -1; +#ifdef _DEBUG + printf("vxi11_close_device: entering\n"); +#endif + /* Which instrument are we referring to? */ + for (l=0; l<VXI11_MAX_CLIENTS; l++){ + if (strcmp(ip,VXI11_IP_ADDRESS[l]) == 0 ) { + device_no=l; + } + } + /* Something's up if we can't find the IP address! */ + if (device_no == -1) { +#ifdef _DEBUG + printf("vxi11_close_device: error: I have no record of you ever opening device\n"); + printf(" with IP address %s\n",ip); +#endif + ret = -4; + } + else { /* Found the IP, there's more than one link to that instrument, + * so keep track and just close the link */ + if (VXI11_LINK_COUNT[device_no] > 1 ) { +#ifdef _DEBUG + printf("%s: more than one link: going to destroy link-client=0x%x link=0x%x\n",__func__,clink->client,clink->link); +#endif + ret = vxi11_close_link(ip,clink->client, clink->link); + VXI11_LINK_COUNT[device_no]--; + } + /* Found the IP, it's the last link, so close the device (link + * AND client) */ + else { +#ifdef _DEBUG + printf("%s: only one link: going to close device-client=0x%x link=0x%x device num=%d\n",__func__,clink->client,clink->link,VXI11_DEVICE_NO); +#endif + ret = vxi11_close_device(ip, clink->client, clink->link); + /* Remove the IP address, so that if we re-open the same device + * we do it properly */ + memset(VXI11_IP_ADDRESS[device_no], 0, 20); + VXI11_DEVICE_NO--; + } + } + return ret; + } + + +/* SEND FUNCTIONS * + * ============== */ + +/* A _lot_ of the time we are sending text strings, and can safely rely on + * strlen(cmd). */ +int vxi11_send(CLINK *clink, const char *cmd) { + return vxi11_send(clink, cmd, strlen(cmd)); + } + +/* We still need the version of the function where the length is set explicitly + * though, for when we are sending fixed length data blocks. */ +int vxi11_send(CLINK *clink, const char *cmd, unsigned long len) { + return vxi11_send(clink->client, clink->link, cmd, len); + } + + +/* RECEIVE FUNCTIONS * + * ================= */ + +/* Lazy wrapper for when I can't be bothered to specify a read timeout */ +long vxi11_receive(CLINK *clink, char *buffer, unsigned long len) { + return vxi11_receive(clink, buffer, len, VXI11_READ_TIMEOUT); + } + +long vxi11_receive(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) { + return vxi11_receive(clink->client, clink->link, buffer, len, timeout); + } + + + +/***************************************************************************** + * USEFUL ADDITIONAL HIGHER LEVER USER FUNCTIONS - USE THESE FROM YOUR * + * PROGRAMS OR INSTRUMENT LIBRARIES * + *****************************************************************************/ + +/* SEND FIXED LENGTH DATA BLOCK FUNCTION * + * ===================================== */ +int vxi11_send_data_block(CLINK *clink, const char *cmd, char *buffer, unsigned long len) { +char *out_buffer; +int cmd_len=strlen(cmd); +int ret; + + out_buffer=new char[cmd_len+10+len]; + sprintf(out_buffer,"%s#8%08lu",cmd,len); + memcpy(out_buffer+cmd_len+10,buffer,(unsigned long) len); + ret = vxi11_send(clink, out_buffer, (unsigned long) (cmd_len+10+len)); + delete[] out_buffer; + return ret; + } + + +/* RECEIVE FIXED LENGTH DATA BLOCK FUNCTION * + * ======================================== */ + +/* This function reads a response in the form of a definite-length block, such + * as when you ask for waveform data. The data is returned in the following + * format: + * #800001000<1000 bytes of data> + * ||\______/ + * || | + * || \---- number of bytes of data + * |\--------- number of digits that follow (in this case 8, with leading 0's) + * \---------- always starts with # + */ +long vxi11_receive_data_block(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout) { +/* I'm not sure what the maximum length of this header is, I'll assume it's + * 11 (#9 + 9 digits) */ +unsigned long necessary_buffer_size; +char *in_buffer; +int ret; +int ndigits; +unsigned long returned_bytes; +int l; +char scan_cmd[20]; + necessary_buffer_size=len+12; + in_buffer=new char[necessary_buffer_size]; + ret=vxi11_receive(clink, in_buffer, necessary_buffer_size, timeout); + if (ret < 0) return ret; + if (in_buffer[0] != '#') { +#ifdef _DEBUG + printf("vxi11_user: data block error: data block does not begin with '#'\n"); + printf("First 20 characters received were: '"); + for(l=0;l<20;l++) { + printf("%c",in_buffer[l]); + } + printf("'\n"); +#endif + return -3; + } + + /* first find out how many digits */ + sscanf(in_buffer,"#%1d",&ndigits); + /* some instruments, if there is a problem acquiring the data, return only "#0" */ + if (ndigits > 0) { + /* now that we know, we can convert the next <ndigits> bytes into an unsigned long */ + sprintf(scan_cmd,"#%%1d%%%dlu",ndigits); + sscanf(in_buffer,scan_cmd,&ndigits,&returned_bytes); + memcpy(buffer, in_buffer+(ndigits+2), returned_bytes); + delete[] in_buffer; + return (long) returned_bytes; + } + else return 0; + } + + +/* SEND AND RECEIVE FUNCTION * + * ========================= */ + +/* This is mainly a useful function for the overloaded vxi11_obtain_value() + * fn's, but is also handy and useful for user and library use */ +long vxi11_send_and_receive(CLINK *clink, const char *cmd, char *buf, unsigned long buf_len, unsigned long timeout) { +int ret; +long bytes_returned; +int count=0; + do + { + count++; + ret = vxi11_send(clink, cmd); + if (ret != 0) + { + if (ret != -VXI11_NULL_WRITE_RESP) + { +#ifdef _DEBUG + printf("Error: vxi11_send_and_receive: could not send cmd.\n"); + printf(" The function vxi11_send returned %d. ",ret); +#endif + return -1; + } +#ifdef _DEBUG + else printf("(Info: VXI11_NULL_WRITE_RESP in vxi11_send_and_receive, resending query) ret=%d\n",ret); +#endif + } + + bytes_returned = vxi11_receive(clink, buf, buf_len, timeout); + if (bytes_returned <= 0) + { + if (bytes_returned >-VXI11_NULL_READ_RESP) + { +#ifdef _DEBUG + printf("Error: vxi11_send_and_receive: problem reading reply.\n"); + printf(" The function vxi11_receive returned %ld. ",bytes_returned); +#endif + return -2; + } +#ifdef _DEBUG + else printf("(Info: VXI11_NULL_READ_RESP in vxi11_send_and_receive, resending query) bytes_returned=%d\n",bytes_returned); +#endif + } + } while ((bytes_returned == -VXI11_NULL_READ_RESP || ret == -VXI11_NULL_WRITE_RESP) && count < 100); + if(count == 100) + { +#ifdef _DEBUG + printf("%s count=%d exiting -3!\n",__func__,count); +#endif + return -3; + } + return 0; + } + + +/* FUNCTIONS TO RETURN A LONG INTEGER VALUE SENT AS RESPONSE TO A QUERY * + * ==================================================================== */ +long vxi11_obtain_long_value(CLINK *clink, const char *cmd, unsigned long timeout) { +char buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */ + memset(buf, 0, 50); + if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) + { +#ifdef _DEBUG + printf("Returning %li\n",LONG_MAX); +#endif + //return 0; + return LONG_MAX; + } + return strtol(buf, (char **)NULL, 10); +} + +/* Lazy wrapper function with default read timeout */ +long vxi11_obtain_long_value(CLINK *clink, const char *cmd) +{ + return vxi11_obtain_long_value(clink, cmd, VXI11_READ_TIMEOUT); +} + + +/* FUNCTIONS TO RETURN A DOUBLE FLOAT VALUE SENT AS RESPONSE TO A QUERY * + * ==================================================================== */ +double vxi11_obtain_double_value(CLINK *clink, const char *cmd, unsigned long timeout) +{ +char buf[50]; /* 50=arbitrary length... more than enough for one number in ascii */ +double val; + memset(buf, 0, 50); + if (vxi11_send_and_receive(clink, cmd, buf, 50, timeout) != 0) + { +#ifdef _DEBUG + printf("Returning %f\n",NAN); +#endif + //return 0.0; + return NAN; + } + val = strtod(buf, (char **)NULL); + return val; +} + +/* Lazy wrapper function with default read timeout */ +double vxi11_obtain_double_value(CLINK *clink, const char *cmd) +{ + return vxi11_obtain_double_value(clink, cmd, VXI11_READ_TIMEOUT); +} + + +/***************************************************************************** + * CORE FUNCTIONS - YOU SHOULDN'T NEED TO USE THESE FROM YOUR PROGRAMS OR * + * INSTRUMENT LIBRARIES * + *****************************************************************************/ + +/* OPEN FUNCTIONS * + * ============== */ +int vxi11_open_device(const char *ip, CLIENT **client, VXI11_LINK **link, char *device) { + +#if 0 + int alive=ping(ip); + if(alive <= 0) + { +#ifdef _DEBUG + printf("%s: client ping error\n",__func__); +#endif + return -1; + } +#endif + *client = clnt_create(ip, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp"); + + if (*client == NULL) { +#ifdef _DEBUG + printf("%s: client creation error\n",__func__); +#endif + clnt_pcreateerror(ip); + return -1; + } +#ifdef _DEBUG + printf("%s: created client=0x%x going to create link\n",__func__,*client); +#endif + return vxi11_open_link(ip, client, link, device); + } + +int vxi11_open_link(const char *ip, CLIENT **client, VXI11_LINK **link, char *device) { + +Create_LinkParms link_parms; + + /* Set link parameters */ + link_parms.clientId = (long) *client; + link_parms.lockDevice = 0; + link_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT; + link_parms.device = device; + + *link = (Create_LinkResp *) calloc(1, sizeof(Create_LinkResp)); + + if (create_link_1(&link_parms, *link, *client) != RPC_SUCCESS) { +#ifdef _DEBUG + printf("%s: error creating link, now client=0x%x link=0x%x\n",__func__,*client,*link); +#endif + clnt_perror(*client, ip); + return -2; + } +#ifdef _DEBUG + printf("%s: created link!!, now client=0x%x link=0x%x\n",__func__,*client,*link); +#endif + return 0; + } + + +/* CLOSE FUNCTIONS * + * =============== */ +int vxi11_close_device(const char *ip, CLIENT *client, VXI11_LINK *link) { +int ret; + + ret = vxi11_close_link(ip, client, link); +#ifdef _DEBUG + printf("%s: going to destroy client...\n",__func__); + printf("%s: going to destroy client=0x%x\n",__func__,client); +#endif + if(!client || !link) + { +#ifdef _DEBUG + printf("%s: NOT EXECUTING clnt_destroy since client=0x%x link=0x%x\n",__func__,client,link); +#endif + return 0; + } + clnt_destroy(client); + + return ret; + } + +int vxi11_close_link(const char *ip, CLIENT *client, VXI11_LINK *link) { +Device_Error dev_error; + memset(&dev_error, 0, sizeof(dev_error)); +#ifdef _DEBUG + printf("%s: going to destroy link...\n",__func__); + printf("%s: going to destroy link-client=0x%x link=0x%x\n",__func__,client,link); +#endif + if(!client || !link) + { +#ifdef _DEBUG + printf("%s: NOT EXECUTING destroy_link_1 since client=0x%x link=0x%x\n",__func__,client,link); +#endif + return 0; + } + if (destroy_link_1(&link->lid, &dev_error, client) != RPC_SUCCESS) { + clnt_perror(client,ip); + return -1; + } + + return 0; + } + + +/* SEND FUNCTIONS * + * ============== */ + +/* A _lot_ of the time we are sending text strings, and can safely rely on + * strlen(cmd). */ +int vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd) { + return vxi11_send(client, link, cmd, strlen(cmd)); + } + +/* We still need the version of the function where the length is set explicitly + * though, for when we are sending fixed length data blocks. */ +int vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd, unsigned long len) { +Device_WriteParms write_parms; +unsigned int bytes_left = len; +char *send_cmd; + + send_cmd = new char[len]; + memcpy(send_cmd, cmd, len); + + write_parms.lid = link->lid; + write_parms.io_timeout = VXI11_DEFAULT_TIMEOUT; + write_parms.lock_timeout = VXI11_DEFAULT_TIMEOUT; + int count=0; + +/* We can only write (link->maxRecvSize) bytes at a time, so we sit in a loop, + * writing a chunk at a time, until we're done. */ + + do { + count++; + Device_WriteResp write_resp; + memset(&write_resp, 0, sizeof(write_resp)); + + if (bytes_left <= link->maxRecvSize) { + write_parms.flags = 8; + write_parms.data.data_len = bytes_left; + } + else { + write_parms.flags = 0; + /* We need to check that maxRecvSize is a sane value (ie >0). Believe it + * or not, on some versions of Agilent Infiniium scope firmware the scope + * returned "0", which breaks Rule B.6.3 of the VXI-11 protocol. Nevertheless + * we need to catch this, otherwise the program just hangs. */ + if (link->maxRecvSize > 0) { + write_parms.data.data_len = link->maxRecvSize; + } + else { + write_parms.data.data_len = 4096; /* pretty much anything should be able to cope with 4kB */ + } + } + write_parms.data.data_val = send_cmd + (len - bytes_left); +#ifdef _DEBUG + printf("%s: bytes_left=%d\n", __func__,bytes_left); +#endif + if(device_write_1(&write_parms, &write_resp, client) != RPC_SUCCESS) { + delete[] send_cmd; + return -VXI11_NULL_WRITE_RESP; /* The instrument did not acknowledge the write, just completely + dropped it. There was no vxi11 comms error as such, the + instrument is just being rude. Usually occurs when the instrument + is busy. If we don't check this first, then the following + line causes a seg fault */ + } + if (write_resp.error != 0) { +#ifdef _DEBUG + printf("vxi11_user: write error: %d\n", (int)write_resp.error); +#endif + delete[] send_cmd; + return -(write_resp.error); + } + bytes_left -= write_resp.size; + } while (bytes_left > 0 && count < 1000); + + delete[] send_cmd; + if(count == 1000) + return -1; + return 0; + } + + +/* RECEIVE FUNCTIONS * + * ================= */ + +// It appeared that this function wasn't correctly dealing with more data available than specified in len. +// This patch attempts to fix this issue. RDP 2007/8/13 + +/* wrapper, for default timeout */ long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len) { return vxi11_receive(client, link, buffer, len, VXI11_READ_TIMEOUT); + } + +#define RCV_END_BIT 0x04 // An end indicator has been read +#define RCV_CHR_BIT 0x02 // A termchr is set in flags and a character which matches termChar is transferred +#define RCV_REQCNT_BIT 0x01 // requestSize bytes have been transferred. This includes a request size of zero. + +long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len, unsigned long timeout) { +Device_ReadParms read_parms; +Device_ReadResp read_resp; +unsigned long curr_pos = 0; + + read_parms.lid = link->lid; + read_parms.requestSize = len; + read_parms.io_timeout = timeout; /* in ms */ + read_parms.lock_timeout = timeout; /* in ms */ + read_parms.flags = 0; + read_parms.termChar = 0; + + int count=0; + + do + { + count++; + memset(&read_resp, 0, sizeof(read_resp)); + + read_resp.data.data_val = buffer + curr_pos; + read_parms.requestSize = len - curr_pos; // Never request more total data than originally specified in len + +#ifdef _DEBUG + printf("%s before device_read_1 requestSize=%d\n", __func__,(int)read_parms.requestSize); +#endif + if(device_read_1(&read_parms, &read_resp, client) != RPC_SUCCESS) + { + return -VXI11_NULL_READ_RESP; /* there is nothing to read. Usually occurs after sending a query + which times out on the instrument. If we don't check this first, + then the following line causes a seg fault */ + } + if (read_resp.error != 0) + { + /* Read failed for reason specified in error code. + * (From published VXI-11 protocol, section B.5.2) + * 0 no error + * 1 syntax error + * 3 device not accessible + * 4 invalid link identifier + * 5 parameter error + * 6 channel not established + * 8 operation not supported + * 9 out of resources + * 11 device locked by another link + * 12 no lock held by this link + * 15 I/O timeout + * 17 I/O error + * 21 invalid address + * 23 abort + * 29 channel already established + */ +#ifdef _DEBUG + printf("vxi11_user: read error: %d\n", (int)read_resp.error); +#endif + return -(read_resp.error); + } + + if((curr_pos + read_resp.data.data_len) <= len) + { + curr_pos += read_resp.data.data_len; + } + else + { + curr_pos = read_resp.data.data_len; + } + if( (read_resp.reason & RCV_END_BIT) || (read_resp.reason & RCV_CHR_BIT) || (read_resp.reason & RCV_REQCNT_BIT)) + { + break; + } + else if( curr_pos == len ) + { +#ifdef _DEBUG + printf("vxi11_user: read error: buffer too small. Read %d bytes without hitting terminator. Response Reason = %d\n", (int)curr_pos, read_resp.reason ); + + for(int i=0; i<len; i++) + printf("vxi11_user: read error: %c-0x%x ", read_resp.data.data_val[i], read_resp.data.data_val[i] ); + printf("\n"); +#endif + return -100; + } + } while(1 && count < 10000); + if(count == 10000) + return -1; + return (curr_pos); /*actual number of bytes received*/ + +} + diff --git a/vxi11_user.h b/vxi11_user.h new file mode 100644 index 0000000..07898e9 --- /dev/null +++ b/vxi11_user.h @@ -0,0 +1,87 @@ +/* vxi11_user.h + * Copyright (C) 2006 Steve D. Sharples + * + * User library for opening, closing, sending to and receiving from + * a device enabled with the VXI11 RPC ethernet protocol. Uses the files + * generated by rpcgen vxi11.x. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The author's email address is steve.sharples@nottingham.ac.uk + */ + +#ifndef __VXI11_USER__ +#define __VXI11_USER__ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rpc/rpc.h> +#include "vxi11.h" + +#define VXI11_DEFAULT_TIMEOUT 10000 /* in ms */ +#define VXI11_READ_TIMEOUT 2000 /* in ms */ +#define VXI11_CLIENT CLIENT +#define VXI11_LINK Create_LinkResp +#define VXI11_MAX_CLIENTS 256 /* maximum no of unique IP addresses/clients */ +#define VXI11_NULL_READ_RESP 50 /* vxi11_receive() return value if a query + * times out ON THE INSTRUMENT (and so we have + * to resend the query again) */ +#define VXI11_NULL_WRITE_RESP 51 /* vxi11_send() return value if a sent command + * times out ON THE INSTURMENT. */ + +struct CLINK { + VXI11_CLIENT *client; + VXI11_LINK *link; + } ; +typedef struct CLINK CLINK; + +/* The four main functions: open, close, send, receieve (plus a couple of wrappers) */ +/* In fact all 6 of these are wrappers to the original functions listed at the + * bottom, that use separate CLIENT and VXI11_LINK structures. It was easier to + * write wrappers for these functions than to re-write the original functions + * themselves. These are the 4 (or 6 if you like) key user functions that you + * should probably be using. They all use the CLINK structure. */ +int vxi11_open_device(const char *ip, CLINK *clink); +int vxi11_open_device(const char *ip, CLINK *clink, char *device); +int vxi11_close_device(const char *ip, CLINK *clink); +int vxi11_send(CLINK *clink, const char *cmd); +int vxi11_send(CLINK *clink, const char *cmd, unsigned long len); +long vxi11_receive(CLINK *clink, char *buffer, unsigned long len); +long vxi11_receive(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout); + +/* Utility functions, that use send() and receive(). Use these too. */ +int vxi11_send_data_block(CLINK *clink, const char *cmd, char *buffer, unsigned long len); +long vxi11_receive_data_block(CLINK *clink, char *buffer, unsigned long len, unsigned long timeout); +long vxi11_send_and_receive(CLINK *clink, const char *cmd, char *buf, unsigned long buf_len, unsigned long timeout); +long vxi11_obtain_long_value(CLINK *clink, const char *cmd, unsigned long timeout); +double vxi11_obtain_double_value(CLINK *clink, const char *cmd, unsigned long timeout); +long vxi11_obtain_long_value(CLINK *clink, const char *cmd); +double vxi11_obtain_double_value(CLINK *link, const char *cmd); + +/* When I first wrote this library I used separate client and links. I've + * retained the original functions and just written clink wrappers for them + * (see above) as it's perhaps a little clearer this way. Probably not worth + * delving this deep in use, but it's where the real nitty gritty is. */ +int vxi11_open_device(const char *ip, CLIENT **client, VXI11_LINK **link, char *device); +int vxi11_open_link(const char *ip, CLIENT **client, VXI11_LINK **link, char *device); +int vxi11_close_device(const char *ip, CLIENT *client, VXI11_LINK *link); +int vxi11_close_link(const char *ip, CLIENT *client, VXI11_LINK *link); +int vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd); +int vxi11_send(CLIENT *client, VXI11_LINK *link, const char *cmd, unsigned long len); +long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len); +long vxi11_receive(CLIENT *client, VXI11_LINK *link, char *buffer, unsigned long len, unsigned long timeout); + +#endif -- GitLab