]> jspc29.x-matter.uni-frankfurt.de Git - trbnettools.git/commitdiff
libtrbnet_python v1.0.6
authorPhilipp Klaus <klaus@physik.uni-frankfurt.de>
Wed, 19 May 2021 09:10:55 +0000 (11:10 +0200)
committerPhilipp Klaus <klaus@physik.uni-frankfurt.de>
Wed, 19 May 2021 09:10:55 +0000 (11:10 +0200)
libtrbnet_python/README.md
libtrbnet_python/setup.cfg [new file with mode: 0644]
libtrbnet_python/setup.py
libtrbnet_python/trbnet/core/highlevel.py
libtrbnet_python/trbnet/core/lowlevel.py

index 49171ed88dd4bcad3c940dbf21c01a1823698e83..590d5c922cc32bce211b23cc7b562ab7578719f2 100644 (file)
@@ -1,6 +1,7 @@
 # PyTrbNet
 
-This is a Python package wrapping libtrbnet.so.
+This is a Python package wrapping libtrbnet.so
+from trbnettools.
 It allows accessing trbnet registers from Python.
 
 The package comes with two additional features:
@@ -11,7 +12,124 @@ The package comes with two additional features:
   status information to the EPICS detector control
   system.
 
+### Installation
+
+This package can be installed from the Python Package
+Index via:
+
+    pip install trbnet
+
+### Configuration / Setup
+
+As this Python package depends on the shared library
+libtrbnet.so for the communication with TrbNet,
+its location needs to be provided.
+This can be done by setting the environment variable
+`LIBTRBNET`.
+
+libtrbnet.so in turn requires the environment variables
+`DAQOPSERVER` (if talking to TrbNet via a trbnetd daemon)
+or the IP of a TRB Board: `TRB3_SERVER` (if talking to
+TrbNet directly).
+
+A fourth environment variable `XMLDB` comes into play,
+if the xmldb capabilities of this Python package are
+to be used. It should point to the location of the
+xml-db for your system.
+
+Those environment variables can also be set from within
+Python with their lowercase variants
+`libtrbnet`, `daqopserver`, and `trb3_server` upon
+instantiating the TrbNet() class.
+
+Here's an example using environment variables in the shell:
+
+
+```sh
+# Setting the relevant environment variables
+export LIBTRBNET=/local/gitrepos/trbnettools/trbnetd/libtrbnet.so
+export DAQOPSERVER=jspc55.x-matter.uni-frankfurt.de:1
+export XMLDB=/local/gitrepos/daqtools/xml-db/database
+
+# example call to get the value in the compile time
+# register for all reachable TRBs:
+trbcmd.py xmlget 0xffff TrbNet CompileTime
+
+# With the environment variables set, you could also
+# run Python and instantiate TrbNet(). It would
+# pick up the settings from the exported variables.
+```
+
+or by setting the variables from within Python:
+
+```python
+import os
+from trbnet import TrbNet
+
+lib = '/local/gitrepos/trbnettools/trbnetd/libtrbnet.so'
+host = 'trbnetd_host:8888'
+t = TrbNet(libtrbnet=lib, daqopserver=host)
+# 0x40 is the register address of CompileTime
+t.register_read(0xffff, 0x40)
+```
+
+### Usage with Python
+
+To read the content of the register address 0x0 for all
+connected TrbNet boards (broadcast address 0xffff), do:
+
+```python
+import os
+from trbnet import TrbNet
+
+t = TrbNet()
+
+response = t.register_read(0xffff, 0x0)
+for endpoint in response:
+    print("endpoint 0x{:08X} responded with: 0x{:08X}".format(endpoint, response[endpoint]))
+```
+
+The TrbNet() class has the following methods:
+
+* `register_read(trb_address, reg_address)`
+* `register_write(trb_address, reg_address, value)`
+* `register_read_mem(trb_address, reg_address, option, size)`
+* `read_uid(trb_address)`
+* Furthermore, multiple methods starting with `trb_` (e.g. `trb_set_address(uid, endpoint, trb_address)`)
+  can be called as they are inherited from [the parent class `_TrbNet`][trbnet/core/lowlevel.py].
+
+### Usage of the Terminal Utility trbcmd.py
+
+The package comes with a simple command line utility called `trbcmd.py`.
+It is a Python counterpart for the trbcmd utility provided
+by trbnettools.
+
+What it can do:
+
+**read register values**
+
+```
+trbcmd.py r 0xffff 0x0
+```
+
+**read memory (subsequent register addresses)**
+
+Read three registers starting at 0x8005 from all boards:
+```
+trbcmd.py rm 0xffff 0x8005 0x3 0x0
+```
+
+**xml-db queries**
+
+Ask all TrbNet nodes (broadcast 0xffff) for the register value of CompileTime as set in TrbNet.xml:
+
+```
+trbcmd.py xmlget 0xffff TrbNet       CompileTime
+```
+
 ### Resources
 
 * [The TRB Website](http://trb.gsi.de)
 * [TrbNet Manual](http://jspc29.x-matter.uni-frankfurt.de/docu/trbnetdocu.pdf)
+
+[trbnet/core/lowlevel.py]: https://github.com/pklaus/pytrbnet/blob/master/trbnet/core/lowlevel.py
diff --git a/libtrbnet_python/setup.cfg b/libtrbnet_python/setup.cfg
new file mode 100644 (file)
index 0000000..c579df8
--- /dev/null
@@ -0,0 +1,38 @@
+[metadata]
+name = trbnet
+version = 1.0.6
+description = Interface to TrbNet (wrapping libtrbnet.so with ctypes)
+long_description = file: README.md
+long_description_content_type = text/markdown
+author = Philipp Klaus
+author_email = klaus@physik.uni-frankfurt.de
+url = https://github.com/pklaus/pytrbnet
+license = GPL
+platforms = Linux
+keywords = TrbNet, PyTrbNet, FPGA, low-latency, network, libtrbnet, wrapper
+classifiers =
+    Development Status :: 4 - Beta
+    Operating System :: OS Independent
+    License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
+    Programming Language :: Python
+    Programming Language :: Python :: 3
+    Topic :: Scientific/Engineering :: Physics
+    Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
+    Topic :: System :: Hardware :: Hardware Drivers
+
+[options]
+packages = trbnet, trbnet.core, trbnet.xmldb, trbnet.util, trbnet.epics
+zip_safe = True
+include_package_data = False
+install_requires = 
+    lxml
+    click
+    enum34; python_version < "3.4"
+    typing; python_version < "3.5"
+
+[options.entry_points]
+console_scripts =
+    trbcmd.py = trbnet.util.trbcmd:cli
+
+[options.extras_require]
+epics: pcaspy
index 691ef760d08541e916d1f761f0099ae57dc0566b..29abe9328f8a089c12d77951ded27aa12799f265 100644 (file)
@@ -1,56 +1,7 @@
-# -*- coding: utf-8 -*-
+from setuptools import setup
 
-try:
-    from setuptools import setup
-except ImportError:
-    from distutils.core import setup
-
-try:
-    import pypandoc
-    LDESC = open('README.md', 'r').read()
-    LDESC = pypandoc.convert_text(LDESC, 'rst', format='md')
-except (ImportError, IOError, RuntimeError) as e:
-    print("Could not create long description:")
-    print(str(e))
-    LDESC = ''
-
-setup(name='trbnet',
-      version = '1.0.dev0',
-      description = 'Interface to TrbNet (wrapping libtrbnet.so with ctypes)',
-      long_description = LDESC,
-      author = 'Philipp Klaus',
-      author_email = 'klaus@physik.uni-frankfurt.de',
-      url = 'https://github.com/pklaus/pytrbnet',
-      license = 'GPL',
-      packages = [
-          'trbnet',
-          'trbnet.core',
-          'trbnet.xmldb',
-          'trbnet.util',
-          'trbnet.epics',
-          ],
-      entry_points = {
-          'console_scripts': [
-              'trbcmd.py = trbnet.util.trbcmd:cli',
-          ],
-      },
-      include_package_data = False,
-      zip_safe = True,
-      platforms = 'Linux',
-      install_requires = [
-          "lxml",
-          "click",
-          "enum34", # for support of enum.IntEnum on Python < 3.4
-      ],
-      keywords = 'TrbNet PyTrbNet FPGA Low-latency network wrapper',
-      classifiers = [
-          'Development Status :: 4 - Beta',
-          'Operating System :: OS Independent',
-          'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
-          'Programming Language :: Python',
-          'Programming Language :: Python :: 3',
-          'Topic :: Scientific/Engineering :: Physics',
-          'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator',
-          'Topic :: System :: Hardware :: Hardware Drivers',
-      ]
+setup(
+    setup_requires=[
+        'setuptools >= 38.6.0'
+    ]
 )
index 2d441b6ba0e61e9738413570964dc70866502ffd..15bd4a8a65f2126fca29c6bdbae371993614c7da 100644 (file)
@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
+from typing import List, Tuple, Dict
+
 from .lowlevel import _TrbNet
 
 
@@ -7,18 +9,18 @@ class TrbNet(_TrbNet):
     High level wrapper providing utility functions for the TrbNet class
     '''
 
-    def register_read(self, trb_address, reg_address):
+    def register_read(self, trb_address: int, reg_address: int) -> Dict[int, int]:
         lin_data = super().trb_register_read(trb_address, reg_address)
         if (len(lin_data) % 2) != 0:
             raise ValueError("len(lin_data) == %d -  expected a multiple of %d" % (len(lin_data), 2))
         result = self._get_dynamic_trb_address_dict(lin_data, force_length=1)
         return {key: value[0] for key, value in result.items()}
 
-    def register_read_mem(self, trb_address, reg_address, option, size):
+    def register_read_mem(self, trb_address: int, reg_address: int, option: int, size: int) -> Dict[int, List[int]]:
         lin_data = super().trb_register_read_mem(trb_address, reg_address, option, size)
         return self._get_dynamic_trb_address_dict(lin_data)
 
-    def read_uid(self, trb_address):
+    def read_uid(self, trb_address: int) -> Dict[Tuple[int, int], int]:
         '''
         Read unique id of TrbNet nodes
 
@@ -35,7 +37,7 @@ class TrbNet(_TrbNet):
         uid_dict = {((r[0] << 32) + r[1], r[2]): r[3] for r in responses}
         return uid_dict
 
-    def _get_dynamic_trb_address_dict(self, lin_data, force_length=0):
+    def _get_dynamic_trb_address_dict(self, lin_data: List[int], force_length: int = 0) -> Dict[int, List[int]]:
         """
         A utility function to structure response data from the
         trb_register_read() and trb_register_read_mem() functions.
@@ -57,3 +59,9 @@ class TrbNet(_TrbNet):
             trb_address_responses[trb_address] = lin_data[offset:offset+length]
             offset += length
         return trb_address_responses
+
+    def register_write(self, trb_address: int, reg_address: int, value: int):
+        """
+        Convenience wrapper for trb_register_write()
+        """
+        super().trb_register_write(trb_address, reg_address, value)
index 2f1be021fde89b60079c8c34490f3fc02cfc5d25..f2b989ec5bfa6c4d2e6ae30b897c88c1c1f98e06 100644 (file)
@@ -2,6 +2,8 @@
 import ctypes
 import os
 
+from typing import List, Tuple, Union
+
 from .error import TrbException
 
 # TODO: use warnings to indicate access to wrong register or no data
@@ -22,7 +24,7 @@ class _TrbNet(object):
     Wrapper class for trbnet access using python
     '''
 
-    def __init__(self, libtrbnet=None, daqopserver=None, trb3_server=None, buffersize=4194304):
+    def __init__(self, libtrbnet: str = None, daqopserver: str = None, trb3_server: str = None, buffersize: int = 4194304):
         '''
         Constructor for the low level TrbNet class.
         Loads the shared library (libtrbnet), sets enviromental variables and initialises ports.
@@ -45,13 +47,13 @@ class _TrbNet(object):
         trb3_server -- optional override of the TRB3_SERVER enviromental variable
         buffersize -- Size of the buffer in 32-bit words when reading back data (default: 16MiB)
         '''
-        if trb3_server: os.environ['TRB3_SERVER'] = trb3_server
-        if daqopserver: os.environ['DAQOPSERVER'] = daqopserver
-        self.buffersize = buffersize
         if not libtrbnet:
             from .libutils import _find_lib
             libtrbnet =_find_lib('trbnet')
         self.libtrbnet = libtrbnet
+        if daqopserver: os.environ['DAQOPSERVER'] = daqopserver
+        if trb3_server: os.environ['TRB3_SERVER'] = trb3_server
+        self.buffersize = buffersize
         self.trblib = ctypes.cdll.LoadLibrary(libtrbnet)
         self.declare_types()
         status = self.trblib.init_ports()
@@ -68,13 +70,17 @@ class _TrbNet(object):
         except AttributeError:
             pass
 
-    def trb_errno(self):
+    def trb_errno(self) -> int:
         '''
         Returns trb_errno flag value
         '''
         return ctypes.c_int.in_dll(self.trblib, 'trb_errno').value
 
-    def trb_term(self):
+    def trb_term(self) -> Tuple[int, int, int, int]:
+        '''
+        Return the TRB_TERM info as tuple consisting of:
+        (status_common, status_channel, sequence, channel)
+        '''
         term = TrbTerm.in_dll(self.trblib, 'trb_term')
         return (term.status_common, term.status_channel, term.sequence, term.channel)
 
@@ -91,6 +97,9 @@ class _TrbNet(object):
         self.trblib.trb_register_read_mem.argtypes = [ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint8, ctypes.c_uint16,
                                                       ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint]
         self.trblib.trb_register_read_mem.restype = ctypes.c_int
+        self.trblib.trb_register_write_mem.argtypes = [ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint8,
+                                                      ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint16]
+        self.trblib.trb_register_read_mem.restype = ctypes.c_int
         self.trblib.trb_registertime_read_mem.argtypes = [ctypes.c_uint16, ctypes.c_uint16, ctypes.c_uint8, ctypes.c_uint16,
                                                           ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint]
         self.trblib.trb_registertime_read_mem.restype = ctypes.c_int
@@ -127,7 +136,7 @@ class _TrbNet(object):
         self.trblib.trb_termstr.restype = ctypes.c_char_p
         
 
-    def trb_errorstr(self, errno):
+    def trb_errorstr(self, errno: int) -> str:
         '''
         Get error string for an integer error number.
 
@@ -141,7 +150,7 @@ class _TrbNet(object):
         _result = self.trblib.trb_errorstr(errno)
         return _result.decode('ascii')
 
-    def trb_register_read(self, trb_address, reg_address):
+    def trb_register_read(self, trb_address: int, reg_address: int) -> List[int]:
         '''
         Read value from trb register.
 
@@ -161,7 +170,7 @@ class _TrbNet(object):
             raise TrbException('Error while reading trb register.', errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_register_write(self, trb_address, reg_address, value):
+    def trb_register_write(self, trb_address: int, reg_address: int, value: int):
         '''
         Write trb register
 
@@ -178,7 +187,7 @@ class _TrbNet(object):
             errno = self.trb_errno()
             raise TrbException('Error while writing trb register.', errno, self.trb_errorstr(errno))
 
-    def trb_register_read_mem(self, trb_address, reg_address, option, size):
+    def trb_register_read_mem(self, trb_address: int, reg_address: int, option: int, size: int) -> List[int]:
         '''
         Perform several trb register reads
 
@@ -196,14 +205,37 @@ class _TrbNet(object):
         trb_address = ctypes.c_uint16(trb_address)
         reg_address = ctypes.c_uint16(reg_address)
         option = ctypes.c_uint8(option)
-        status = self.trblib.trb_register_read_mem(trb_address, reg_address, option, ctypes.c_uint16(size), data_array, ctypes.c_uint(self.buffersize))
+        size = ctypes.c_uint16(size)
+        dsize = ctypes.c_uint(self.buffersize)
+        status = self.trblib.trb_register_read_mem(trb_address, reg_address, option, size, data_array, dsize)
         if status == -1:
             errno = self.trb_errno()
             raise TrbException('Error while reading trb register memory.',
                                errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_read_uid(self, trb_address):
+    def trb_register_write_mem(self, trb_address: int, reg_address: int, option: int, values: List[int], size: int = None):
+        '''
+        Write several trb registers
+
+        Arguments:
+        trb_address -- node(s) to write to
+        reg_address -- register address
+        option -- write option, 0 = write same register several times 1 = write adjacent registers
+        values -- list of values to write to register(s)
+        '''
+
+        data_array = (ctypes.c_uint32 * len(values))(*values)
+        trb_address = ctypes.c_uint16(trb_address)
+        reg_address = ctypes.c_uint16(reg_address)
+        option = ctypes.c_uint8(option)
+        size = size or ctypes.c_uint16(len(values))
+        status = self.trblib.trb_register_write_mem(trb_address, reg_address, option, data_array, size)
+        if status == -1:
+            errno = self.trb_errno()
+            raise TrbException('Error while writing trb register memory.', errno, self.trb_errorstr(errno))
+
+    def trb_read_uid(self, trb_address: int) -> List[int]:
         '''
         Read unique id(s) of TrbNet node(s)
 
@@ -226,7 +258,7 @@ class _TrbNet(object):
                                errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_set_address(self, uid, endpoint, trb_address):
+    def trb_set_address(self, uid: int, endpoint: int, trb_address: int):
         '''
         Set trb net address
 
@@ -246,15 +278,15 @@ class _TrbNet(object):
 
 #  rarely used funtions without documentation in trbnet.h
 #  meaning of arguments and returned data unknown
-    def network_reset(self):
+    def network_reset(self) -> int:
         '''TRB network reset'''
         return self.trblib.network_reset()
 
-    def com_reset(self):
+    def com_reset(self) -> int:
         '''communication reset'''
         return self.trblib.com_reset()
 
-    def trb_fifo_flush(self, channel):
+    def trb_fifo_flush(self, channel: int) -> int:
         '''flush trb fifo
 
         Arguments:
@@ -262,7 +294,7 @@ class _TrbNet(object):
         channel = ctypes.c_uint8(channel)
         return self.trblib.trb_fifo_flush(channel)
 
-    def trb_send_trigger(self, trigtype, info, random, number):
+    def trb_send_trigger(self, trigtype: int, info: int, random: int, number: int) -> int:
         '''send trigger to trb
 
         Arguments:
@@ -277,21 +309,21 @@ class _TrbNet(object):
         number = ctypes.c_uint16(number)
         return self.trblib.trb_send_trigger(trigtype, info, random, number)
 
-    def trb_register_setbit(self, trb_address, reg_address, bitmask):
+    def trb_register_setbit(self, trb_address: int, reg_address: int, bitmask: int) -> int:
         trb_address = ctypes.c_uint16(trb_address)
         reg_address = ctypes.c_uint16(reg_address)
         bitmask = ctypes.c_uint32(bitmask)
         return self.trblib.trb_register_setbit(trb_address, reg_address,
                                                bitmask)
 
-    def trb_register_clearbit(self, trb_address, reg_address, bitmask):
+    def trb_register_clearbit(self, trb_address: int, reg_address: int, bitmask: int) -> int:
         trb_address = ctypes.c_uint16(trb_address)
         reg_address = ctypes.c_uint16(reg_address)
         bitmask = ctypes.c_uint32(bitmask)
         return self.trblib.trb_register_clearbit(trb_address, reg_address,
                                                  bitmask)
 
-    def trb_register_loadbit(self, trb_address, reg_address, bitmask, bitvalue):
+    def trb_register_loadbit(self, trb_address: int, reg_address: int, bitmask: int, bitvalue: int) -> int:
         trb_address = ctypes.c_uint16(trb_address)
         reg_address = ctypes.c_uint16(reg_address)
         bitmask = ctypes.c_uint32(bitmask)
@@ -299,39 +331,43 @@ class _TrbNet(object):
         return self.trblib.trb_register_loadbit(trb_address, reg_address,
                                                 bitmask, bitvalue)
 
-    def trb_registertime_read_mem(self, trb_address, reg_address, option, size):
-        data_array = (ctypes.c_uint32 * self.buffersize)()
+    def trb_registertime_read_mem(self, trb_address: int, reg_address: int, option: int, size: int) -> List[int]:
         trb_address = ctypes.c_uint16(trb_address)
         reg_address = ctypes.c_uint16(reg_address)
         option = ctypes.c_uint8(option)
-        status = self.trblib.trb_register_read_mem(trb_address, reg_address, option, ctypes.c_uint16(size), data_array, ctypes.c_uint(self.buffersize))
+        size = ctypes.c_uint16(size)
+        data_array = (ctypes.c_uint32 * self.buffersize)()
+        dsize = ctypes.c_uint(self.buffersize)
+        status = self.trblib.trb_registertime_read_mem(trb_address, reg_address, option, size, data_array, dsize)
         if status == -1:
             errno = self.trb_errno()
             raise TrbException('Error while reading trb register memory.', errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_ipu_data_read(self, trg_type, trg_info, trg_random, trg_number, size):
+    def trb_ipu_data_read(self, trg_type: int, trg_info: int, trg_random: int, trg_number: int, size: int) -> List[int]:
         trg_type = ctypes.c_uint8(trg_type)
         trg_info = ctypes.c_uint8(trg_info)
         trg_random = ctypes.c_uint8(trg_random)
         trg_number = ctypes.c_uint16(trg_number)
         data_array = (ctypes.c_uint32 * self.buffersize)()
-        status = self.trblib.trb_ipu_data_read(trg_type, trg_info, trg_random, trg_number, data_array, ctypes.c_uint(self.buffersize))
+        dsize = ctypes.c_uint(self.buffersize)
+        status = self.trblib.trb_ipu_data_read(trg_type, trg_info, trg_random, trg_number, data_array, dsize)
         if status == -1:
             errno = self.trb_errno()
             raise TrbException('Error while reading trb ipu data.', errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_nettrace(self, trb_address, size):
+    def trb_nettrace(self, trb_address: int):
         trb_address = ctypes.c_uint16(trb_address)
         data_array = (ctypes.c_uint32 * self.buffersize)()
-        status = self.trblib.trb_nettrace(trb_address, data_array, ctypes.c_uint(self.buffersize))
+        dsize = ctypes.c_uint(self.buffersize)
+        status = self.trblib.trb_nettrace(trb_address, data_array, dsize)
         if status == -1:
             errno = self.trb_errno()
             raise TrbException('Error while doing net trace.', errno, self.trb_errorstr(errno))
         return [data_array[i] for i in range(status)]
 
-    def trb_termstr(self, term):
+    def trb_termstr(self, term: Union[Tuple[int, int, int, int], TrbTerm]) -> str:
         '''
         Get string representation for network termination packet info tuple.