syndesi 0.4.0__py3-none-any.whl → 0.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syndesi/adapters/adapter.py +91 -158
- syndesi/adapters/auto.py +1 -1
- syndesi/adapters/backend/adapter_backend.py +54 -37
- syndesi/adapters/backend/adapter_session.py +26 -27
- syndesi/adapters/backend/backend_status.py +0 -0
- syndesi/adapters/backend/backend_tools.py +1 -1
- syndesi/adapters/backend/descriptors.py +3 -2
- syndesi/adapters/backend/ip_backend.py +1 -0
- syndesi/adapters/backend/serialport_backend.py +9 -10
- syndesi/adapters/backend/stop_condition_backend.py +47 -26
- syndesi/adapters/backend/visa_backend.py +7 -7
- syndesi/adapters/ip.py +6 -10
- syndesi/adapters/stop_condition.py +10 -83
- syndesi/adapters/timeout.py +3 -30
- syndesi/adapters/visa.py +2 -2
- syndesi/cli/backend_status.py +7 -9
- syndesi/cli/console.py +1 -54
- syndesi/cli/shell.py +1 -14
- syndesi/cli/shell_tools.py +0 -5
- syndesi/protocols/delimited.py +17 -37
- syndesi/protocols/modbus.py +17 -14
- syndesi/protocols/raw.py +20 -16
- syndesi/protocols/scpi.py +18 -15
- syndesi/scripts/syndesi.py +1 -3
- syndesi/tools/backend_api.py +5 -38
- syndesi/tools/backend_logger.py +0 -1
- syndesi/tools/errors.py +4 -5
- syndesi/tools/log.py +0 -88
- syndesi/tools/types.py +0 -44
- syndesi/version.py +1 -1
- syndesi-0.4.2.dist-info/METADATA +96 -0
- syndesi-0.4.2.dist-info/RECORD +60 -0
- syndesi-0.4.0.dist-info/METADATA +0 -123
- syndesi-0.4.0.dist-info/RECORD +0 -59
- {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/WHEEL +0 -0
- {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/entry_points.txt +0 -0
- {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {syndesi-0.4.0.dist-info → syndesi-0.4.2.dist-info}/top_level.txt +0 -0
syndesi/tools/errors.py
CHANGED
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
PACKAGE_PATH = Path(__file__).resolve().parent.parent
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
class SyndesiError(Exception):
|
|
10
11
|
"""Base class for all Syndesi errors"""
|
|
11
12
|
|
|
@@ -26,7 +27,7 @@ class AdapterError(SyndesiError):
|
|
|
26
27
|
"""Error inside an adapter frontend"""
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def make_error_description(e
|
|
30
|
+
def make_error_description(e: Exception) -> str:
|
|
30
31
|
tb = e.__traceback__
|
|
31
32
|
if tb is None:
|
|
32
33
|
error_message = ""
|
|
@@ -44,8 +45,6 @@ def make_error_description(e : Exception) -> str:
|
|
|
44
45
|
frame = tb.tb_frame
|
|
45
46
|
line_no = tb.tb_lineno
|
|
46
47
|
filename = frame.f_code.co_filename
|
|
47
|
-
error_message =
|
|
48
|
-
f"{_type} : {extra_arguments} {filename}:{line_no}"
|
|
49
|
-
)
|
|
48
|
+
error_message = f"{_type} : {extra_arguments} {filename}:{line_no}"
|
|
50
49
|
|
|
51
|
-
return error_message
|
|
50
|
+
return error_message
|
syndesi/tools/log.py
CHANGED
|
@@ -9,94 +9,6 @@ from typing import TextIO
|
|
|
9
9
|
from .backend_logger import BackendLogger
|
|
10
10
|
from .log_settings import LoggerAlias
|
|
11
11
|
|
|
12
|
-
# class LogManager:
|
|
13
|
-
# _instance = None
|
|
14
|
-
# _lock = threading.Lock()
|
|
15
|
-
# _initialized : bool = False
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# DEFAULT_FORMATTER = logging.Formatter(
|
|
19
|
-
# "%(asctime)s:%(name)s:%(levelname)s:%(message)s"
|
|
20
|
-
# )
|
|
21
|
-
# DEFAULT_LOG_LEVEL = logging.ERROR
|
|
22
|
-
|
|
23
|
-
# def __new__(cls) -> "LogManager":
|
|
24
|
-
# with cls._lock:
|
|
25
|
-
# if cls._instance is None:
|
|
26
|
-
# cls._instance = super(LogManager, cls).__new__(cls)
|
|
27
|
-
# cls._instance._initialized = False
|
|
28
|
-
# return cls._instance
|
|
29
|
-
|
|
30
|
-
# def __init__(self) -> None:
|
|
31
|
-
# if self._initialized:
|
|
32
|
-
# return
|
|
33
|
-
# self._initialized = True
|
|
34
|
-
# self._file_handler : logging.Handler | None = None
|
|
35
|
-
# self._all_loggers = False
|
|
36
|
-
# self._loggers : list[str] = []
|
|
37
|
-
# self._level = self.DEFAULT_LOG_LEVEL
|
|
38
|
-
# self._stream_handler : logging.StreamHandler[TextIO] | None = None
|
|
39
|
-
# self._backend_logger = BackendLogger()
|
|
40
|
-
# self._backend_logger.start()
|
|
41
|
-
|
|
42
|
-
# def set_log_level(self, level: str | int) -> None:
|
|
43
|
-
# if isinstance(level, str):
|
|
44
|
-
# if not hasattr(logging, level.upper()):
|
|
45
|
-
# raise ValueError(f"Invalid log level: {level}")
|
|
46
|
-
# internal_level = getattr(logging, level.upper())
|
|
47
|
-
# elif isinstance(level, int):
|
|
48
|
-
# internal_level = level
|
|
49
|
-
# else:
|
|
50
|
-
# raise ValueError(f"Invalid level : {level}")
|
|
51
|
-
|
|
52
|
-
# self._level = internal_level
|
|
53
|
-
# self.update_loggers()
|
|
54
|
-
|
|
55
|
-
# def set_console_log(self, enabled: bool) -> None:
|
|
56
|
-
# if enabled:
|
|
57
|
-
# self._stream_handler = logging.StreamHandler()
|
|
58
|
-
# self._stream_handler.setFormatter(self.DEFAULT_FORMATTER)
|
|
59
|
-
# else:
|
|
60
|
-
# self._stream_handler = None
|
|
61
|
-
|
|
62
|
-
# def set_log_file(self, file: str | None) -> None:
|
|
63
|
-
# if file is not None:
|
|
64
|
-
# self._file_handler = logging.FileHandler(file)
|
|
65
|
-
# self._file_handler.setFormatter(self.DEFAULT_FORMATTER)
|
|
66
|
-
# else:
|
|
67
|
-
# if self._file_handler is not None:
|
|
68
|
-
# self._file_handler.close()
|
|
69
|
-
# self._file_handler = None
|
|
70
|
-
|
|
71
|
-
# def set_logger_filter(self, loggers: list[str] | str) -> None:
|
|
72
|
-
# self._all_loggers = False
|
|
73
|
-
# self._loggers = []
|
|
74
|
-
# if isinstance(loggers, list):
|
|
75
|
-
# self._loggers = loggers
|
|
76
|
-
# elif isinstance(loggers, str):
|
|
77
|
-
# if loggers == "all":
|
|
78
|
-
# self._all_loggers = True
|
|
79
|
-
# else:
|
|
80
|
-
# self._loggers = [loggers]
|
|
81
|
-
# else:
|
|
82
|
-
# raise ValueError("Invalid argument loggers")
|
|
83
|
-
|
|
84
|
-
# def update_loggers(self) -> None:
|
|
85
|
-
# # 1) Remove everything
|
|
86
|
-
# for alias in LoggerAlias:
|
|
87
|
-
# logger = logging.getLogger(alias.value)
|
|
88
|
-
# logger.handlers.clear()
|
|
89
|
-
# # 2) Update
|
|
90
|
-
# for alias in LoggerAlias:
|
|
91
|
-
# if self._all_loggers or alias.value in self._loggers:
|
|
92
|
-
# logger = logging.getLogger(alias.value)
|
|
93
|
-
# if self._file_handler is not None:
|
|
94
|
-
# logger.addHandler(self._file_handler)
|
|
95
|
-
# if self._stream_handler is not None:
|
|
96
|
-
# logger.addHandler(self._stream_handler)
|
|
97
|
-
# logger.setLevel(self._level)
|
|
98
|
-
|
|
99
|
-
|
|
100
12
|
class LogManager:
|
|
101
13
|
_lock = threading.Lock()
|
|
102
14
|
|
syndesi/tools/types.py
CHANGED
|
@@ -2,20 +2,6 @@
|
|
|
2
2
|
# Author : Sébastien Deriaz
|
|
3
3
|
# License : GPL
|
|
4
4
|
|
|
5
|
-
# try:
|
|
6
|
-
# import numpy as np
|
|
7
|
-
# HAS_NUMPY = True
|
|
8
|
-
# except ImportError:
|
|
9
|
-
# HAS_NUMPY = False
|
|
10
|
-
# class _Default : __slots__ = ()
|
|
11
|
-
# DEFAULT : Final[_Default] = _Default()
|
|
12
|
-
# EllipsisType : TypeAlias = _Default
|
|
13
|
-
# def is_default(x : Any) -> TypeGuard[EllipsisType]:
|
|
14
|
-
# return x is DEFAULT
|
|
15
|
-
# DEFAULT : EllipsisType = ...
|
|
16
|
-
# EllipsisType : TypeAlias = EllipsisType
|
|
17
|
-
# def is_default(x : Any) -> TypeGuard[EllipsisType]:
|
|
18
|
-
# return x is DEFAULT
|
|
19
5
|
from typing import TYPE_CHECKING, Any, TypeGuard
|
|
20
6
|
|
|
21
7
|
try:
|
|
@@ -30,36 +16,6 @@ if TYPE_CHECKING:
|
|
|
30
16
|
else:
|
|
31
17
|
NumberLike = int | float | np.number # runtime will resolve string
|
|
32
18
|
|
|
33
|
-
# def is_byte_instance(X : Any):
|
|
34
|
-
# """
|
|
35
|
-
# Check if the given X is an instance of bytearray or bytes
|
|
36
|
-
|
|
37
|
-
# Parameters
|
|
38
|
-
# ----------
|
|
39
|
-
# X : any
|
|
40
|
-
|
|
41
|
-
# Returns
|
|
42
|
-
# -------
|
|
43
|
-
# result : bool
|
|
44
|
-
# """
|
|
45
|
-
# result = isinstance(X, (bytearray, bytes))
|
|
46
|
-
# return result
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# def assert_byte_instance(*args):
|
|
50
|
-
# """
|
|
51
|
-
# Checks if the given argument(s) is of type bytes
|
|
52
|
-
# or bytes. A TypeError is raised if it isn't the case
|
|
53
|
-
|
|
54
|
-
# Parameters
|
|
55
|
-
# ----------
|
|
56
|
-
# args
|
|
57
|
-
# """
|
|
58
|
-
# for arg in args:
|
|
59
|
-
# if not is_byte_instance(arg):
|
|
60
|
-
# raise TypeError(f"Variable {arg} should be of type bytes or bytes")
|
|
61
|
-
|
|
62
|
-
|
|
63
19
|
def is_number(X: Any) -> TypeGuard[NumberLike]:
|
|
64
20
|
"""
|
|
65
21
|
Check if the given X is an instance of int or float
|
syndesi/version.py
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: syndesi
|
|
3
|
+
Version: 0.4.2
|
|
4
|
+
Summary: Syndesi
|
|
5
|
+
Author-email: Sébastien Deriaz <sebastien.deriaz1@gmail.com>
|
|
6
|
+
License: GPL
|
|
7
|
+
Keywords: python,syndesi,interface,ethernet,serial,visa
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Education
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: Unix
|
|
12
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: prompt_toolkit
|
|
18
|
+
Requires-Dist: pyserial
|
|
19
|
+
Requires-Dist: rich
|
|
20
|
+
Requires-Dist: platformdirs
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Syndesi Python Implementation
|
|
24
|
+
|
|
25
|
+
Syndesi description is available [here](https://github.com/syndesi-project/Syndesi/README.md)
|
|
26
|
+
|
|
27
|
+
Syndesi is a modular Python framework designed to streamline communication and control of a wide range of electronic instruments and devices. By providing a unified abstraction layer for adapters, protocols, and device drivers, Syndesi enables seamless integration with test equipment such as multimeters, oscilloscopes, power supplies, UART/USB devices, and more. Its flexible architecture supports both high-level and low-level operations, making it ideal for automation, data acquisition, and custom device interfacing in laboratory, industrial, and research environments.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
The syndesi Python package can be installed through pip
|
|
32
|
+
|
|
33
|
+
``pip install syndesi``
|
|
34
|
+
|
|
35
|
+
The package can also be installed locally by cloning this repository
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/syndesi-project/Syndesi
|
|
39
|
+
cd Syndesi
|
|
40
|
+
pip install .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
The user can work with any of the three following layers :
|
|
46
|
+
|
|
47
|
+
- Adapters : low-level communication (IP, UART, ...)
|
|
48
|
+
- Protocols : Encapsulated protocols (Delimited, Modbus, ...)
|
|
49
|
+
- Drivers : Device or application specific commands
|
|
50
|
+
|
|
51
|
+
### Adapters
|
|
52
|
+
|
|
53
|
+
The adapter allows the user to read and write raw data through IP, serial and VISA
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from syndesi import IP
|
|
57
|
+
|
|
58
|
+
my_adapter = IP('192.168.1.12', port=5025)
|
|
59
|
+
|
|
60
|
+
my_adapter.write(b'ping\n')
|
|
61
|
+
|
|
62
|
+
my_adapter.read() # -> b'pong'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from syndesi import SerialPort
|
|
67
|
+
|
|
68
|
+
arduino = SerialPort('/dev/ttyUSB0', baudrate=115200) # COMx on Windows
|
|
69
|
+
arduino.query(b'get_temperature\n') # -> 20.5
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Protocols
|
|
73
|
+
|
|
74
|
+
Protocols encapsulate and format data
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from syndesi import IP, Delimited
|
|
78
|
+
|
|
79
|
+
my_server = Delimited(IP('test.server.local', port=1234))
|
|
80
|
+
|
|
81
|
+
my_server.query('Hello world\n') # -> Hello world (\n is removed by Delimited)
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Drivers
|
|
86
|
+
|
|
87
|
+
A driver only requires an adapter, the protocol (if used) is instanciated internally
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from syndesi_drivers.instruments.mutlimeters.siglent.SDM3055 import SDM3055
|
|
91
|
+
from syndesi.adapters import IP
|
|
92
|
+
|
|
93
|
+
mm = SDM3055(IP("192.168.1.123"))
|
|
94
|
+
|
|
95
|
+
voltage = mm.measure_dc_voltage()
|
|
96
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
syndesi/__init__.py,sha256=FjPBCp-hgUfpzbl9vvNVybvP3Ml8toibnew9kZH2cQw,360
|
|
2
|
+
syndesi/__main__.py,sha256=S9G9k0SHGJJ9qMdF_txtYryiPdEPTI10bgQ-M-rVITs,75
|
|
3
|
+
syndesi/version.py,sha256=N7YMxKDsV6J_qHl8WtOeRrGxjN8_l6QQ1AFeNkv0fRE,68
|
|
4
|
+
syndesi/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
syndesi/adapters/adapter.py,sha256=7f9vjz6zXj7F-TFS9N0sF7voPhNDXzIUmrlnIxfDQHY,21057
|
|
6
|
+
syndesi/adapters/auto.py,sha256=SSNlo_EpjWJIqjpSyYPOYBKowVsd1TlaS8_-nng-Bp4,1592
|
|
7
|
+
syndesi/adapters/ip.py,sha256=IGzp7h_yqyKjrIE9oDppof6cO7JYu3-sxHYT0vdXCyU,3393
|
|
8
|
+
syndesi/adapters/ip_server.py,sha256=8o0cPRxAjnzTvwTCADy6MaNCDc5Uk0NDMXo0sZXoYCY,3773
|
|
9
|
+
syndesi/adapters/serialport.py,sha256=GeMVfwqgpTL0mR0LfI--4M80EwSg4zvjj03FIGh-x9g,2362
|
|
10
|
+
syndesi/adapters/stop_condition.py,sha256=QRxCAj6soDdALWUBbzT1pjNVHnPPEWygKT5BXitgrWU,2164
|
|
11
|
+
syndesi/adapters/timeout.py,sha256=0uLZzLjVXddvq792o9SJ6v3QDQXM649_pISyEZJZ40A,2443
|
|
12
|
+
syndesi/adapters/visa.py,sha256=dbszb9qFaPc3iiFh8KQV2bQK-QrwTcCUA36yPip4dkU,1406
|
|
13
|
+
syndesi/adapters/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
syndesi/adapters/backend/adapter_backend.py,sha256=E69K25fHZtCWy201UQ1mLYQcyl99KJdNAspheY9r800,14321
|
|
15
|
+
syndesi/adapters/backend/adapter_manager.py,sha256=8t_4D3WGtkvdF5RdnFiBJASD3_xny5eBxP8ZQI5BmgM,1938
|
|
16
|
+
syndesi/adapters/backend/adapter_session.py,sha256=Bjm8Pc40lJo4KCiFi4S-HYI3bCpy4BI9h7T0vPmXALs,13999
|
|
17
|
+
syndesi/adapters/backend/backend.py,sha256=yoEYW9wnkii8b6TkiQNz_iRLjB8kdhzZG3Ky1dcycxI,15862
|
|
18
|
+
syndesi/adapters/backend/backend_status.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
syndesi/adapters/backend/backend_tools.py,sha256=cJKAdDh3cVCDGc1bQmKSuaR3kKWXiov8GU32RYCnJcg,1893
|
|
20
|
+
syndesi/adapters/backend/descriptors.py,sha256=xDkdvVx2t0unxvzGIu8zH02q2QSKb5LBrX4MqtEUfxU,4300
|
|
21
|
+
syndesi/adapters/backend/ip_backend.py,sha256=wiETW21eLOi-JlvZf3yw_SdBxCddV7H5ElMmuHYsjfk,5122
|
|
22
|
+
syndesi/adapters/backend/serialport_backend.py,sha256=DRGgAZtKVIpcy6-AF_36Jj_IbxsyokVRo8K2CZNY17k,8479
|
|
23
|
+
syndesi/adapters/backend/stop_condition_backend.py,sha256=nLOoEUEBep5ii8l2fKzVmc-xjLi06Eh9Pxkx9JPup3o,6988
|
|
24
|
+
syndesi/adapters/backend/timed_queue.py,sha256=CwE3PklJqwwwbjyVvdEXIHXAIMwQSGPeBX3O_Kk4wH8,1163
|
|
25
|
+
syndesi/adapters/backend/timeout.py,sha256=thWUajfgvasPLptf0n5TvWLEjp3F2k0s3EAbAICpdvU,10480
|
|
26
|
+
syndesi/adapters/backend/visa_backend.py,sha256=mI6LWurPRye1esiPekoQT_MNpsmEknQ_AF6GueC8910,6352
|
|
27
|
+
syndesi/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
+
syndesi/cli/backend_console.py,sha256=9INqGf2EtnuCxFYWZbNCJ3exrx6k04uCh6jno8sUQTw,2971
|
|
29
|
+
syndesi/cli/backend_status.py,sha256=12-tIUTXq1fSQ2wphSHXGZ9u0F5UvXpc0FhGaEAjR6A,11653
|
|
30
|
+
syndesi/cli/backend_wrapper.py,sha256=dbBZs0NaWh2OiV3eh_D6_njfkPj_vYGJsY_SSY7QaCI,1900
|
|
31
|
+
syndesi/cli/console.py,sha256=yiJiZH2r5sZzRERVVfMrWI1yNvrkM16pkrqpT2s8LOg,8149
|
|
32
|
+
syndesi/cli/shell.py,sha256=hZDNuO6TrarWhaCbLeyGiUCOhM2RTW9PUhSryCpRYRc,7147
|
|
33
|
+
syndesi/cli/shell_tools.py,sha256=wqa0d5yELV1my_NhcLw00OXmYP8vKlrlkPqjLF2dCNs,3335
|
|
34
|
+
syndesi/cli/terminal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
syndesi/cli/terminal_apps.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
syndesi/cli/terminal_tools.py,sha256=VsqN-i7MM29Vo0gIUqFmgTyvMRBkcNuw6H3M4jJ4b4o,285
|
|
37
|
+
syndesi/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
syndesi/protocols/delimited.py,sha256=RIRjDs83cba8SrmlYPVqdiclYU1GLIjPMJXXTUh0c8M,6410
|
|
39
|
+
syndesi/protocols/modbus.py,sha256=BjVJKhLbHVpkwUwX2XvTkHchiwBdRU7nsUOYmBXOxfE,52980
|
|
40
|
+
syndesi/protocols/protocol.py,sha256=r4Hdc5UvR3oYsFW7NYiOYQBG-K0MPEJGHygK3jlp4pI,2263
|
|
41
|
+
syndesi/protocols/raw.py,sha256=CxepjGEYaUQBbZ2L1URdg9LeC7ImyIrD51gqwfQrn-A,2754
|
|
42
|
+
syndesi/protocols/scpi.py,sha256=DE1tWCVQ9rAAAfBv3MrxwSdG0TKJUjGLkOfVDU2zNLw,4798
|
|
43
|
+
syndesi/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
+
syndesi/scripts/syndesi.py,sha256=WYAmDh4WtXGiqyRcNebq8yt6sYnMHBbFMa5BPZC96mI,1371
|
|
45
|
+
syndesi/scripts/syndesi_backend.py,sha256=wrJt-_ciuKumOgbcNTcpNGQj7XN_toJ_Mp_IjdA5TZA,914
|
|
46
|
+
syndesi/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
syndesi/tools/backend_api.py,sha256=43T-4t1b2dMh-9Pz4mtYfW4IubRzh_qLFgqun4J8vqg,5325
|
|
48
|
+
syndesi/tools/backend_logger.py,sha256=aS15rWfQe4NWmAIvTp5Tf72MQoyWB4YeHA12lUKsjyE,2299
|
|
49
|
+
syndesi/tools/errors.py,sha256=qr-7pdymqHcjlnx3n_2M6-lZJnXQe35mJzv9WYf4Z-I,1202
|
|
50
|
+
syndesi/tools/exceptions.py,sha256=4zWJFMpNgVHMW91zFX-CafVhBFuP-P8h5tgvHlQMWw4,372
|
|
51
|
+
syndesi/tools/internal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
syndesi/tools/log.py,sha256=Z2uv56bXFNyboyfRBBIcTgJ9XjAr6Xur8He3cFkC2CI,4414
|
|
53
|
+
syndesi/tools/log_settings.py,sha256=CEshxSpIZeVu1BUhy-l1Fel1PY_hxb5ywsYQs9UEUVQ,382
|
|
54
|
+
syndesi/tools/types.py,sha256=fkPMLGTr30NFGNRPqZ3AeTAHMiiFmbFlSLDJEzQo6P4,1403
|
|
55
|
+
syndesi-0.4.2.dist-info/licenses/LICENSE,sha256=7oldAMqsditrYeX4dzMFHpFZ-6AkyGi3bha2zeaJB0A,34492
|
|
56
|
+
syndesi-0.4.2.dist-info/METADATA,sha256=37FRINk27uZcPQxaL0w8yriwFLsW8eDISao92gNnsX0,2827
|
|
57
|
+
syndesi-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
58
|
+
syndesi-0.4.2.dist-info/entry_points.txt,sha256=1JbZYMX6PrakEg-6b_M_f58QJ1mGFJKJd7puoPQPyKM,112
|
|
59
|
+
syndesi-0.4.2.dist-info/top_level.txt,sha256=HrY36JU6hFYp_6qv-GuVBBtHYYemn8qhCrqpvXBd1Lg,8
|
|
60
|
+
syndesi-0.4.2.dist-info/RECORD,,
|
syndesi-0.4.0.dist-info/METADATA
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: syndesi
|
|
3
|
-
Version: 0.4.0
|
|
4
|
-
Summary: Syndesi
|
|
5
|
-
Author-email: Sébastien Deriaz <sebastien.deriaz1@gmail.com>
|
|
6
|
-
License: GPL
|
|
7
|
-
Keywords: python,syndesi,interface,ethernet,serial,visa
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Intended Audience :: Education
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Operating System :: Unix
|
|
12
|
-
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
-
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
License-File: LICENSE
|
|
17
|
-
Requires-Dist: prompt_toolkit
|
|
18
|
-
Requires-Dist: pyserial
|
|
19
|
-
Requires-Dist: rich
|
|
20
|
-
Requires-Dist: platformdirs
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
|
|
23
|
-
# Syndesi Python Implementation
|
|
24
|
-
|
|
25
|
-
Syndesi description is available [here](https://github.com/syndesi-project/Syndesi/README.md)
|
|
26
|
-
|
|
27
|
-
## Installation
|
|
28
|
-
|
|
29
|
-
The syndesi Python package can be installed through pip
|
|
30
|
-
|
|
31
|
-
``pip install syndesi``
|
|
32
|
-
|
|
33
|
-
The package can also be installed locally by cloning this repository
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
git clone https://github.com/syndesi-project/Syndesi
|
|
37
|
-
cd Syndesi/Python
|
|
38
|
-
pip install .
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Usage
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
To instantiate a device, one must import the device and a suitable adapter
|
|
46
|
-
|
|
47
|
-
```python
|
|
48
|
-
# 1) Import the device
|
|
49
|
-
from syndesi.drivers.instruments.mutlimeters.siglent.SDM3055 import SDM3055
|
|
50
|
-
# 2) Import the adapter
|
|
51
|
-
from syndesi.adapters import IP
|
|
52
|
-
|
|
53
|
-
# 3) Instantiate the multimeter using its IP
|
|
54
|
-
mm = SDM3055(IP("192.168.1.123"))
|
|
55
|
-
|
|
56
|
-
## 4) Use
|
|
57
|
-
voltage = mm.measure_dc_voltage()
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Layers
|
|
61
|
-
|
|
62
|
-
The first layer is the "Device" base class
|
|
63
|
-
|
|
64
|
-
The second layer is made of "Primary drivers". First stage drivers implement mid-level communication protocols like Modbus, SDP, Raw, HTTP, SPCI, etc... Those drivers can be instanciated by the user if he wishes to use a device "as is" (i.e without an application driver)
|
|
65
|
-
|
|
66
|
-
Next are device drivers. They provide implementation for device-specific operations
|
|
67
|
-
|
|
68
|
-
Last are the application drivers. These are used to provide application-specific operations that mar or may not be tied to a particular device.
|
|
69
|
-
|
|
70
|
-
Note that both device drivers and application drivers can be omitted and can also be stacked as all first stage drivers, device drivers and application drivers stem from the same base Class
|
|
71
|
-
|
|
72
|
-
## Usecases
|
|
73
|
-
|
|
74
|
-
- Test gear (multimeters, oscilloscopes, power supply, etc...)
|
|
75
|
-
- set values (output voltage, settings, etc...)
|
|
76
|
-
- get values (measured voltage, trace, screenshot)
|
|
77
|
-
- continuously read data (UART multimeter for instance)
|
|
78
|
-
- UART devices (Arduinos, etc...)
|
|
79
|
-
- Send / receive raw data
|
|
80
|
-
- Custom drivers
|
|
81
|
-
- Syndesi devices
|
|
82
|
-
- Send / receive formatted data
|
|
83
|
-
- USB devices
|
|
84
|
-
- Send / receive data using the USB protocol
|
|
85
|
-
|
|
86
|
-
## Notes
|
|
87
|
-
|
|
88
|
-
06.09.2023 : bytearray is changed to bytes everywhere
|
|
89
|
-
|
|
90
|
-
23.10.2023 : continuation timeout isn't suitable for TCP, but it can work for UDP as a UDP server can send multiple response packets after a single packet from the client. This can be handled in different ways by firewalls. Thankfull that's none of our business so continuation timeout can be implemented
|
|
91
|
-
|
|
92
|
-
22.11.2023 : The timeout and stop conditions strategy is a bit complicated :
|
|
93
|
-
|
|
94
|
-
- What if we receive the message b'ACK\nNCK\n' using a termination stop condition but we receive b'ACK', then a timeout, then b'\nNCK\n' ?
|
|
95
|
-
- Should the first part be kept ? should an error be raised at the timeout because nothing was read ?
|
|
96
|
-
- Two kinds of timeouts ?
|
|
97
|
-
- One where "we read as much as possible during the available time"
|
|
98
|
-
- One where "we expect a response within X otherwise it's trash"
|
|
99
|
-
|
|
100
|
-
24.08.2025 : Shell and terminal
|
|
101
|
-
|
|
102
|
-
There will be two console tools : shell and terminal
|
|
103
|
-
|
|
104
|
-
- Shell : Run commands from drivers, protocols and adapters similar to ipython so "write_coil 0 1", "read_register 12", "read_temperature". I think using the POSIX utility argument syntax is a good idea. Another solution would be to use the Python syntax, so write_register(0, 1)
|
|
105
|
-
- Terminal : Send raw data to a driver, a protocol, an adapter, etc... Multiple formats are possible such as text, hex or bytes
|
|
106
|
-
|
|
107
|
-
The use could implement both Shell and Terminal in their classes and then call them from syndesi. I'm thinking of 4 ways to get shells or terminals
|
|
108
|
-
|
|
109
|
-
- Built-ins "syndesi shell ..." or "syndesi terminal ..."
|
|
110
|
-
- relative path "syndesi shell xxx.py" or "syndesi terminal xxx.py"
|
|
111
|
-
- plugin, modules behave like built-ins using the plugin/hook system (?) not sure about this one
|
|
112
|
-
- dotted syntax, the user can use the dotted syntax to call their modules "syndesi terminal mypkg.myterm:MyTerminal"
|
|
113
|
-
|
|
114
|
-
11.09.2025 : Read and buffers
|
|
115
|
-
|
|
116
|
-
When a user calls a read, there's two behaviours :
|
|
117
|
-
|
|
118
|
-
1) Only data that is received after the read() call is be returned (or slightly before with a delay)
|
|
119
|
-
2) The first data available (can be way before the read() call) is returned
|
|
120
|
-
|
|
121
|
-
Choice has been made to go with the second solution. This is the expected behaviour and it's easier to simulate the first option by using this architecture than the other way around. To obtain a "read only what's after" we can use the flush method or query with flush enabled
|
|
122
|
-
|
|
123
|
-
The consequence is that the adapter has to keep a buffer of data
|
syndesi-0.4.0.dist-info/RECORD
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
syndesi/__init__.py,sha256=FjPBCp-hgUfpzbl9vvNVybvP3Ml8toibnew9kZH2cQw,360
|
|
2
|
-
syndesi/__main__.py,sha256=S9G9k0SHGJJ9qMdF_txtYryiPdEPTI10bgQ-M-rVITs,75
|
|
3
|
-
syndesi/version.py,sha256=nZZls72GhOFlxA23gIGU0AOvczmnB83gYWJ7YNU_ZhA,68
|
|
4
|
-
syndesi/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
syndesi/adapters/adapter.py,sha256=ERheb_kmrufF8k2Uo7hI1Ot6qPjiGucEMZEdWNsepxY,24481
|
|
6
|
-
syndesi/adapters/auto.py,sha256=L9dgiNkGRnBG4_ErwfX13MEp4JF2agXz7eg9O2-aPPA,1586
|
|
7
|
-
syndesi/adapters/ip.py,sha256=oerOwEcaM5luS-Z3e40YPUJpCbUTtl3a1CuVfg1Vy3M,3518
|
|
8
|
-
syndesi/adapters/ip_server.py,sha256=8o0cPRxAjnzTvwTCADy6MaNCDc5Uk0NDMXo0sZXoYCY,3773
|
|
9
|
-
syndesi/adapters/serialport.py,sha256=GeMVfwqgpTL0mR0LfI--4M80EwSg4zvjj03FIGh-x9g,2362
|
|
10
|
-
syndesi/adapters/stop_condition.py,sha256=1mMPpwv1oYSaPV83Avgn0LVuijdhlB-eSqlC38rgJ9o,4495
|
|
11
|
-
syndesi/adapters/timeout.py,sha256=bKHBr5u_KzTeD3aaJ44TcitMeAwhxCHkSJZT0NXZZtU,3167
|
|
12
|
-
syndesi/adapters/visa.py,sha256=G50ih0klh984nNLLch9SxgoC1oP72nMjTjZlPwk-niw,1389
|
|
13
|
-
syndesi/adapters/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
syndesi/adapters/backend/adapter_backend.py,sha256=ubqdZ1DVMnPGIHta3h3LsqeNjgktVg1Vlrr7Nowj2PQ,13948
|
|
15
|
-
syndesi/adapters/backend/adapter_manager.py,sha256=8t_4D3WGtkvdF5RdnFiBJASD3_xny5eBxP8ZQI5BmgM,1938
|
|
16
|
-
syndesi/adapters/backend/adapter_session.py,sha256=yh0ywQaXsfuHgj71V1mth5d0ptGb5Cux0gyUhMgv7Mk,14147
|
|
17
|
-
syndesi/adapters/backend/backend.py,sha256=yoEYW9wnkii8b6TkiQNz_iRLjB8kdhzZG3Ky1dcycxI,15862
|
|
18
|
-
syndesi/adapters/backend/backend_tools.py,sha256=fkl4_lgW9QKb1fTiC9LvkI88g4SD9K9rxS3qMVc_0FA,1893
|
|
19
|
-
syndesi/adapters/backend/descriptors.py,sha256=kJVVfnbH1CzJ7T2lhMXRADCABfXkPVJpM-541Iw-98k,4273
|
|
20
|
-
syndesi/adapters/backend/ip_backend.py,sha256=XCAkaLXtvGUl8NnG6gco2pEL7a8NyCfbuq8IK7csDu4,5061
|
|
21
|
-
syndesi/adapters/backend/serialport_backend.py,sha256=N4WG-ODwzDCqLV8b74yIkI3fgT3oST5yL7Eit9S9GEI,8451
|
|
22
|
-
syndesi/adapters/backend/stop_condition_backend.py,sha256=102ObiC30khJu85Y4Hn3xodN7HExkJrT9PzS2YywYRM,6995
|
|
23
|
-
syndesi/adapters/backend/timed_queue.py,sha256=CwE3PklJqwwwbjyVvdEXIHXAIMwQSGPeBX3O_Kk4wH8,1163
|
|
24
|
-
syndesi/adapters/backend/timeout.py,sha256=thWUajfgvasPLptf0n5TvWLEjp3F2k0s3EAbAICpdvU,10480
|
|
25
|
-
syndesi/adapters/backend/visa_backend.py,sha256=apn6GjCpfDKcACDKpPDP1r9zpUj0PHWn_2lhvwy1C6w,6455
|
|
26
|
-
syndesi/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
syndesi/cli/backend_console.py,sha256=9INqGf2EtnuCxFYWZbNCJ3exrx6k04uCh6jno8sUQTw,2971
|
|
28
|
-
syndesi/cli/backend_status.py,sha256=uD-IS0RcPsWGaKCue0sR-_aTy3cytipSk4C0Rl7w4AY,11908
|
|
29
|
-
syndesi/cli/backend_wrapper.py,sha256=dbBZs0NaWh2OiV3eh_D6_njfkPj_vYGJsY_SSY7QaCI,1900
|
|
30
|
-
syndesi/cli/console.py,sha256=eNxp7XxE30pVJUNRWwbmtSE6XIrFzWvdWuwieNiO_d0,10417
|
|
31
|
-
syndesi/cli/shell.py,sha256=iM05uHyslASz_fBROwiapJPHgWde5EPQTPlgJ34ATfs,7786
|
|
32
|
-
syndesi/cli/shell_tools.py,sha256=YGPeB1Le4exvtrcLOaKnpDrAlSosztvW4AkChvBLm4E,3455
|
|
33
|
-
syndesi/cli/terminal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
syndesi/cli/terminal_apps.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
syndesi/cli/terminal_tools.py,sha256=VsqN-i7MM29Vo0gIUqFmgTyvMRBkcNuw6H3M4jJ4b4o,285
|
|
36
|
-
syndesi/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
-
syndesi/protocols/delimited.py,sha256=tPaSpaYoHj0hSnI55kN1TS60WXnH90rkE517Qdt3d94,7210
|
|
38
|
-
syndesi/protocols/modbus.py,sha256=11RwTaj7u-DQB58OhgMnzG8ROMTya98dHoPfdEJPx7A,52816
|
|
39
|
-
syndesi/protocols/protocol.py,sha256=r4Hdc5UvR3oYsFW7NYiOYQBG-K0MPEJGHygK3jlp4pI,2263
|
|
40
|
-
syndesi/protocols/raw.py,sha256=eCuHlBYO-SSELFugwWuaNyFkbDL2TH9TA9xblTcLuxk,2522
|
|
41
|
-
syndesi/protocols/scpi.py,sha256=kUEvCf9h-1GMT_EwG4Q5rKe93i8ruUvXyrsND0sxyB8,4699
|
|
42
|
-
syndesi/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
|
-
syndesi/scripts/syndesi.py,sha256=sCY14-_YUG27PjteGDPWboS2nO092qpfGpdfU0Rulj4,1386
|
|
44
|
-
syndesi/scripts/syndesi_backend.py,sha256=wrJt-_ciuKumOgbcNTcpNGQj7XN_toJ_Mp_IjdA5TZA,914
|
|
45
|
-
syndesi/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
-
syndesi/tools/backend_api.py,sha256=mBm8U-KmQ0h5kLfoc8stspS6Dki74tikOHaWyJa-yes,6292
|
|
47
|
-
syndesi/tools/backend_logger.py,sha256=dpST6jKQz7bq58C-JLLpawZZPie1EcW9vKvsS8L1CFA,2300
|
|
48
|
-
syndesi/tools/errors.py,sha256=ZUS6wRnZlP3Lzw9uA8goU0a_h4DIs-qClm_dkTUCY9s,1226
|
|
49
|
-
syndesi/tools/exceptions.py,sha256=4zWJFMpNgVHMW91zFX-CafVhBFuP-P8h5tgvHlQMWw4,372
|
|
50
|
-
syndesi/tools/internal.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
-
syndesi/tools/log.py,sha256=k_L3kMm4r_Vxfw1B7znGXRxsMc_Fo37t5Ky6yZxmE_o,7686
|
|
52
|
-
syndesi/tools/log_settings.py,sha256=CEshxSpIZeVu1BUhy-l1Fel1PY_hxb5ywsYQs9UEUVQ,382
|
|
53
|
-
syndesi/tools/types.py,sha256=7k3rbKZCxSDNA6T1p3sS6TvEclV1HCDeWCW8ymBN0Vo,2498
|
|
54
|
-
syndesi-0.4.0.dist-info/licenses/LICENSE,sha256=7oldAMqsditrYeX4dzMFHpFZ-6AkyGi3bha2zeaJB0A,34492
|
|
55
|
-
syndesi-0.4.0.dist-info/METADATA,sha256=nJh98oaqKuYD03j833dUDYBNGQxzZItn9zCmkIxSu4w,5101
|
|
56
|
-
syndesi-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
-
syndesi-0.4.0.dist-info/entry_points.txt,sha256=1JbZYMX6PrakEg-6b_M_f58QJ1mGFJKJd7puoPQPyKM,112
|
|
58
|
-
syndesi-0.4.0.dist-info/top_level.txt,sha256=HrY36JU6hFYp_6qv-GuVBBtHYYemn8qhCrqpvXBd1Lg,8
|
|
59
|
-
syndesi-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|