pax_global_header00006660000000000000000000000064144321171020014505gustar00rootroot0000000000000052 comment=e3a4a019017fe12474453b649d6d02fcfbf39a26 liblxi-1.20/000077500000000000000000000000001443211710200127125ustar00rootroot00000000000000liblxi-1.20/.circleci/000077500000000000000000000000001443211710200145455ustar00rootroot00000000000000liblxi-1.20/.circleci/config.yml000066400000000000000000000021101443211710200165270ustar00rootroot00000000000000# Use the latest 2.1 version of CircleCI pipeline process engine. # See: https://circleci.com/docs/2.0/configuration-reference version: 2.1 # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: build-liblxi: # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor docker: - image: cimg/base:2021.04 # Add steps to the job # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - checkout - run: sudo apt-get -qq update - run: sudo apt-get install -y libtirpc-dev libavahi-common-dev libavahi-client-dev libxml2-dev meson - run: meson build --prefix=$HOME/test/liblxi && ninja -C build install # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: build-liblxi-workflow: jobs: - build-liblxi liblxi-1.20/.gitignore000066400000000000000000000000421443211710200146760ustar00rootroot00000000000000build *.swp .cache .vscode search liblxi-1.20/AUTHORS000066400000000000000000000007131443211710200137630ustar00rootroot00000000000000Maintainer: Martin Lund Contributors: Robert Scheck Jakub Wilk Dima Kogan Dmitri Goutnik zramudzuli Holzapfel Perry Hung Alexander von Gluck IV Rob Carruthers Thanks to everyone who has contributed to this project. liblxi-1.20/LICENSE000066400000000000000000000133521443211710200137230ustar00rootroot00000000000000Unless otherwise *explicitly* stated, liblxi is available for use under the following license, commonly known as the 3-clause (or "modified") BSD license. BSD 3-Clause License Copyright (c) 2016-2022 Martin Lund All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The following files: src/vxi11core.rpcl src/vxi11core_clnt.c (automatically generated from .rpcl using rpcgen) src/vxi11core.h (automatically generated from .rpcl using rpcgen) src/vxi11core.rpcl (automatically generated from .rpcl using rpcgen) src/vxi11core_svc.c (automatically generated from .rpcl using rpcgen) src/vxi11core_xdr.c (automatically generated fomr .rpcl using rpcgen) Are covered by the EPICS license: Copyright (c) 2002 University of Chicago, The Regents of the University of California, and Berliner Elektronenspeicherring Gesellschaft fuer Synchrotronstrahlung m.b.H. (BESSY) All rights reserved. Copyright (c) 2004 by Danfysik and Cosylab (Danfysik has funded the work performed by Cosylab). asynDriver is distributed subject to the following license conditions: SOFTWARE LICENSE AGREEMENT Software: asynDriver 1. The "Software", below, refers to asynDriver (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: a. Copies in source code must include the copyright notice and this Software License Agreement. b. 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: a. Copies in source code must include the copyright notice and this Software License Agreement; b. 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; c. 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. liblxi-1.20/NEWS000066400000000000000000000232311443211710200134120ustar00rootroot00000000000000=== liblxi v1.20 === Changes since liblxi v1.19: Rob Carruthers: * refactor(bonjour): Fix typo & Refine browse default domain * feat(bonjour): Add mdns support for macOS This code is designed to discover LXI (LAN eXtensions for Instrumentation) devices using the Bonjour service (dns_sd.h) discovery protocol. The flow of the implementation is as follows: 1. bonjour_discover(lxi_info_t *info, int timeout_ms) is the entry point of the code. It takes an lxi_info_t struct to store the discovered information and a timeout in milliseconds. It calls the browse_lxi_services() function with these parameters. The lxi_info_t is setup with callbacks to initially to recieve the discovered instrument data. See test folder for examples. 2. lxi_info_t struct is defined in lxi.h. browse_lxi_services(lxi_info_t *info, int timeout_ms) iterates through lxi_services (defined in lxi.h) and calls the Bonjour DNSServiceBrowse() function for each service. It then processes the results and sets a timeout to stop waiting for results after a specified duration. It provides the browse_callback() function as a callback. 3. browse_callback() is called for each discovered service. It extracts relevant information about the service and then creates a browse_data_t struct to aggregate service data. It calls DNSServiceResolve() to resolve the service's hostname, and provides resolve_callback() as a callback. 4. resolve_callback() is called once the service hostname is resolved. It calls the resolve_ip_address() function to convert the hostname into an IP address. It also extracts more information about the service and then calls the info->service() callback function with the discovered service's information. Finally, it frees the memory allocated for the browse_data_t struct. 5. resolve_ip_address() takes a hostname and port, and converts them into an IP address using the getaddrinfo() function. The resulting IP address is stored in the provided buffer. Service types and labels are declared in the lxi_services array in src/lxc.c Changes since liblxi v1.18: * Silence cast of function type in autogenerated vxi11 code * Add test example demonstrating how to use RAW protocol Rob Carruthers: * Docs: Update README with Homebrew installation instructions * macOS: Build support * macOS: Add check for RPC headers * macOS: Remove libtirpc dependency during build process Changes since liblxi v1.17: Alexander von Gluck IV: * build: make avahi optional again after meson conversion * matches readme again * liblxi is still usable, but it definitely takes some of the fun out of it. * vxi11: Drop non-portable pthread timeout call; solves #30 * Convert to manually constructing a timedjoin wrapper which should work outside of Linux * Tested functional Changes since liblxi v1.16: Perry Hung: * vxi11: do not fail on zero length messages Zero length messages are valid replies in VXI-11. Do not return an error and prematurely exit. Reads should be repeated until EOI or an error is encountered. Holzapfel: * Fixed missing VXI11 connect-abort multithreading synchronization * Fixed LXI connect error memory leak Changes since liblxi v1.15: * Fix handling of send errors for TCP/RAW connections Changes since liblxi v1.14: * Fix meson libtirpc dependency Remove the hardcoded include patch to libtirpc and replace it with one dynamically resolved via pkg-config. The reason for implementing the meson dependency check this way is to avoid linking with libtirpc because it is broken with regards to its Sun RPC implementation so instead we link with the RPC implementation which still reside in glibc. However, glibc removed their RPC header files so we need the headers from libtirpc. Further investigation is required to find and fix the bug in the libtirpc RPC implementation so we can get back to normal. They changed something moving it out of glibc and they shouldn't have. Changes since liblxi v1.13: * Add lxi_discover_if() function Works exactly like the lxi_discover() function but adds an additional parameter ifname that specifies which network interface to broadcast on in case of using the DISCOVER_VXI11 discovery type. * Bypass linking with libtirpc because of bug When linking with libtirpc some of the VXI11 connect calls starts failing for some instruments. More investigation is needed to find out exactly why. It may be some regression in the libtirpc Sun RPC implementation. The Sun RPC features have recently been moved out of glibc into libtirpc. When we do not link with libtirpc we fallback to using glibc's implementation of the RPC features which seem to work better. We will accept this hack for now. * Remove include directory * Reduce compiler optimization level * Introduce proper Avahi timeout handling for mDNS * Increase number of allowed concurrent sessions * Fix timeout for VXI11 connect The VXI11 API does not provide any way to specify a communications timeout when connecting. To fix that we move the VXI11 connect action into a separate thread that is killed if the timeout is reached before the thread exits. The old behavior was that the connect action would eventually time out for instruments on known subnets. However, if you tried to connect to an instrument on an unknown subnet it would stall forever. This new implementation will respect the timeout for all cases. * Replace autotools with meson zramudzuli: * Added timeout for RAW/TCP connections Changes since liblxi v1.12: * Fix Sun RPC headers configure check The Sun RPC headers have been moved out of glibc into a separate library, libtirpc. Hence, check for glibc headers first and in case that fails search for headers in libtirpc via pkg-config. * Add const qualifier Because it is the right thing to do. * Update Travis * Use libtirpc for Sun RPC headers * Move test directory Changes since liblxi v1.11: * Add send/receive sanity checks * Strip CR from ID response string Fixes corrupted output from 'lxi discover'. Changes since liblxi v1.10: * Fix mDNS/DNS-SD discover feature Changes since liblxi v1.9: * Update Travis * Cleanup * Add --disable-avahi configure option Makes avahi mandatory unless --disable-avahi is provided. Changes since liblxi v1.8: * Update AUTHORS * Convert tabs to spaces * Make API usable in C++ As suggested by Dima Kogan, lets wrap the API so that it is usable in C++. * Only export lxi API specific functions Hide visibility of internal functions so that only the lxi API specific ones are exported/visible to applications linking with liblxi. These changes are applied on behalf of Dima Kogan. * Add discover fallback to request ID via HTTP/XML If retrieving the instrument ID fails via VXI-11 during discovery then try to retrieve the ID via the /lxi/identification XML file hosted by some instruments via HTTP. Adds dependency on libxml2. Dmitri Goutnik: * Make code clang friendly, fix warnings Changes since liblxi v1.7: * Fix lxi_connect() so it does not apply lock Some instruments fail to lock for exclusive access when creating a VXI-11 connection. So, to play it safe, we will simply not try to lock when setting up the connection. Changes since liblxi v1.6: * Update to new URL * Update README * Update AUTHORS * Use HTTPS in the configure script Jakub Wilk: * Fix typos Changes since liblxi v1.5: * Update README * Add authors section in README * Add README.md to prettify GitHub page Changes since liblxi v1.4: * Add support for mDNS/DNS-SD discovery Add parameter to lxi_discover() so it is possible to select discovery using VXI-11 or mDNS/DNS-SD. If detected available, Avahi is used as the mDNS/DNS-SD backend implementation. * Print errors to stderr * Update README Changes since liblxi v1.3: * Fix discover output strings Discovery of multiple LXI instruments revealed a bug in the id string handling which results in garbled output strings. Adding missing string termination fixes this. * Add timeout handling for raw/TCP * Update examples * Cleanup * Update README * Add support for configurable protocol backends Reworked the code to support configurable protocol backends. Currently supported protocols include VXI11 and raw TCP. In the future support for HiSlip can be added. Changes since liblxi v1.2: * Fix building with multiple jobs (make -jN, N>1) * Update README Changes since liblxi v1.1: * Added AUTHORS file * Update COPYING * Update README * Update connect test * Improve lxi_connect() with device name and timeout * Make timeout error message human readable Lets explain the most common error, that is timeout, in a human readable format. * Fix timeout handling * Use thread-safe version of VXI11 function calls * Autogenerate VXI11 RPC functions Automatically generate VXI11 RPC functions instead of using bundled or system provided VXI11 library. This allows us to generate thread-safe versions of the VXI11 RPC functions in the future. Changes since liblxi v1.0: * Fixed instrument not responding Use the default LAN Device Name of "inst0". Some instruments do not respond if this device name is not used. * Remove unused rpcgen tool check * Cleanup rpc header check * Add support for use of system VXI library Added configure option '--with-vxi=[internal/system]' which allows the user to decide whether to use the internally bundled VXI library or the VXI library provided by the system. By default the internal VXI library is used. liblxi v1.0: * First release (stable) liblxi-1.20/README.md000066400000000000000000000117571443211710200142040ustar00rootroot00000000000000# liblxi [![](https://img.shields.io/circleci/build/github/lxi-tools/liblxi)](https://circleci.com/gh/lxi-tools/liblxi/tree/master) [![](https://img.shields.io/github/v/release/lxi-tools/liblxi?sort=semver)](https://github.com/lxi-tools/liblxi/releases) [![](https://img.shields.io/repology/repositories/liblxi)](https://repology.org/project/liblxi/versions) [![](https://img.shields.io/tokei/lines/github/lxi-tools/liblxi)](https://github.com/lxi-tools/liblxi) ## 1. Introduction liblxi is an open source software library which offers a simple API for communicating with LXI compatible instruments. The API allows applications to discover instruments on your network, send SCPI commands, and receive responses. Currently the library supports VXI-11/TCP and RAW/TCP connections. Future work include adding support for the newer and more efficient HiSlip protocol which is used by next generation LXI instruments. The library is based on the VXI-11 RPC protocol implementation which is part of the asynDriver EPICS module, which, at time of writing, is available [here](http://www.aps.anl.gov/epics/modules/soft/asyn/index.html). ### 1.1 What is LXI? LAN eXtensions for Instrumentation (LXI) is a standard developed by the LXI Consortium, an industry consortium that maintains the LXI specification and promotes the LXI Standard. The LXI standard defines the communication protocols for modern instrumentation and data acquisition systems using Ethernet. Visit www.lxistandard.org for more details. Please notice that liblxi is not affiliated with the LXI consortium - it is an independent open source community effort. ## 2. The liblxi API The API is small and simple. It includes functions required for discovering and communicating SCPI messages with LXI devices: ``` int lxi_init(void); int lxi_discover(struct lxi_info_t *info, int timeout, lxi_discover_t type); int lxi_connect(const char *address, int port, const char *name, int timeout, lxi_protocol_t protocol); int lxi_send(int device, const char *message, int length, int timeout); int lxi_receive(int device, char *message, int length, int timeout); int lxi_disconnect(int device); ``` Note: `type` is `DISCOVER_VXI11` or `DISCOVER_MDNS` Note: `protocol` is `VXI11` or `RAW` ## 3. API usage Here is a simple code example on how to use the liblxi API: ``` #include #include #include int main() { char response[65536]; int device, length, timeout = 1000; char *command = "*IDN?"; // Initialize LXI library lxi_init(); // Connect to LXI device device = lxi_connect("10.42.0.42", 0, "inst0", timeout, VXI11); // Send SCPI command lxi_send(device, command, strlen(command), timeout); // Wait for response lxi_receive(device, response, sizeof(response), timeout); printf("%s\n", response); // Disconnect lxi_disconnect(device); } ``` The example above prints the ID string of the LXI instrument. For example, a Rigol DS1104Z oscilloscope would respond: ``` RIGOL TECHNOLOGIES,DS1104Z,DS1ZA1234567890,00.04.03 ``` See src/test for more examples. ## 4. Installation ### 4.1 Installation from source The latest source releases can be found [here](https://github.com/lxi-tools/liblxi/releases). To compile and install successfully from source you need to install the following dependencies: * libtirpc * libxml2 * avahi (optional) Install steps: ``` $ meson setup build $ meson compile -C build $ meson install -C build ``` Note: Please do no try to install from source if you are not familiar with using meson. ### 4.2 Installation using package manager (Linux) liblxi comes prepackaged for various GNU/Linux distributions. Please consult your package manager tool to find and install lxi-tools. If you would like to see liblxi included in your favorite distribution, please reach out to its package maintainers team. ### 4.3 Installation using Homebrew (MacOS, Linux) If you have [Homebrew](https://brew.sh) installed: ``` shell $ brew install liblxi ``` ## 5. Contributing liblxi is open source. If you want to help out with the project please feel free to join in. All contributions (bug reports, code, doc, ideas, etc.) are welcome. Please use the github issue tracker and pull request features. Also, if you find this free open source software useful please feel free to consider making a donation of your choice: [![Donate](https://raw.githubusercontent.com/lxi-tools/lxi-tools/master/images/Paypal.png)](https://www.paypal.me/lundmar) ## 6. Website Visit [lxi-tools.github.io](https://lxi-tools.github.io) ## 7. License liblxi includes code covered by the following licenses: * BSD-3, commonly known as the 3-clause (or "modified") BSD license * EPICS Open software license For license details please see the COPYING file. ## 8. Authors Created by Martin Lund \ See the AUTHORS file for full list of contributors. liblxi-1.20/man/000077500000000000000000000000001443211710200134655ustar00rootroot00000000000000liblxi-1.20/man/lxi_connect.3.in000066400000000000000000000015071443211710200164660ustar00rootroot00000000000000.TH "lxi_connect" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_connect \- connect to LXI device .SH "SYNOPSIS" .PP .B #include .B int lxi_connect(char *address, int port, char *name, int timeout, lxi_protocol_t protocol); .SH "DESCRIPTION" .PP The .BR lxi_connect() function connects to a LXI device with .I name at IP address pointed to by .I address .PP If .I name is NULL then the default name "inst0" will be used. .PP .I protocol is either VXI11 or RAW. .PP If .I protocol is RAW then .I port will be used as destination port. .PP The .I timeout is in milliseconds. .SH "RETURN VALUE" Upon successful completion .BR lxi_connect() returns a new connection handle, or .BR LXI_ERROR if an error occurred. .SH "SEE ALSO" .BR lxi_send (3), .BR lxi_receive (3), .BR lxi_disconnect (3), liblxi-1.20/man/lxi_disconnect.3.in000066400000000000000000000010711443211710200171620ustar00rootroot00000000000000.TH "lxi_disconnect" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_disconnect \- disconnect a LXI connection .SH "SYNOPSIS" .PP .B #include .B int lxi_disconnect(int device); .SH "DESCRIPTION" .PP The .BR lxi_disconnect() function disconnects an existing LXI connection handle pointed to by .I device .SH "RETURN VALUE" Upon successful completion .BR lxi_disconnect() returns .BR LXI_OK , else .BR LXI_ERROR is returned if an error occurred. .SH "SEE ALSO" .BR lxi_send (3), .BR lxi_receive (3), .BR lxi_disconnect (3), liblxi-1.20/man/lxi_discover.3.in000066400000000000000000000043041443211710200166510ustar00rootroot00000000000000.TH "lxi_discover" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_discover \- search for LXI devices on network .SH "SYNOPSIS" .PP .B #include .B int lxi_discover(lxi_info_t *info, int timeout, lxi_discover_t type); .SH "DESCRIPTION" .PP The .BR lxi_discover() function searches for LXI devices or services on the local network using VXI-11 or mDNS/DNS-SD respectively. Which discover .I type is used is defined as follows: .sp .nf typedef enum { DISCOVER_VXI11, DISCOVER_MDNS } lxi_discover_t; .fi .PP During the discover operation events and results are returned by callbacks registered via the .I info structure, defined as follows: .sp .nf typedef struct { void (*broadcast)(char *address, char *interface); void (*device)(char *address, char *id); void (*service)(char *address, char *id, char *service, int port); } lxi_info_t; .fi .PP The .I broadcast callback is called whenever a new network interface is searched (DISCOVER_VXI11 only). The .I device callback is called whenever a new LXI device is found (DISCOVER_VXI11 only). The .I service callback is called whenever a new LXI service is found (DISCOVER_MDNS only). .PP The .I timeout is in milliseconds. .SH "RETURN VALUE" Upon successful completion .BR lxi_discover() returns .BR LXI_OK , or .BR LXI_ERROR if an error occurred. .SH EXAMPLE .PP The following example searches for LXI devices using VXI-11 and prints the ID and IP addresses of found devices: .nf #include #include void broadcast(char *address, char *interface) { printf("Broadcasting on interface %s\\n", interface); } void device(char *address, char *id) { printf(" Found %s on address %s\\n", id, address); } int main() { lxi_info_t info; // Initialize LXI library lxi_init(); // Set up search information callbacks info.broadcast = &broadcast; info.device = &device; printf("Searching for LXI devices - please wait...\\n"); // Search for LXI devices, 1 second timeout lxi_discover(&info, 1000, DISCOVER_VXI11); return 0; } .fi .SH "SEE ALSO" .BR lxi_discover_if (3) .BR lxi_init (3) .BR lxi_open (3), .BR lxi_close (3) .BR lxi_receive (3), .BR lxi_disconnect (3), liblxi-1.20/man/lxi_discover_if.3.in000066400000000000000000000012451443211710200173300ustar00rootroot00000000000000.TH "lxi_discover_if" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_discover_if \- search for LXI devices on network via specified network interface .SH "SYNOPSIS" .PP .B #include .B int lxi_discover_if(lxi_info_t *info, const char *ifname, int timeout, lxi_discover_t type); .SH "DESCRIPTION" .PP The .BR lxi_discover_if() function works exactly like .BR lxi_discover() but adds an additional parameter .I ifname which specifies the name of the network interface to broadcast on when using the .I DISCOVER_VXI11 discovery type. The .I ifname parameter is ignored for other discovery types. .fi .SH "SEE ALSO" .BR lxi_discover (3) liblxi-1.20/man/lxi_init.3.in000066400000000000000000000010621443211710200157740ustar00rootroot00000000000000.TH "lxi_init" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_init \- initialize LXI library .SH "SYNOPSIS" .PP .B #include .B int lxi_init(void); .SH "DESCRIPTION" .PP The .BR lxi_init() function initializes the LXI library. This is required before calling any other available lxi functions. .SH "RETURN VALUE" Upon successful completion .BR lxi_init() returns .BR LXI_OK , or .BR LXI_ERROR if an error occurred. .SH "SEE ALSO" .BR lxi_connect (3), .BR lxi_send (3), .BR lxi_receive (3), .BR lxi_disconnect (3), liblxi-1.20/man/lxi_receive.3.in000066400000000000000000000012251443211710200164540ustar00rootroot00000000000000.TH "lxi_receive" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_receive \- receive message from LXI device .SH "SYNOPSIS" .PP .B #include .B int lxi_receive(int device, char *message, int length, int timeout); .SH "DESCRIPTION" .PP The . .BR lxi_receive() function receives up to .I length bytes in the message buffer pointed to by .I message .PP The .I timeout is in milliseconds. .SH "RETURN VALUE" Upon successful completion .BR lxi_receive() returns the number of bytes successfully received, or .BR LXI_ERROR if an error occurred. .SH "SEE ALSO" .BR lxi_open (3), .BR lxi_send (3), .BR lxi_disconnect (3), liblxi-1.20/man/lxi_send.3.in000066400000000000000000000011671443211710200157700ustar00rootroot00000000000000.TH "lxi_send" "3" "@version_date@" "liblxi @version@" "C Library Functions" .SH "NAME" lxi_send \- send message to LXI device .SH "SYNOPSIS" .PP .B #include .B int lxi_send(int device, char *message, int length, int timeout); .SH "DESCRIPTION" .PP The .BR lxi_send() function sends .I length bytes from the message buffer pointed to by .I message .PP The .I timeout is in milliseconds. .SH "RETURN VALUE" Upon successful completion .BR lxi_send() returns the number of bytes successfully sent, or .BR LXI_ERROR if an error occurred. .SH "SEE ALSO" .BR lxi_open (3), .BR lxi_receive (3), .BR lxi_disconnect (3), liblxi-1.20/man/meson.build000066400000000000000000000027231443211710200156330ustar00rootroot00000000000000mandir = join_paths(get_option('prefix'), get_option('mandir')) man3dir = join_paths(mandir, 'man3') conf = configuration_data() conf.set('version', meson.project_version()) conf.set('version_date', version_date) manpage_lxi_connect = configure_file( input: files('lxi_connect.3.in'), output: 'lxi_connect.3', configuration: conf, ) manpage_lxi_disconnect = configure_file( input: files('lxi_disconnect.3.in'), output: 'lxi_disconnect.3', configuration: conf, ) manpage_lxi_discover = configure_file( input: files('lxi_discover.3.in'), output: 'lxi_discover.3', configuration: conf, ) manpage_lxi_discover_if = configure_file( input: files('lxi_discover_if.3.in'), output: 'lxi_discover_if.3', configuration: conf, ) manpage_lxi_init = configure_file( input: files('lxi_init.3.in'), output: 'lxi_init.3', configuration: conf, ) manpage_lxi_receive = configure_file( input: files('lxi_receive.3.in'), output: 'lxi_receive.3', configuration: conf, ) manpage_lxi_send = configure_file( input: files('lxi_send.3.in'), output: 'lxi_send.3', configuration: conf, ) manpages = [ manpage_lxi_connect, manpage_lxi_disconnect, manpage_lxi_init, manpage_lxi_discover, manpage_lxi_discover_if, manpage_lxi_receive, manpage_lxi_send, ] install_man( manpages, install_dir: man3dir, ) liblxi-1.20/meson.build000066400000000000000000000010261443211710200150530ustar00rootroot00000000000000project('liblxi', 'c', version : '1.20', license : [ 'BSD-3-Clause'], meson_version : '>= 0.53.2', default_options : [ 'warning_level=2', 'buildtype=release', 'c_std=gnu11', 'optimization=2', 'b_lundef=false' ] ) # The tag date of the project_version(), update when the version bumps. version_date='2022-09-28' subdir('src') subdir('man') pkg_mod = import('pkgconfig') pkg_mod.generate(libraries : liblxi, name : 'liblxi', filebase : 'liblxi', description : 'A Library for managing LXI compatible test instruments' ) liblxi-1.20/search_mdns000077500000000000000000001015101443211710200151240ustar00rootroot00000000000000 ` H__PAGEZERO__TEXT@@__text__TEXT>>__stubs__TEXT?$? __cstring__TEXT4?4?__unwind_info__TEXT?H?__DATA_CONST@@@@__got__DATA_CONST@@H__LINKEDIT@H430@h P( /usr/lib/dyld3>^?[v_p)HX2   Y*(> @/opt/homebrew/lib/liblxi.1.dylib 8d'/usr/lib/libSystem.B.dylib&){R<C9a; <4@}R"R*@{C_C{C__^C^ ,+* ( ={DC_{ @(`> {B_@@ @Searching for LXI devices - please wait... Found "%s" on address %s %s service on port %u Broadcasting on interface %s >44?4  P\@@2_lxi_discover_lxi_init_printf_ _mh_execute_headermain%||h\<|>N>>*4 __mh_execute_header_main_lxi_discover_lxi_init_printf_service_callback_broadcast_callback  dX  @search_mdnsOF.E'_RDj)BUj,%*XofkOX||zڽH,XofkOX||zڽH,nHA@XHErzet~;rA.ʁѰI& 銾XofkOX||zڽH,XofkOX||zڽH,XofkOX||zڽH,2pG'g>]Tܚ(7liblxi-1.20/src/000077500000000000000000000000001443211710200135015ustar00rootroot00000000000000liblxi-1.20/src/avahi.c000066400000000000000000000173531443211710200147460ustar00rootroot00000000000000/* * Copyright (c) 2017-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "avahi.h" static AvahiSimplePoll *simple_poll = NULL; static const AvahiPoll *poll_api = NULL; static AvahiServiceBrowser *sb[10] = {}; static lxi_info_t *lxi_info; static int count = 0; static void avahi_resolve_callback( AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, AVAHI_GCC_UNUSED void* userdata) { assert(r); /* Called whenever a service has been resolved successfully or timed out */ switch (event) { case AVAHI_RESOLVER_FAILURE: error_printf("Avahi failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); break; case AVAHI_RESOLVER_FOUND: { char addr[AVAHI_ADDRESS_STR_MAX] = "Unknown"; char *service_type = "Unknown"; // Pretty print service type if (strcmp(type, "_lxi._tcp") == 0) service_type = "lxi"; else if (strcmp(type, "_vxi-11._tcp") == 0) service_type = "vxi-11"; else if (strcmp(type, "_scpi-raw._tcp") == 0) service_type = "scpi-raw"; else if (strcmp(type, "_scpi-telnet._tcp") == 0) service_type = "scpi-telnet"; else if (strcmp(type, "_hislip._tcp") == 0) service_type = "hislip"; avahi_address_snprint(addr, sizeof(addr), address); if (lxi_info->service != NULL) lxi_info->service(addr, (char *) name, service_type, port); } } avahi_service_resolver_free(r); } static void avahi_browse_callback( AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { AvahiClient *c = userdata; assert(b); /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ switch (event) { case AVAHI_BROWSER_FAILURE: error_printf("(Avahi) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); avahi_simple_poll_quit(simple_poll); return; case AVAHI_BROWSER_NEW: if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_INET, 0, avahi_resolve_callback, c))) error_printf("Avahi failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); break; case AVAHI_BROWSER_REMOVE: case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: break; } } static void avahi_client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) { assert(c); /* Called whenever the client or server state changes */ if (state == AVAHI_CLIENT_FAILURE) { error_printf("Avahi server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); avahi_simple_poll_quit(simple_poll); } } static int create_service_browser(AvahiClient *client, char *service) { if (!(sb[count++] = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, service, NULL, 0, avahi_browse_callback, client))) { error_printf("Failed to create Avahi service browser: %s\n", avahi_strerror(avahi_client_errno(client))); return 1; } return 0; } static void avahi_terminate(AVAHI_GCC_UNUSED AvahiTimeout *timeout, AVAHI_GCC_UNUSED void *userdata) { avahi_simple_poll_quit(simple_poll); } int avahi_discover(lxi_info_t *info, int timeout) { AvahiClient *client = NULL; struct timeval tv; int status = 1; int error; /* Setup callback structure and timeout for avahi service callback */ lxi_info = info; /* Allocate main loop object */ simple_poll = avahi_simple_poll_new(); if (!simple_poll) { error_printf("Failed to create simple Avahi poll object.\n"); goto fail; } /* Get poll API object for configuration of Avahi poll loop */ poll_api = avahi_simple_poll_get(simple_poll); if (!poll_api) { error_printf("Failed to create Avahi poll API object.\n"); goto fail; } /* Allocate a new client */ client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, avahi_client_callback, NULL, &error); if (!client) { error_printf("Failed to create Avahi client: %s\n", avahi_strerror(error)); goto fail; } /* Create the service browsers */ if (create_service_browser(client, "_lxi._tcp")) goto fail_sb; if (create_service_browser(client, "_vxi-11._tcp")) goto fail_sb; if (create_service_browser(client, "_scpi-raw._tcp")) goto fail_sb; if (create_service_browser(client, "_scpi-telnet._tcp")) goto fail_sb; if (create_service_browser(client, "_hislip._tcp")) goto fail_sb; // Set timeout avahi_elapse_time(&tv, timeout, 0); poll_api->timeout_new(poll_api, &tv, avahi_terminate, NULL); /* Run the main Avahi loop */ avahi_simple_poll_loop(simple_poll); status = 0; fail_sb: while (--count >= 0) { avahi_service_browser_free(sb[count]); } fail: if (client) avahi_client_free(client); if (simple_poll) avahi_simple_poll_free(simple_poll); return status; } liblxi-1.20/src/avahi.h000066400000000000000000000032221443211710200147410ustar00rootroot00000000000000/* * Copyright (c) 2017-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef AVAHI_H #define AVAHI_H #include int avahi_discover(lxi_info_t *info, int timeout); #endif liblxi-1.20/src/bonjour.c000066400000000000000000000117211443211710200153250ustar00rootroot00000000000000#include #include #include #include #include #include #include "lxi.h" typedef struct { lxi_info_t *info; char *servicename; char *regtype; } browse_data_t; void resolve_ip_address(const char *hostname, uint16_t port, char *ip_address) { struct addrinfo hints, *servinfo, *p; char port_str[6]; sprintf(port_str, "%u", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; getaddrinfo(hostname, port_str, &hints, &servinfo); for (p = servinfo; p != NULL; p = p->ai_next) { struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; inet_ntop(p->ai_family, &(ipv4->sin_addr), ip_address, INET_ADDRSTRLEN); break; } freeaddrinfo(servinfo); } void resolve_callback( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) { if (errorCode != kDNSServiceErr_NoError) { fprintf(stderr, "Bonjour Resolve Callback, DNSServiceErrorType %d", errorCode); return; } char ip_address[INET_ADDRSTRLEN]; resolve_ip_address(hosttarget, port, ip_address); browse_data_t *browse_data = (browse_data_t *)context; lxi_info_t *info = (lxi_info_t *)browse_data->info; // Pretty print service type const char *service_type = "Unknown"; for (lxi_service_t *s = lxi_services; s->broadcast_type != NULL; s++) { if (strcmp(browse_data->regtype, s->broadcast_type) == 0) { service_type = s->service_name; break; } } info->service(ip_address, browse_data->servicename, service_type, ntohs(port)); free(browse_data->regtype); free(browse_data->servicename); free(browse_data); } void browse_callback( DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) { if (errorCode != kDNSServiceErr_NoError) { fprintf(stderr, "Bonjour browse Callback, DNSServiceErrorType %d", errorCode); return; } char if_name[IF_NAMESIZE]; if_indextoname((unsigned int)interfaceIndex, if_name); lxi_info_t *info = (lxi_info_t *)context; info->broadcast(serviceName, if_name); browse_data_t *browse_data = (browse_data_t *)malloc(sizeof(browse_data_t)); if (!browse_data) { printf("Browse data struct memory allocation failed\n"); return; } browse_data->info = info; browse_data->servicename = strdup(serviceName); browse_data->regtype = strdup(regtype); DNSServiceRef resolveService; DNSServiceErrorType error; error = DNSServiceResolve(&resolveService, 0, interfaceIndex, serviceName, regtype, replyDomain, resolve_callback, browse_data); if (error != kDNSServiceErr_NoError) { fprintf(stderr, "DNSServiceResolve() failed: %d", error); return; } error = DNSServiceProcessResult(resolveService); if (error != kDNSServiceErr_NoError) { fprintf(stderr, "DNSServiceProcessResult() failed: %d", error); return; } DNSServiceRefDeallocate(resolveService); } void browse_lxi_services(lxi_info_t *info, int timeout_ms) { DNSServiceRef service; DNSServiceErrorType error; struct timeval timeout; timeout.tv_sec = timeout_ms / 1000; // convert milliseconds to seconds timeout.tv_usec = (timeout_ms % 1000) * 1000; // remainder in microseconds for (lxi_service_t *s = lxi_services; s->broadcast_type != NULL; s++) { error = DNSServiceBrowse(&service, 0, 0, s->broadcast_type, NULL, browse_callback, info); if (error != kDNSServiceErr_NoError) { fprintf(stderr, "DNSServiceBrowse() failed: %d\n", error); return; } int dns_sd_fd = DNSServiceRefSockFD(service); int nfds = dns_sd_fd + 1; fd_set readfds; FD_ZERO(&readfds); FD_SET(dns_sd_fd, &readfds); int result = select(nfds, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout); if (result > 0) { error = DNSServiceProcessResult(service); if (error != kDNSServiceErr_NoError) { fprintf(stderr, "DNSServiceProcessResult() failed: %d\n", error); return; } } else if (result == 0) { fprintf(stderr, "DNSServiceProcessResult() timed out\n"); return; } else { fprintf(stderr, "select() failed\n"); return; } } DNSServiceRefDeallocate(service); } void bonjour_discover(lxi_info_t *info, int timeout_ms) { browse_lxi_services(info, timeout_ms); } liblxi-1.20/src/bonjour.h000066400000000000000000000002011443211710200153210ustar00rootroot00000000000000#ifndef BONJOUR_H #define BONJOUR_H #include int bonjour_discover(lxi_info_t *info, int timeout); #endif // BONJOUR_H liblxi-1.20/src/error.h000066400000000000000000000032441443211710200150060ustar00rootroot00000000000000/* * Copyright (c) 2017-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ERROR_H #define ERROR_H #define error_printf(format, args...) \ fprintf(stderr, "Error: " format, ## args) #endif liblxi-1.20/src/lxi.c000066400000000000000000000144511443211710200144460ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "error.h" #include "session.h" #include "vxi11.h" #include "tcp.h" #include "mdns.h" #define EXPORT __attribute__((visibility("default"))) static struct session_t session[SESSIONS_MAX] = {}; static pthread_mutex_t session_mutex = PTHREAD_MUTEX_INITIALIZER; lxi_service_t lxi_services[] = { {"_lxi._tcp.", "lxi"}, {"_vxi-11._tcp.", "vxi-11"}, {"_scpi-raw._tcp.", "scpi-raw"}, {"_scpi-telnet._tcp.", "scpi-telnet"}, {"_hislip._tcp.", "hislip"}, {NULL, NULL}}; EXPORT int lxi_init(void) { int i; // Initialize session structures for (i = 0; i < SESSIONS_MAX; i++) { session[i].allocated = false; session[i].connected = false; } return LXI_OK; } EXPORT int lxi_connect(const char *address, int port, const char *name, int timeout, lxi_protocol_t protocol) { bool session_available = false; int i; pthread_mutex_lock(&session_mutex); // Find a free session entry for (i = 0; i < SESSIONS_MAX; i++) { if (session[i].allocated == false) { session_available = true; break; } } // Return error if no session can be allocated if (session_available == false) { error_printf("Too many active sessions!\n"); goto error_session; } // Set up protocol backend switch (protocol) { case VXI11: session[i].connect = vxi11_connect; session[i].send = vxi11_send; session[i].receive = vxi11_receive; session[i].disconnect = vxi11_disconnect; session[i].data = malloc(sizeof(vxi11_data_t)); break; case RAW: session[i].connect = tcp_connect; session[i].send = tcp_send; session[i].receive = tcp_receive; session[i].disconnect = tcp_disconnect; session[i].data = malloc(sizeof(tcp_data_t)); break; case HISLIP: // Error: Not yet supported goto error_protocol; break; default: // Error: Unknown protocol goto error_protocol; break; } // Connect if (session[i].connect(session[i].data, address, port, name, timeout) != 0) goto error_connect; session[i].allocated = true; session[i].connected = true; pthread_mutex_unlock(&session_mutex); // Return session handle return i; error_connect: if (session[i].data) free(session[i].data); error_protocol: error_session: pthread_mutex_unlock(&session_mutex); return LXI_ERROR; } EXPORT int lxi_disconnect(int device) { if (device > SESSIONS_MAX) return LXI_ERROR; pthread_mutex_lock(&session_mutex); // Disconnect if (session[device].connected) session[device].disconnect(session[device].data); // Free resources free(session[device].data); session[device].connected = false; session[device].allocated = false; pthread_mutex_unlock(&session_mutex); return LXI_OK; } EXPORT int lxi_send(int device, const char *message, int length, int timeout) { int bytes_sent; if (device < 0) return LXI_ERROR; if (session[device].connected == false) return LXI_ERROR; // Send bytes_sent = session[device].send(session[device].data, message, length, timeout); if (bytes_sent < 0) return LXI_ERROR; // Return number of bytes sent return bytes_sent; } EXPORT int lxi_receive(int device, char *message, int length, int timeout) { int bytes_received; if (device < 0) return LXI_ERROR; if (session[device].connected == false) return LXI_ERROR; // Receive bytes_received = session[device].receive(session[device].data, message, length, timeout); if (bytes_received < 0) return LXI_ERROR; // Return number of bytes received return bytes_received; } EXPORT int lxi_discover(lxi_info_t *info, int timeout, lxi_discover_t type) { switch (type) { case DISCOVER_VXI11: vxi11_discover(info, timeout); break; case DISCOVER_MDNS: mdns_discover(info, timeout); break; default: error_printf("Unknown discover type (%d)\n", type); return LXI_ERROR; } return LXI_OK; } EXPORT int lxi_discover_if(lxi_info_t *info, const char *ifname, int timeout, lxi_discover_t type) { switch (type) { case DISCOVER_VXI11: if (ifname == NULL) vxi11_discover(info, timeout); else vxi11_discover_if(info, ifname, timeout); break; case DISCOVER_MDNS: mdns_discover(info, timeout); break; default: error_printf("Unknown discover type (%d)\n", type); return LXI_ERROR; } return LXI_OK; } liblxi-1.20/src/lxi.h000066400000000000000000000053761443211710200144610ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LXI_H #define LXI_H #ifdef __cplusplus extern "C" { #endif #define LXI_OK 0 #define LXI_ERROR -1 typedef struct { const char *broadcast_type; const char *service_name; } lxi_service_t; extern lxi_service_t lxi_services[]; typedef struct { void (*broadcast)(const char *address, const char *interface); void (*device)(const char *address, const char *id); void (*service)(const char *address, const char *id, const char *service, int port); } lxi_info_t; typedef enum { VXI11, RAW, HISLIP } lxi_protocol_t; typedef enum { DISCOVER_VXI11, DISCOVER_MDNS } lxi_discover_t; int lxi_init(void); int lxi_discover(lxi_info_t *info, int timeout, lxi_discover_t type); int lxi_discover_if(lxi_info_t *info, const char *ifname, int timeout, lxi_discover_t type); int lxi_connect(const char *address, int port, const char *name, int timeout, lxi_protocol_t protocol); int lxi_send(int device, const char *message, int length, int timeout); int lxi_receive(int device, char *message, int length, int timeout); int lxi_disconnect(int device); #ifdef __cplusplus } #endif #endif liblxi-1.20/src/mdns.c000066400000000000000000000035661443211710200146200ustar00rootroot00000000000000/* * Copyright (c) 2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #ifdef HAVE_AVAHI #include "avahi.h" #endif #ifdef HAVE_BONJOUR #include "bonjour.h" #endif int mdns_discover(lxi_info_t *info, int timeout) { #ifdef HAVE_AVAHI return avahi_discover(info, timeout); #elif defined(HAVE_BONJOUR) return bonjour_discover(info, timeout); #else return 0; #endif } liblxi-1.20/src/mdns.h000066400000000000000000000031751443211710200146210ustar00rootroot00000000000000/* * Copyright (c) 2017-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MDNS_H #define MDNS_H int mdns_discover(lxi_info_t *info, int timeout); #endif liblxi-1.20/src/meson.build000066400000000000000000000030001443211710200156340ustar00rootroot00000000000000liblxi_sources = [ 'lxi.c', 'mdns.c', 'tcp.c', 'vxi11.c', 'vxi11core_clnt.c', 'vxi11core_xdr.c', ] liblxi_deps = [ dependency('avahi-client', required: false), dependency('libxml-2.0', required: true), dependency('threads', required: true), ] tirpc_excluded_systems = ['darwin'] liblxi_link_args = ['-fvisibility=hidden'] tirpc_incdir = [] # without avahi or bonjour, mdns discovery won't do anything if meson.get_compiler('c').has_header('avahi-client/client.h') add_project_arguments('-DHAVE_AVAHI', language: 'c') liblxi_sources += 'avahi.c' elif meson.get_compiler('c').has_header('dns_sd.h') add_project_arguments('-DHAVE_BONJOUR', language: 'c') liblxi_sources += 'bonjour.c' endif if host_machine.system() not in tirpc_excluded_systems tirpc_dep = dependency('libtirpc', required: true) tirpc_incpath = join_paths(tirpc_dep.get_variable(pkgconfig: 'includedir'), 'tirpc') tirpc_incdir = include_directories(tirpc_incpath) liblxi_link_args += ['-Wl,-init,init'] elif not meson.get_compiler('c').has_header('rpc/rpc.h') error('The required RPC headers is not available, cannot proceed with the build.') endif liblxi_c_args = [ '-Wno-unused-variable', '-Wno-unused-parameter', '-Wno-unused-result', '-fvisibility=hidden', '-D_GNU_SOURCE', ] liblxi = shared_library( 'lxi', liblxi_sources, dependencies: liblxi_deps, install: true, c_args: liblxi_c_args, include_directories: tirpc_incdir, link_args: liblxi_link_args, version: '1.0.0', ) install_headers('lxi.h') liblxi-1.20/src/session.h000066400000000000000000000037651443211710200153500ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SESSION_H #define SESSION_H #include #include #define SESSIONS_MAX 1024 struct session_t { bool allocated; bool connected; void *data; int (*connect)(void *data, const char *address, int port, const char *name, int timeout); int (*disconnect)(void *data); int (*send)(void *data, const char *message, int length, int timeout); int (*receive)(void *data, char *message, int length, int timeout); }; #endif liblxi-1.20/src/tcp.c000066400000000000000000000157051443211710200144430ustar00rootroot00000000000000/* * Copyright (c) 2017-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "tcp.h" #include "error.h" #include int tcp_connect(void *data, const char *address, int port, const char *name, int timeout) { struct sockaddr_in server_address; struct hostent *host; struct timeval tv; int result, opt; fd_set wait_set; socklen_t len; tcp_data_t *tcp_data = (tcp_data_t *) data; // Create a TCP/IP stream socket if ((tcp_data->server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { error_printf("socket() call failed\n"); return -1; } // Get socket flags if ((opt = fcntl(tcp_data->server_socket, F_GETFL, NULL)) < 0) { error_printf("%s\n", strerror(errno)); return -1; } // Set socket non-blocking if ((fcntl(tcp_data->server_socket, F_SETFL, opt | O_NONBLOCK)) < 0) { error_printf("%s\n", strerror(errno)); return -1; } // Construct the server address structure memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_port = htons(port); server_address.sin_addr.s_addr = inet_addr(address); if (server_address.sin_addr.s_addr == (unsigned long) INADDR_NONE) { // Look up host address host = gethostbyname(address); if (host == (struct hostent *) NULL) { error_printf("Host not found\n"); close(tcp_data->server_socket); return -1; } memcpy(&server_address.sin_addr, host->h_addr, sizeof(server_address.sin_addr)); } tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; // Establish connection to server result = connect(tcp_data->server_socket, (struct sockaddr *) &server_address, sizeof(server_address)); if (result < 0) { if (errno == EINPROGRESS) { FD_ZERO(&wait_set); FD_SET(tcp_data->server_socket, &wait_set); // Wait for socket to be writable up to timeout duration result = select(tcp_data->server_socket + 1, NULL, &wait_set, NULL, &tv); } } else { result = 1; } // Reset socket flags if (fcntl(tcp_data->server_socket, F_SETFL, opt) < 0) { error_printf("%s\n", strerror(errno)); close(tcp_data->server_socket); return -1; } if (result < 0) { error_printf("connect() call failed\n"); close(tcp_data->server_socket); return -1; } else if (result == 0) { error_printf("connect() call timed out\n"); close(tcp_data->server_socket); return -1; } else { // Check for socket errors len = sizeof(opt); if (getsockopt(tcp_data->server_socket, SOL_SOCKET, SO_ERROR, &opt, &len) != 0) { error_printf("%s\n", strerror(errno)); close(tcp_data->server_socket); return -1; } } return 0; } int tcp_disconnect(void *data) { tcp_data_t *tcp_data = (tcp_data_t *) data; close(tcp_data->server_socket); return 0; } int tcp_send(void *data, const char *message, int length, int timeout) { int status; struct timeval tv; fd_set wdfs; int n = 0, bytes_sent = 0; tcp_data_t *tcp_data = (tcp_data_t *) data; // Set timeout tv.tv_sec = 0; tv.tv_usec = timeout * 1000; FD_ZERO(&wdfs); FD_SET(tcp_data->server_socket, &wdfs); // Wait for socket to be writable status = select(tcp_data->server_socket + 1, NULL, &wdfs, NULL, &tv); if (status == -1) { error_printf("%s\n", strerror(errno)); return -1; } else if (status) { // Send until all data is sent do { n = send(tcp_data->server_socket, message + n, length, 0); if (n < 0) { error_printf("%s\n", strerror(errno)); return -1; } length -= n; bytes_sent += n; } while (length > 0); return bytes_sent; } else { error_printf("Timeout\n"); } return -1; } static int tcp_receive_(void *data, char *message, int length, int timeout, int flags) { int status; struct timeval tv; fd_set rdfs; int n = 0, bytes_received = 0; tcp_data_t *tcp_data = (tcp_data_t *) data; // Set timeout tv.tv_sec = 0; tv.tv_usec = timeout * 1000; FD_ZERO(&rdfs); FD_SET(tcp_data->server_socket, &rdfs); // Wait for socket to be readable status = select(tcp_data->server_socket + 1, &rdfs, NULL, NULL, &tv); if (status == -1) return -1; else if (status) { // Receive until all data is received do { n = recv(tcp_data->server_socket, message + n, length, flags); if (n < 0) break; length -= n; bytes_received += n; } while (n > 0); return bytes_received; } else { error_printf("Timeout\n"); } return -1; } int tcp_receive(void *data, char *message, int length, int timeout) { return tcp_receive_(data, message, length, timeout, MSG_DONTWAIT); } int tcp_receive_wait(void *data, char *message, int length, int timeout) { return tcp_receive_(data, message, length, timeout, 0); } liblxi-1.20/src/tcp.h000066400000000000000000000037221443211710200144440ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TCP_H #define TCP_H typedef struct { int server_socket; } tcp_data_t; int tcp_connect(void *data, const char *address, int port, const char *name, int timeout); int tcp_disconnect(void *data); int tcp_send(void *data, const char *message, int length, int timeout); int tcp_receive(void *data, char *message, int length, int timeout); int tcp_receive_wait(void *data, char *message, int length, int timeout); #endif liblxi-1.20/src/vxi11.c000066400000000000000000000405731443211710200146260ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vxi11core.h" #include "vxi11.h" #include "tcp.h" #include "error.h" #define PORT_HTTP 80 #define PORT_RPC 111 #define ID_REQ_HTTP "GET /lxi/identification HTTP/1.0\r\n\r\n"; #define ID_REQ_SCPI "*IDN?\n" #define ID_LENGTH_MAX 65536 #define RECEIVE_END_BIT 0x04 // Receive end indicator #define RECEIVE_TERM_CHAR_BIT 0x02 // Receive termination character typedef struct { void *data; const char *address; int port; const char *name; int timeout; } thread_vxi11_connect_args_t; typedef struct { int joined; pthread_t td; pthread_mutex_t mtx; pthread_cond_t cond; void **res; } thread_vxi11_wrapper_args_t; // Payload representing GETPORT RPC call static char rpc_GETPORT_msg[] = { 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x86, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0xaf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 }; // A POSIX compatible pthread_timedjoin_np static void *_pthread_waiter(void *ap) { thread_vxi11_wrapper_args_t *args = ap; pthread_join(args->td, args->res); pthread_mutex_lock(&args->mtx); args->joined = 1; pthread_mutex_unlock(&args->mtx); pthread_cond_signal(&args->cond); return 0; } static int _pthread_timedjoin(pthread_t td, void **res, struct timespec *ts) { pthread_t tmp; int ret; thread_vxi11_wrapper_args_t args = { .td = td, .res = res }; pthread_mutex_init(&args.mtx, 0); pthread_cond_init(&args.cond, 0); pthread_mutex_lock(&args.mtx); ret = pthread_create(&tmp, 0, _pthread_waiter, &args); if (ret == 0) { do { ret = pthread_cond_timedwait(&args.cond, &args.mtx, ts); } while (!args.joined && ret != ETIMEDOUT); } pthread_cancel(tmp); pthread_join(tmp, 0); pthread_cond_destroy(&args.cond); pthread_mutex_destroy(&args.mtx); return args.joined ? 0 : ret; } static int _vxi11_connect(void *data, const char *address, int port, const char *name, int timeout) { Create_LinkParms link_params; vxi11_data_t *vxi11_data = (vxi11_data_t *) data; // Set up client vxi11_data->rpc_client = clnt_create(address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp"); if (vxi11_data->rpc_client == NULL) goto error_client; // Set up link link_params.clientId = (unsigned long) vxi11_data->rpc_client; link_params.lockDevice = 0; // No lock link_params.lock_timeout = 0; if (name == NULL) link_params.device = "inst0"; // Use default device name else link_params.device = (char *) name; // Use provided device name if (create_link_1(&link_params, &vxi11_data->link_resp, vxi11_data->rpc_client) != RPC_SUCCESS) goto error_link; return 0; error_link: clnt_destroy(vxi11_data->rpc_client); error_client: return -1; } static void *thread_vxi11_connect(void *ptr) { int *status; thread_vxi11_connect_args_t *args = (thread_vxi11_connect_args_t *) ptr; status = malloc(sizeof(int)); // Automatically freed when thread is killed *status = _vxi11_connect(args->data, args->address, args->port, args->name, args->timeout); pthread_exit(status); } int vxi11_connect(void *data, const char *address, int port, const char *name, int timeout) { struct timespec timeout_tv; pthread_t thread; int status; int *thread_status; thread_vxi11_connect_args_t args = { .data = data, .address = address, .port = port, .name = name, .timeout = timeout, }; status = clock_gettime(CLOCK_REALTIME, &timeout_tv); if (status != 0) { error_printf("Error clock_gettime()\n"); return -1; } // Convert timeout in ms to timespec timeout_tv.tv_sec += timeout / 1000; timeout_tv.tv_nsec += (timeout % 1000) * 1000; // Start thread that will perform the connect action status = pthread_create(&thread, NULL, thread_vxi11_connect, &args); if (status != 0) { error_printf("Error pthread_create()\n"); return -1; } // Wait for thread to terminate or timeout status = _pthread_timedjoin(thread, (void *)&thread_status, &timeout_tv); if (status != 0) { // Timeout reached pthread_cancel(thread); // Wait for child thread to end before returning pthread_join(thread, NULL); return -1; } return *thread_status; } int vxi11_disconnect(void *data) { Device_Error device_error; vxi11_data_t *vxi11_data = (vxi11_data_t *) data; destroy_link_1(&vxi11_data->link_resp.lid, &device_error, vxi11_data->rpc_client); clnt_destroy(vxi11_data->rpc_client); return 0; } int vxi11_send(void *data, const char *message, int length, int timeout) { Device_WriteParms write_params; Device_WriteResp write_resp; vxi11_data_t *vxi11_data = (vxi11_data_t *) data; // Configure VXI11 write parameters write_params.lid = vxi11_data->link_resp.lid; write_params.lock_timeout = 0; write_params.io_timeout = timeout; write_params.flags = 0x9; write_params.data.data_len = length; write_params.data.data_val = (char *) message; // Send if (device_write_1(&write_params, &write_resp, vxi11_data->rpc_client) != RPC_SUCCESS) return -1; // Return number of bytes sent return write_resp.size; } int vxi11_receive(void *data, char *message, int length, int timeout) { Device_ReadParms read_params; Device_ReadResp read_resp; int response_length = 0; int offset = 0; vxi11_data_t *vxi11_data = (vxi11_data_t *) data; // Configure VXI11 read parameters read_params.lid = vxi11_data->link_resp.lid; read_params.lock_timeout = 0; read_params.io_timeout = timeout; read_params.flags = 0; read_params.termChar = 0; read_params.requestSize = length; // Receive until done do { // Prepare for (repeated) read operation memset(&read_resp, 0, sizeof(read_resp)); read_resp.data.data_val = message + offset; read_params.requestSize = length - offset; if (device_read_1(&read_params, &read_resp, vxi11_data->rpc_client) != RPC_SUCCESS) return -1; if (read_resp.error != 0) { if (read_resp.error == 15) error_printf("Read error (timeout)\n"); // Most common error explained else error_printf("Read error (response error code %d)\n", (int) read_resp.error); return -1; } if (read_resp.data.data_len > 0) { response_length += read_resp.data.data_len; // Return error if provided receive message buffer is too small if (response_length > length) { error_printf("Read error (receive message buffer too small)\n"); return -1; } offset += read_resp.data.data_len; } // Stop if we have reached end of receive operation if ((read_resp.reason & RECEIVE_END_BIT) || (read_resp.reason & RECEIVE_TERM_CHAR_BIT)) break; } while (read_resp.reason == 0); // Return number of bytes received return response_length; } int vxi11_lock(void *data) { return 0; } int vxi11_unlock(void *data) { return 0; } static xmlChar *get_element_value(xmlDocPtr doc, xmlChar *element) { xmlNodePtr node; xmlChar *value = NULL; node = xmlDocGetRootElement(doc); node = node->xmlChildrenNode; while (node != NULL) { if ((!xmlStrcmp(node->name, element))) { value = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); break; } node = node->next; } return value; } static int get_device_id(char *address, char *id, int timeout) { vxi11_data_t data; int length; int device; device = vxi11_connect(&data, address, 0, NULL, timeout); if (device < 0) goto error_connect; length = vxi11_send(&data, ID_REQ_SCPI, strlen(ID_REQ_SCPI), timeout); if (length < 0) goto error_send; length = vxi11_receive(&data, id, ID_LENGTH_MAX, timeout); if (length < 0) goto error_receive; vxi11_disconnect(&data); // Terminate string id[length] = 0; if (length > 0) { // Strip newline if (id[length-1] == '\n') id[--length] = 0; // Strip carriage return if (id[length-1] == '\r') id[--length] = 0; } else { // Fallback - try retrieve ID via HTTP/XML char *request = ID_REQ_HTTP; char response[4096]; char *response_xml; tcp_data_t tcp_data; xmlDocPtr doc; xmlChar *value; // Mute stderr temporarily freopen("/dev/null", "w", stderr); // Get XML identification file tcp_connect(&tcp_data, address, PORT_HTTP, NULL, timeout); tcp_send(&tcp_data, request, strlen(request), timeout); tcp_receive_wait(&tcp_data, response, 4096, timeout); tcp_disconnect(&tcp_data); // Find start of XML response_xml = strstr(response, "sin_addr.s_addr; recv_addr.sin_port = htons(PORT_RPC); // Broadcast RPC GETPORT message sendto(sockfd, rpc_GETPORT_msg, sizeof(rpc_GETPORT_msg), 0, (struct sockaddr*)&recv_addr, sizeof(recv_addr)); addrlen = sizeof(recv_addr); // Go through received responses do { count = recvfrom(sockfd, buffer, ID_LENGTH_MAX, 0, (struct sockaddr*)&recv_addr, &addrlen); if (count > 0) { // Add device if an LXI ID string is returned char *address = inet_ntoa(recv_addr.sin_addr); if (get_device_id(address, id, timeout) == 0) { // Notify device found via callback if (info->device != NULL) info->device(address, id); } } } while (count > 0); return 0; socket_options_error: // Shutdown socket shutdown(sockfd, SHUT_RDWR); return -1; } int vxi11_discover(lxi_info_t *info, int timeout) { struct sockaddr_in *broadcast_addr; struct ifaddrs *ifap; // Go through available broadcast addresses if (getifaddrs(&ifap) == 0) { struct ifaddrs *ifap_p = ifap; while (ifap_p) { if ((ifap_p->ifa_addr) && (ifap_p->ifa_addr->sa_family == AF_INET)) { broadcast_addr = (struct sockaddr_in *) ifap_p->ifa_broadaddr; // Notify current broadcast address and network interface via callback if (info->broadcast != NULL) info->broadcast(inet_ntoa(broadcast_addr->sin_addr), ifap_p->ifa_name); // Find VXI11 devices via broadcast address discover_devices(broadcast_addr, info, timeout); } ifap_p = ifap_p->ifa_next; } freeifaddrs(ifap); } return 0; } int vxi11_discover_if(lxi_info_t *info, const char *ifname, int timeout) { struct sockaddr_in *broadcast_addr; struct ifaddrs *ifap; int status = 0; // Go through available broadcast addresses if (getifaddrs(&ifap) == 0) { struct ifaddrs *ifap_p = ifap; while (ifap_p) { if ((ifap_p->ifa_addr) && (ifap_p->ifa_addr->sa_family == AF_INET) && (strcmp(ifap_p->ifa_name, ifname) == 0)) { broadcast_addr = (struct sockaddr_in *) ifap_p->ifa_broadaddr; // Notify current broadcast address and network interface via callback if (info->broadcast != NULL) info->broadcast(inet_ntoa(broadcast_addr->sin_addr), ifap_p->ifa_name); // Find VXI11 devices via broadcast address status = discover_devices(broadcast_addr, info, timeout); } ifap_p = ifap_p->ifa_next; } freeifaddrs(ifap); } return status; } liblxi-1.20/src/vxi11.h000066400000000000000000000041341443211710200146240ustar00rootroot00000000000000/* * Copyright (c) 2016-2022 Martin Lund * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef VXI11_H #define VXI11_H #include "vxi11core.h" #include typedef struct { CLIENT *rpc_client; Create_LinkResp link_resp; } vxi11_data_t; int vxi11_connect(void *data, const char *address, int port, const char *name, int timeout); int vxi11_disconnect(void *data); int vxi11_send(void *data, const char *message, int length, int timeout); int vxi11_receive(void *data, char *message, int length, int timeout); int vxi11_discover(lxi_info_t *info, int timeout); int vxi11_discover_if(lxi_info_t *info, const char *ifname, int timeout); #endif liblxi-1.20/src/vxi11core.h000066400000000000000000000237741443211710200155100ustar00rootroot00000000000000/* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _VXI11CORE_H_RPCGEN #define _VXI11CORE_H_RPCGEN #include #include #ifdef __cplusplus extern "C" { #endif typedef int Device_Link; enum Device_AddrFamily { DEVICE_TCP = 0, DEVICE_UDP = 1, }; typedef enum Device_AddrFamily Device_AddrFamily; typedef int Device_Flags; typedef int Device_ErrorCode; struct Device_Error { Device_ErrorCode error; }; typedef struct Device_Error Device_Error; struct Create_LinkParms { int clientId; bool_t lockDevice; u_int lock_timeout; char *device; }; typedef struct Create_LinkParms Create_LinkParms; struct Create_LinkResp { Device_ErrorCode error; Device_Link lid; u_short abortPort; u_int maxRecvSize; }; typedef struct Create_LinkResp Create_LinkResp; struct Device_WriteParms { Device_Link lid; u_int io_timeout; u_int lock_timeout; Device_Flags flags; struct { u_int data_len; char *data_val; } data; }; typedef struct Device_WriteParms Device_WriteParms; struct Device_WriteResp { Device_ErrorCode error; u_int size; }; typedef struct Device_WriteResp Device_WriteResp; struct Device_ReadParms { Device_Link lid; u_int requestSize; u_int io_timeout; u_int lock_timeout; Device_Flags flags; char termChar; }; typedef struct Device_ReadParms Device_ReadParms; struct Device_ReadResp { Device_ErrorCode error; int reason; struct { u_int data_len; char *data_val; } data; }; typedef struct Device_ReadResp Device_ReadResp; struct Device_ReadStbResp { Device_ErrorCode error; u_char stb; }; typedef struct Device_ReadStbResp Device_ReadStbResp; struct Device_GenericParms { Device_Link lid; Device_Flags flags; u_int lock_timeout; u_int io_timeout; }; typedef struct Device_GenericParms Device_GenericParms; struct Device_RemoteFunc { u_int hostAddr; u_int hostPort; u_int progNum; u_int progVers; Device_AddrFamily progFamily; }; typedef struct Device_RemoteFunc Device_RemoteFunc; struct Device_EnableSrqParms { Device_Link lid; bool_t enable; struct { u_int handle_len; char *handle_val; } handle; }; typedef struct Device_EnableSrqParms Device_EnableSrqParms; struct Device_LockParms { Device_Link lid; Device_Flags flags; u_int lock_timeout; }; typedef struct Device_LockParms Device_LockParms; struct Device_DocmdParms { Device_Link lid; Device_Flags flags; u_int io_timeout; u_int lock_timeout; int cmd; bool_t network_order; int datasize; struct { u_int data_in_len; char *data_in_val; } data_in; }; typedef struct Device_DocmdParms Device_DocmdParms; struct Device_DocmdResp { Device_ErrorCode error; struct { u_int data_out_len; char *data_out_val; } data_out; }; typedef struct Device_DocmdResp Device_DocmdResp; #define DEVICE_ASYNC 0x0607B0 #define DEVICE_ASYNC_VERSION 1 #if defined(__STDC__) || defined(__cplusplus) #define device_abort 1 extern enum clnt_stat device_abort_1(Device_Link *, Device_Error *, CLIENT *); extern bool_t device_abort_1_svc(Device_Link *, Device_Error *, struct svc_req *); extern int device_async_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #else /* K&R C */ #define device_abort 1 extern enum clnt_stat device_abort_1(); extern bool_t device_abort_1_svc(); extern int device_async_1_freeresult (); #endif /* K&R C */ #define DEVICE_CORE 0x0607AF #define DEVICE_CORE_VERSION 1 #if defined(__STDC__) || defined(__cplusplus) #define create_link 10 extern enum clnt_stat create_link_1(Create_LinkParms *, Create_LinkResp *, CLIENT *); extern bool_t create_link_1_svc(Create_LinkParms *, Create_LinkResp *, struct svc_req *); #define device_write 11 extern enum clnt_stat device_write_1(Device_WriteParms *, Device_WriteResp *, CLIENT *); extern bool_t device_write_1_svc(Device_WriteParms *, Device_WriteResp *, struct svc_req *); #define device_read 12 extern enum clnt_stat device_read_1(Device_ReadParms *, Device_ReadResp *, CLIENT *); extern bool_t device_read_1_svc(Device_ReadParms *, Device_ReadResp *, struct svc_req *); #define device_readstb 13 extern enum clnt_stat device_readstb_1(Device_GenericParms *, Device_ReadStbResp *, CLIENT *); extern bool_t device_readstb_1_svc(Device_GenericParms *, Device_ReadStbResp *, struct svc_req *); #define device_trigger 14 extern enum clnt_stat device_trigger_1(Device_GenericParms *, Device_Error *, CLIENT *); extern bool_t device_trigger_1_svc(Device_GenericParms *, Device_Error *, struct svc_req *); #define device_clear 15 extern enum clnt_stat device_clear_1(Device_GenericParms *, Device_Error *, CLIENT *); extern bool_t device_clear_1_svc(Device_GenericParms *, Device_Error *, struct svc_req *); #define device_remote 16 extern enum clnt_stat device_remote_1(Device_GenericParms *, Device_Error *, CLIENT *); extern bool_t device_remote_1_svc(Device_GenericParms *, Device_Error *, struct svc_req *); #define device_local 17 extern enum clnt_stat device_local_1(Device_GenericParms *, Device_Error *, CLIENT *); extern bool_t device_local_1_svc(Device_GenericParms *, Device_Error *, struct svc_req *); #define device_lock 18 extern enum clnt_stat device_lock_1(Device_LockParms *, Device_Error *, CLIENT *); extern bool_t device_lock_1_svc(Device_LockParms *, Device_Error *, struct svc_req *); #define device_unlock 19 extern enum clnt_stat device_unlock_1(Device_Link *, Device_Error *, CLIENT *); extern bool_t device_unlock_1_svc(Device_Link *, Device_Error *, struct svc_req *); #define device_enable_srq 20 extern enum clnt_stat device_enable_srq_1(Device_EnableSrqParms *, Device_Error *, CLIENT *); extern bool_t device_enable_srq_1_svc(Device_EnableSrqParms *, Device_Error *, struct svc_req *); #define device_docmd 22 extern enum clnt_stat device_docmd_1(Device_DocmdParms *, Device_DocmdResp *, CLIENT *); extern bool_t device_docmd_1_svc(Device_DocmdParms *, Device_DocmdResp *, struct svc_req *); #define destroy_link 23 extern enum clnt_stat destroy_link_1(Device_Link *, Device_Error *, CLIENT *); extern bool_t destroy_link_1_svc(Device_Link *, Device_Error *, struct svc_req *); #define create_intr_chan 25 extern enum clnt_stat create_intr_chan_1(Device_RemoteFunc *, Device_Error *, CLIENT *); extern bool_t create_intr_chan_1_svc(Device_RemoteFunc *, Device_Error *, struct svc_req *); #define destroy_intr_chan 26 extern enum clnt_stat destroy_intr_chan_1(void *, Device_Error *, CLIENT *); extern bool_t destroy_intr_chan_1_svc(void *, Device_Error *, struct svc_req *); extern int device_core_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #else /* K&R C */ #define create_link 10 extern enum clnt_stat create_link_1(); extern bool_t create_link_1_svc(); #define device_write 11 extern enum clnt_stat device_write_1(); extern bool_t device_write_1_svc(); #define device_read 12 extern enum clnt_stat device_read_1(); extern bool_t device_read_1_svc(); #define device_readstb 13 extern enum clnt_stat device_readstb_1(); extern bool_t device_readstb_1_svc(); #define device_trigger 14 extern enum clnt_stat device_trigger_1(); extern bool_t device_trigger_1_svc(); #define device_clear 15 extern enum clnt_stat device_clear_1(); extern bool_t device_clear_1_svc(); #define device_remote 16 extern enum clnt_stat device_remote_1(); extern bool_t device_remote_1_svc(); #define device_local 17 extern enum clnt_stat device_local_1(); extern bool_t device_local_1_svc(); #define device_lock 18 extern enum clnt_stat device_lock_1(); extern bool_t device_lock_1_svc(); #define device_unlock 19 extern enum clnt_stat device_unlock_1(); extern bool_t device_unlock_1_svc(); #define device_enable_srq 20 extern enum clnt_stat device_enable_srq_1(); extern bool_t device_enable_srq_1_svc(); #define device_docmd 22 extern enum clnt_stat device_docmd_1(); extern bool_t device_docmd_1_svc(); #define destroy_link 23 extern enum clnt_stat destroy_link_1(); extern bool_t destroy_link_1_svc(); #define create_intr_chan 25 extern enum clnt_stat create_intr_chan_1(); extern bool_t create_intr_chan_1_svc(); #define destroy_intr_chan 26 extern enum clnt_stat destroy_intr_chan_1(); extern bool_t destroy_intr_chan_1_svc(); extern int device_core_1_freeresult (); #endif /* K&R C */ /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_Device_Link (XDR *, Device_Link*); extern bool_t xdr_Device_AddrFamily (XDR *, Device_AddrFamily*); extern bool_t xdr_Device_Flags (XDR *, Device_Flags*); extern bool_t xdr_Device_ErrorCode (XDR *, Device_ErrorCode*); extern bool_t xdr_Device_Error (XDR *, Device_Error*); extern bool_t xdr_Create_LinkParms (XDR *, Create_LinkParms*); extern bool_t xdr_Create_LinkResp (XDR *, Create_LinkResp*); extern bool_t xdr_Device_WriteParms (XDR *, Device_WriteParms*); extern bool_t xdr_Device_WriteResp (XDR *, Device_WriteResp*); extern bool_t xdr_Device_ReadParms (XDR *, Device_ReadParms*); extern bool_t xdr_Device_ReadResp (XDR *, Device_ReadResp*); extern bool_t xdr_Device_ReadStbResp (XDR *, Device_ReadStbResp*); extern bool_t xdr_Device_GenericParms (XDR *, Device_GenericParms*); extern bool_t xdr_Device_RemoteFunc (XDR *, Device_RemoteFunc*); extern bool_t xdr_Device_EnableSrqParms (XDR *, Device_EnableSrqParms*); extern bool_t xdr_Device_LockParms (XDR *, Device_LockParms*); extern bool_t xdr_Device_DocmdParms (XDR *, Device_DocmdParms*); extern bool_t xdr_Device_DocmdResp (XDR *, Device_DocmdResp*); #else /* K&R C */ extern bool_t xdr_Device_Link (); extern bool_t xdr_Device_AddrFamily (); extern bool_t xdr_Device_Flags (); extern bool_t xdr_Device_ErrorCode (); extern bool_t xdr_Device_Error (); extern bool_t xdr_Create_LinkParms (); extern bool_t xdr_Create_LinkResp (); extern bool_t xdr_Device_WriteParms (); extern bool_t xdr_Device_WriteResp (); extern bool_t xdr_Device_ReadParms (); extern bool_t xdr_Device_ReadResp (); extern bool_t xdr_Device_ReadStbResp (); extern bool_t xdr_Device_GenericParms (); extern bool_t xdr_Device_RemoteFunc (); extern bool_t xdr_Device_EnableSrqParms (); extern bool_t xdr_Device_LockParms (); extern bool_t xdr_Device_DocmdParms (); extern bool_t xdr_Device_DocmdResp (); #endif /* K&R C */ #ifdef __cplusplus } #endif #endif /* !_VXI11CORE_H_RPCGEN */ liblxi-1.20/src/vxi11core.rpcl000066400000000000000000000117111443211710200162050ustar00rootroot00000000000000/****************************************************************************** * * 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 int Device_Link; enum Device_AddrFamily { DEVICE_TCP, DEVICE_UDP }; typedef int Device_Flags; typedef int Device_ErrorCode; struct Device_Error { Device_ErrorCode error; }; struct Create_LinkParms { int clientId; /* implementation specific value */ bool lockDevice; /* attempt to lock the device */ unsigned int 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 int maxRecvSize; /* max # of bytes accepted on write */ }; struct Device_WriteParms { Device_Link lid; /* link id from create_link */ unsigned int io_timeout; /* time to wait for I/O */ unsigned int 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 int size; /* # of bytes written */ }; struct Device_ReadParms { Device_Link lid; /* link id from create_link */ unsigned int requestSize; /* # of bytes requested */ unsigned int io_timeout; /* time to wait for I/O */ unsigned int 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; int 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 int lock_timeout; /* time to wait for lock */ unsigned int io_timeout; /* time to wait for I/O */ }; struct Device_RemoteFunc { unsigned int hostAddr; /* host servicing interrupt */ unsigned int hostPort; /* valid port # on client */ unsigned int progNum; /* DEVICE_INTR */ unsigned int 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 int 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 int io_timeout; /* time to wait for I/O */ unsigned int lock_timeout; /* time to wait for lock */ int cmd; /* which command to execute */ bool network_order; /* client's byte order */ int 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; liblxi-1.20/src/vxi11core_clnt.c000066400000000000000000000106201443211710200165050ustar00rootroot00000000000000/* * Please do not edit this file. * It was generated using rpcgen. */ #include /* for memset */ #include "vxi11core.h" /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; enum clnt_stat device_abort_1(Device_Link *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_abort, (xdrproc_t) xdr_Device_Link, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat create_link_1(Create_LinkParms *argp, Create_LinkResp *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, create_link, (xdrproc_t) xdr_Create_LinkParms, (caddr_t) argp, (xdrproc_t) xdr_Create_LinkResp, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_write_1(Device_WriteParms *argp, Device_WriteResp *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_write, (xdrproc_t) xdr_Device_WriteParms, (caddr_t) argp, (xdrproc_t) xdr_Device_WriteResp, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_read_1(Device_ReadParms *argp, Device_ReadResp *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_read, (xdrproc_t) xdr_Device_ReadParms, (caddr_t) argp, (xdrproc_t) xdr_Device_ReadResp, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_readstb_1(Device_GenericParms *argp, Device_ReadStbResp *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_readstb, (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp, (xdrproc_t) xdr_Device_ReadStbResp, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_trigger_1(Device_GenericParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_trigger, (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_clear_1(Device_GenericParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_clear, (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_remote_1(Device_GenericParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_remote, (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_local_1(Device_GenericParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_local, (xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_lock_1(Device_LockParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_lock, (xdrproc_t) xdr_Device_LockParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_unlock_1(Device_Link *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_unlock, (xdrproc_t) xdr_Device_Link, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_enable_srq_1(Device_EnableSrqParms *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_enable_srq, (xdrproc_t) xdr_Device_EnableSrqParms, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat device_docmd_1(Device_DocmdParms *argp, Device_DocmdResp *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, device_docmd, (xdrproc_t) xdr_Device_DocmdParms, (caddr_t) argp, (xdrproc_t) xdr_Device_DocmdResp, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat destroy_link_1(Device_Link *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, destroy_link, (xdrproc_t) xdr_Device_Link, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } enum clnt_stat create_intr_chan_1(Device_RemoteFunc *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, create_intr_chan, (xdrproc_t) xdr_Device_RemoteFunc, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-function-type" #endif enum clnt_stat destroy_intr_chan_1(void *argp, Device_Error *clnt_res, CLIENT *clnt) { return (clnt_call(clnt, destroy_intr_chan, (xdrproc_t) xdr_void, (caddr_t) argp, (xdrproc_t) xdr_Device_Error, (caddr_t) clnt_res, TIMEOUT)); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif liblxi-1.20/src/vxi11core_svc.c000066400000000000000000000200751443211710200163450ustar00rootroot00000000000000/* * Please do not edit this file. * It was generated using rpcgen. */ #include "vxi11core.h" #include #include #include #include #include #include #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif static void device_async_1(struct svc_req *rqstp, register SVCXPRT *transp) { union { Device_Link device_abort_1_arg; } argument; union { Device_Error device_abort_1_res; } result; bool_t retval; xdrproc_t _xdr_argument, _xdr_result; bool_t (*local)(char *, void *, struct svc_req *); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case device_abort: _xdr_argument = (xdrproc_t) xdr_Device_Link; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_abort_1_svc; break; default: svcerr_noproc (transp); return; } memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp); if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } if (!device_async_1_freeresult (transp, _xdr_result, (caddr_t) &result)) fprintf (stderr, "%s", "unable to free results"); return; } static void device_core_1(struct svc_req *rqstp, register SVCXPRT *transp) { union { Create_LinkParms create_link_1_arg; Device_WriteParms device_write_1_arg; Device_ReadParms device_read_1_arg; Device_GenericParms device_readstb_1_arg; Device_GenericParms device_trigger_1_arg; Device_GenericParms device_clear_1_arg; Device_GenericParms device_remote_1_arg; Device_GenericParms device_local_1_arg; Device_LockParms device_lock_1_arg; Device_Link device_unlock_1_arg; Device_EnableSrqParms device_enable_srq_1_arg; Device_DocmdParms device_docmd_1_arg; Device_Link destroy_link_1_arg; Device_RemoteFunc create_intr_chan_1_arg; } argument; union { Create_LinkResp create_link_1_res; Device_WriteResp device_write_1_res; Device_ReadResp device_read_1_res; Device_ReadStbResp device_readstb_1_res; Device_Error device_trigger_1_res; Device_Error device_clear_1_res; Device_Error device_remote_1_res; Device_Error device_local_1_res; Device_Error device_lock_1_res; Device_Error device_unlock_1_res; Device_Error device_enable_srq_1_res; Device_DocmdResp device_docmd_1_res; Device_Error destroy_link_1_res; Device_Error create_intr_chan_1_res; Device_Error destroy_intr_chan_1_res; } result; bool_t retval; xdrproc_t _xdr_argument, _xdr_result; bool_t (*local)(char *, void *, struct svc_req *); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case create_link: _xdr_argument = (xdrproc_t) xdr_Create_LinkParms; _xdr_result = (xdrproc_t) xdr_Create_LinkResp; local = (bool_t (*) (char *, void *, struct svc_req *))create_link_1_svc; break; case device_write: _xdr_argument = (xdrproc_t) xdr_Device_WriteParms; _xdr_result = (xdrproc_t) xdr_Device_WriteResp; local = (bool_t (*) (char *, void *, struct svc_req *))device_write_1_svc; break; case device_read: _xdr_argument = (xdrproc_t) xdr_Device_ReadParms; _xdr_result = (xdrproc_t) xdr_Device_ReadResp; local = (bool_t (*) (char *, void *, struct svc_req *))device_read_1_svc; break; case device_readstb: _xdr_argument = (xdrproc_t) xdr_Device_GenericParms; _xdr_result = (xdrproc_t) xdr_Device_ReadStbResp; local = (bool_t (*) (char *, void *, struct svc_req *))device_readstb_1_svc; break; case device_trigger: _xdr_argument = (xdrproc_t) xdr_Device_GenericParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_trigger_1_svc; break; case device_clear: _xdr_argument = (xdrproc_t) xdr_Device_GenericParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_clear_1_svc; break; case device_remote: _xdr_argument = (xdrproc_t) xdr_Device_GenericParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_remote_1_svc; break; case device_local: _xdr_argument = (xdrproc_t) xdr_Device_GenericParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_local_1_svc; break; case device_lock: _xdr_argument = (xdrproc_t) xdr_Device_LockParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_lock_1_svc; break; case device_unlock: _xdr_argument = (xdrproc_t) xdr_Device_Link; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_unlock_1_svc; break; case device_enable_srq: _xdr_argument = (xdrproc_t) xdr_Device_EnableSrqParms; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))device_enable_srq_1_svc; break; case device_docmd: _xdr_argument = (xdrproc_t) xdr_Device_DocmdParms; _xdr_result = (xdrproc_t) xdr_Device_DocmdResp; local = (bool_t (*) (char *, void *, struct svc_req *))device_docmd_1_svc; break; case destroy_link: _xdr_argument = (xdrproc_t) xdr_Device_Link; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))destroy_link_1_svc; break; case create_intr_chan: _xdr_argument = (xdrproc_t) xdr_Device_RemoteFunc; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))create_intr_chan_1_svc; break; case destroy_intr_chan: _xdr_argument = (xdrproc_t) xdr_void; _xdr_result = (xdrproc_t) xdr_Device_Error; local = (bool_t (*) (char *, void *, struct svc_req *))destroy_intr_chan_1_svc; break; default: svcerr_noproc (transp); return; } memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp); if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } if (!device_core_1_freeresult (transp, _xdr_result, (caddr_t) &result)) fprintf (stderr, "%s", "unable to free results"); return; } int main (int argc, char **argv) { register SVCXPRT *transp; pmap_unset (DEVICE_ASYNC, DEVICE_ASYNC_VERSION); pmap_unset (DEVICE_CORE, DEVICE_CORE_VERSION); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { fprintf (stderr, "%s", "cannot create udp service."); exit(1); } if (!svc_register(transp, DEVICE_ASYNC, DEVICE_ASYNC_VERSION, device_async_1, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (DEVICE_ASYNC, DEVICE_ASYNC_VERSION, udp)."); exit(1); } if (!svc_register(transp, DEVICE_CORE, DEVICE_CORE_VERSION, device_core_1, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (DEVICE_CORE, DEVICE_CORE_VERSION, udp)."); exit(1); } transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, DEVICE_ASYNC, DEVICE_ASYNC_VERSION, device_async_1, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (DEVICE_ASYNC, DEVICE_ASYNC_VERSION, tcp)."); exit(1); } if (!svc_register(transp, DEVICE_CORE, DEVICE_CORE_VERSION, device_core_1, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (DEVICE_CORE, DEVICE_CORE_VERSION, tcp)."); exit(1); } svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */ } liblxi-1.20/src/vxi11core_xdr.c000066400000000000000000000256011443211710200163470ustar00rootroot00000000000000/* * Please do not edit this file. * It was generated using rpcgen. */ #include "vxi11core.h" bool_t xdr_Device_Link (XDR *xdrs, Device_Link *objp) { register int32_t *buf; if (!xdr_int (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp) { register int32_t *buf; if (!xdr_enum (xdrs, (enum_t *) objp)) return FALSE; return TRUE; } bool_t xdr_Device_Flags (XDR *xdrs, Device_Flags *objp) { register int32_t *buf; if (!xdr_int (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp) { register int32_t *buf; if (!xdr_int (xdrs, objp)) return FALSE; return TRUE; } bool_t xdr_Device_Error (XDR *xdrs, Device_Error *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; return TRUE; } bool_t xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_int (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; } else { IXDR_PUT_LONG(buf, objp->clientId); IXDR_PUT_BOOL(buf, objp->lockDevice); IXDR_PUT_U_LONG(buf, objp->lock_timeout); } if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_int (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; } else { objp->clientId = IXDR_GET_LONG(buf); objp->lockDevice = IXDR_GET_BOOL(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); } if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } if (!xdr_int (xdrs, &objp->clientId)) return FALSE; if (!xdr_bool (xdrs, &objp->lockDevice)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_string (xdrs, &objp->device, ~0)) return FALSE; return TRUE; } bool_t xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_short (xdrs, &objp->abortPort)) return FALSE; if (!xdr_u_int (xdrs, &objp->maxRecvSize)) return FALSE; return TRUE; } bool_t xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp) { register int32_t *buf; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_u_int (xdrs, &objp->size)) return FALSE; return TRUE; } bool_t xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->requestSize); IXDR_PUT_U_LONG(buf, objp->io_timeout); IXDR_PUT_U_LONG(buf, objp->lock_timeout); } if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; } else { objp->requestSize = IXDR_GET_U_LONG(buf); objp->io_timeout = IXDR_GET_U_LONG(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); } if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_u_int (xdrs, &objp->requestSize)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_char (xdrs, &objp->termChar)) return FALSE; return TRUE; } bool_t xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_int (xdrs, &objp->reason)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_u_char (xdrs, &objp->stb)) return FALSE; return TRUE; } bool_t xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp) { register int32_t *buf; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; return TRUE; } bool_t xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_int (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_int (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_int (xdrs, &objp->progVers)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->hostAddr); IXDR_PUT_U_LONG(buf, objp->hostPort); IXDR_PUT_U_LONG(buf, objp->progNum); IXDR_PUT_U_LONG(buf, objp->progVers); } if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_int (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_int (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_int (xdrs, &objp->progVers)) return FALSE; } else { objp->hostAddr = IXDR_GET_U_LONG(buf); objp->hostPort = IXDR_GET_U_LONG(buf); objp->progNum = IXDR_GET_U_LONG(buf); objp->progVers = IXDR_GET_U_LONG(buf); } if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } if (!xdr_u_int (xdrs, &objp->hostAddr)) return FALSE; if (!xdr_u_int (xdrs, &objp->hostPort)) return FALSE; if (!xdr_u_int (xdrs, &objp->progNum)) return FALSE; if (!xdr_u_int (xdrs, &objp->progVers)) return FALSE; if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily)) return FALSE; return TRUE; } bool_t xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp) { register int32_t *buf; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_bool (xdrs, &objp->enable)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40)) return FALSE; return TRUE; } bool_t xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp) { register int32_t *buf; if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; return TRUE; } bool_t xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp) { register int32_t *buf; if (xdrs->x_op == XDR_ENCODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_int (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_int (xdrs, &objp->datasize)) return FALSE; } else { IXDR_PUT_U_LONG(buf, objp->io_timeout); IXDR_PUT_U_LONG(buf, objp->lock_timeout); IXDR_PUT_LONG(buf, objp->cmd); IXDR_PUT_BOOL(buf, objp->network_order); IXDR_PUT_LONG(buf, objp->datasize); } if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } else if (xdrs->x_op == XDR_DECODE) { if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT); if (buf == NULL) { if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_int (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_int (xdrs, &objp->datasize)) return FALSE; } else { objp->io_timeout = IXDR_GET_U_LONG(buf); objp->lock_timeout = IXDR_GET_U_LONG(buf); objp->cmd = IXDR_GET_LONG(buf); objp->network_order = IXDR_GET_BOOL(buf); objp->datasize = IXDR_GET_LONG(buf); } if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } if (!xdr_Device_Link (xdrs, &objp->lid)) return FALSE; if (!xdr_Device_Flags (xdrs, &objp->flags)) return FALSE; if (!xdr_u_int (xdrs, &objp->io_timeout)) return FALSE; if (!xdr_u_int (xdrs, &objp->lock_timeout)) return FALSE; if (!xdr_int (xdrs, &objp->cmd)) return FALSE; if (!xdr_bool (xdrs, &objp->network_order)) return FALSE; if (!xdr_int (xdrs, &objp->datasize)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0)) return FALSE; return TRUE; } bool_t xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp) { register int32_t *buf; if (!xdr_Device_ErrorCode (xdrs, &objp->error)) return FALSE; if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0)) return FALSE; return TRUE; } liblxi-1.20/test/000077500000000000000000000000001443211710200136715ustar00rootroot00000000000000liblxi-1.20/test/receive-image-data.c000066400000000000000000000027611443211710200174540ustar00rootroot00000000000000#include #include #include // Example - send SCPI screenshot command to instrument and receive image data using RAW protocol // // Tested with Rohde & Schwarz RTB2004 DSO // // Similar operation can be done using netcat (nc): // // time echo "HCOPy:DATA?" | nc -w1 192.168.0.157 5025 | dd bs=1 skip=7 of=image.png int main() { char response[65536*2]; int device, timeout = 1000; char *command = "HCOPy:DATA?\n"; int recv_bytes, sent_bytes, total_recv_bytes = 0; int buffer_size_free = sizeof(response); // Initialize LXI library lxi_init(); // Connect LXI device device = lxi_connect("192.168.0.157", 5025, NULL, timeout, RAW); if (device < 0) { perror("Unable to connect\n"); return -1; } // Send SCPI command to request screenshot image data sent_bytes = lxi_send(device, command, strlen(command), timeout); if (sent_bytes <= 0) { perror("Send failure\n"); return -1; } // Keep receiving until all image data is received (meaning, until timeout) while (1) { recv_bytes = lxi_receive(device, response + total_recv_bytes, buffer_size_free, timeout); if (recv_bytes <= 0) break; total_recv_bytes += recv_bytes; buffer_size_free -= recv_bytes; } printf("Received %d bytes\n", total_recv_bytes); // Add code here to skip meta header and save only PNG image data to file // Disconnect lxi_disconnect(device); } liblxi-1.20/test/scpi.c000066400000000000000000000011371443211710200147750ustar00rootroot00000000000000#include #include #include // Example - send SCPI to instrument using VXI-11 protocol int main() { char response[65536]; int device, timeout = 3000; char *command = "*IDN?"; // Initialize LXI library lxi_init(); // Connect LXI device device = lxi_connect("10.42.0.42", 0, NULL, timeout, VXI11); // Send SCPI command lxi_send(device, command, strlen(command), timeout); // Wait for response lxi_receive(device, response, sizeof(response), timeout); printf("%s\n", response); // Disconnect lxi_disconnect(device); } liblxi-1.20/test/search-mdns.c000066400000000000000000000014371443211710200162460ustar00rootroot00000000000000#include #include // Example - Search for LXI instruments using mDNS discovery static void service_callback(const char *address, const char *id, const char *service, int port) { printf(" Found \"%s\" on address %s\n %s service on port %u\n\n", id, address, service, port); } static void broadcast_callback(const char *address, const char *interface) { printf("Broadcasting on interface %s\n\n", interface); } int main() { lxi_info_t info; // Initialize LXI library lxi_init(); // Set up search information callbacks info.service = &service_callback; info.broadcast = &broadcast_callback; printf("Searching for LXI devices - please wait...\n\n"); // Search for LXI devices, 1 second timeout lxi_discover(&info, 1000, DISCOVER_MDNS); return 0; } liblxi-1.20/test/search.c000066400000000000000000000012631443211710200153040ustar00rootroot00000000000000#include #include // Example - Search for LXI instruments using VXI-11 discovery void broadcast(const char *address, const char *interface) { printf("Broadcasting on interface %s\n", interface); } void device(const char *address, const char *id) { printf(" Found %s on address %s\n", id, address); } int main() { lxi_info_t info; // Initialize LXI library lxi_init(); // Set up search information callbacks info.broadcast = &broadcast; info.device = &device; printf("Searching for LXI devices - please wait...\n\n"); // Search for LXI devices, 1 second timeout lxi_discover(&info, 1000, DISCOVER_VXI11); return 0; }