├── .gitignore ├── README.md ├── examples ├── discover.py └── send_receive.py ├── lxi.py └── pyproject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # liblxi-python 2 | 3 | Python bindings for liblxi. 4 | 5 | ## Requirements 6 | 7 | Make sure you have python3 and liblxi installed. 8 | 9 | ## Installation 10 | 11 | To use the liblxi python bindings script put it next to your script or add the 12 | location of lxi.py to your PYTHONPATH variable. Also install the required 13 | dependencies as described below. 14 | 15 | ### Linux 16 | 17 | Install on Linux Debian based (Ubuntu, etc.): 18 | ``` 19 | sudo apt install liblxi1 python3 20 | ``` 21 | 22 | For other Linux distributions, consult your package manager tool. 23 | 24 | ### FreeBSD 25 | 26 | Install on FreeBSD: 27 | ``` 28 | pkg install liblxi python3 29 | ``` 30 | 31 | ## Run the example code 32 | 33 | Note: 34 | 35 | If it fails to find the liblxi library you can try preload it with the specific 36 | path to the library. For example: 37 | 38 | ``` 39 | $ LD_PRELOAD=$HOME/opt/lib/liblxi.so PYTHONPATH=. python3 ./examples/send_receive.py 192.168.0.157 40 | ``` 41 | 42 | ### Send and receive example 43 | 44 | Run the example test script with the IP of your instrument as argument: 45 | ``` 46 | $ PYTHONPATH=. python3 ./examples/send_receive.py 192.168.0.157 47 | Sent 5 bytes 48 | Sent command: *IDN? 49 | Received 49 bytes 50 | Received message: Rohde&Schwarz,RTB2004,1333.1005k04/113192,02.400 51 | ``` 52 | 53 | ### Discover example 54 | 55 | Search for instruments: 56 | ``` 57 | $ PYTHONPATH=. python3 ./examples/discover.py 58 | Broadcasting on lo using address 127.0.0.1 59 | Broadcasting on enxe4b97a86fdad using address 192.168.0.255 60 | Found Rohde&Schwarz,NGM202,3638.4472k03/101403,03.068 00A8F863604 on address 192.168.0.107 61 | Broadcasting on virbr0 using address 192.168.122.255 62 | ``` 63 | -------------------------------------------------------------------------------- /examples/discover.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # liblxi-python discover example script 4 | 5 | import lxi 6 | 7 | 8 | # Callback functions which are called during discovery 9 | 10 | def broadcast(address, interface): 11 | address = str(address, 'ascii') 12 | interface = str(interface, 'ascii') 13 | print("Broadcasting on " + interface + " using address " + address) 14 | return 15 | 16 | def device(address, id): 17 | address = str(address, 'ascii') 18 | id = str(id, 'ascii') 19 | print(" Found " + id + " on address " + address) 20 | return 21 | 22 | def service(address, id, service, port): 23 | address = str(address, 'ascii') 24 | id = str(id, 'ascii') 25 | service = str(service, 'ascii') 26 | port = str(port) 27 | print("Found " + id + " on address " + address) 28 | print(" " + service + " service on port " + port) 29 | return 30 | 31 | # Initialize library 32 | lxi.init() 33 | 34 | # Search for devices 35 | timeout = 1000 36 | info = lxi.lxi_info_class() 37 | info.broadcast = broadcast 38 | info.device = device 39 | info.service = service 40 | 41 | device = lxi.discover(info, timeout, lxi.discover_protocol.DISCOVER_VXI11) 42 | # device = lxi.discover(info, timeout, lxi.discover_protocol.DISCOVER_MDNS) 43 | 44 | -------------------------------------------------------------------------------- /examples/send_receive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # liblxi-python test script 4 | 5 | import lxi 6 | import sys 7 | 8 | max_msg_length = 5000 9 | timeout = 3000 10 | 11 | if len(sys.argv) != 2: 12 | print("Usage: %s " % sys.argv[0]) 13 | exit() 14 | 15 | # Initialize library 16 | lxi.init() 17 | 18 | # Connect to device 19 | device = lxi.connect(sys.argv[1], 0, "inst0", timeout, lxi.protocol.VXI11) 20 | 21 | # Send command 22 | command = "*IDN?" 23 | status = lxi.send(device, command, len(command), timeout) 24 | print("Sent " + str(status) + " bytes") 25 | print("Sent command: " + str(command)) 26 | 27 | # Receive command response 28 | status, message = lxi.receive(device, max_msg_length, timeout) 29 | print("Received " + str(status) + " bytes") 30 | print("Received message: " + message) 31 | 32 | # Disconnect 33 | lxi.disconnect(device) 34 | 35 | -------------------------------------------------------------------------------- /lxi.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021 Keep It Simple Solutions 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # 3. Neither the name of the copyright holders nor contributors may be 15 | # used to endorse or promote products derived from this software 16 | # without specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # 30 | 31 | # 32 | # Python bindings for liblxi 33 | # 34 | 35 | from ctypes import * 36 | from ctypes.util import find_library 37 | 38 | # Find library 39 | liblxi = find_library('lxi') 40 | if not liblxi: 41 | print("Could not find liblxi library") 42 | exit() 43 | 44 | # Load the library 45 | lib = cdll.LoadLibrary(liblxi) 46 | 47 | # Define functions 48 | def init(): 49 | lib.lxi_init() 50 | 51 | # Define types 52 | class LXI_INFO(Structure): 53 | _fields_ = [("broadcast", CFUNCTYPE(None, c_char_p, c_char_p )), 54 | ("device", CFUNCTYPE(None, c_char_p, c_char_p)), 55 | ("service", CFUNCTYPE(None, c_char_p, c_char_p, c_char_p, c_int))] 56 | 57 | class lxi_info_class: 58 | def broadcast(self, address, interface): 59 | return 60 | 61 | def device(self, address, id): 62 | return 63 | 64 | def service(self, address, id, service, port): 65 | return 66 | 67 | def discover(info: lxi_info_class, timeout: int, type: int): 68 | lib.lxi_discover.argtypes = c_void_p, c_int, c_int 69 | lib.lxi_discover.restype = c_int 70 | BROADCAST_FUNC = CFUNCTYPE(None, c_char_p, c_char_p) 71 | broadcast_func = BROADCAST_FUNC(info.broadcast) 72 | DEVICE_FUNC = CFUNCTYPE(None, c_char_p, c_char_p) 73 | device_func = DEVICE_FUNC(info.device) 74 | SERVICE_FUNC = CFUNCTYPE(None, c_char_p, c_char_p, c_char_p, c_int) 75 | service_func = SERVICE_FUNC(info.service) 76 | c_info_p = pointer(LXI_INFO(broadcast_func, device_func, service_func)) 77 | status = lib.lxi_discover(c_info_p, c_int(timeout), c_int(type)) 78 | return status 79 | 80 | def connect(address, port: int, name, timeout: int, protocol: int): 81 | lib.lxi_connect.argtypes = c_char_p, c_int, c_char_p, c_int, c_int 82 | lib.lxi_connect.restype = c_int 83 | address_bytes = str.encode(address, "ascii") 84 | name_bytes = str.encode(name, "ascii") 85 | device = lib.lxi_connect(address_bytes, c_int(port), name_bytes, c_int(timeout), c_int(protocol)) 86 | return device 87 | 88 | def send(device: int, message, length: int, timeout: int): 89 | lib.lxi_send.argtypes = c_int, c_char_p, c_int, c_int 90 | lib.lxi_send.restype = c_int 91 | message_bytes = str.encode(message) 92 | status = lib.lxi_send(c_int(device), message_bytes, c_int(length), c_int(timeout)) 93 | return status 94 | 95 | def receive(device: int, length: int, timeout: int): 96 | lib.lxi_receive.argtypes = c_int, c_char_p, c_int, c_int 97 | lib.lxi_receive.restype = c_int 98 | message_p = create_string_buffer(length) 99 | status = lib.lxi_receive(c_int(device), message_p, c_int(length), c_int(timeout)) 100 | message = str(message_p.value,"ascii") 101 | return status, message 102 | 103 | def disconnect(device: int): 104 | lib.lxi_disconnect.argtypes = (c_int,) 105 | lib.lxi_disconnect.restype = c_int 106 | status = lib.lxi_disconnect(device) 107 | return status 108 | 109 | class _protocol_: 110 | def __init__(self): 111 | self.VXI11 = 0 112 | self.RAW = 1 113 | 114 | protocol = _protocol_() 115 | 116 | class _discover_protocol_: 117 | def __init__(self): 118 | self.DISCOVER_VXI11 = 0 119 | self.DISCOVER_MDNS = 1 120 | 121 | discover_protocol = _discover_protocol_() 122 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | version = "1.0" 3 | name = "lxi" 4 | description = "Python bindings for liblxi" 5 | authors = [{name = "Martin Lund", email = "martin.lund@keep-it-simple.com"}] 6 | license = {text = "BSD"} 7 | readme = {file = "README.md", content-type = "text/markdown"} 8 | requires-python = ">=3" 9 | 10 | [project.urls] 11 | Homepage = "https://github.com/lxi-tools/liblxi-python" 12 | 13 | [build-system] 14 | requires = ["setuptools"] 15 | build-backend = "setuptools.build_meta" 16 | 17 | [tool.setuptools] 18 | py-modules = ["lxi"] 19 | --------------------------------------------------------------------------------