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/adapters/timeout.py
CHANGED
|
@@ -8,12 +8,9 @@ from typing import Any, Protocol
|
|
|
8
8
|
|
|
9
9
|
from ..tools.types import NumberLike, is_number
|
|
10
10
|
|
|
11
|
-
# from .backend.timeout import TimeoutAction, JsonKey
|
|
12
|
-
|
|
13
|
-
|
|
14
11
|
class TimeoutAction(Enum):
|
|
15
12
|
ERROR = "error"
|
|
16
|
-
|
|
13
|
+
RETURN_EMPTY = "return_empty"
|
|
17
14
|
|
|
18
15
|
|
|
19
16
|
class IsInitialized(Protocol):
|
|
@@ -78,10 +75,9 @@ class Timeout:
|
|
|
78
75
|
return None
|
|
79
76
|
else:
|
|
80
77
|
return self._response
|
|
81
|
-
|
|
82
|
-
def is_initialized(self) -> bool:
|
|
83
|
-
return not self._response is Ellipsis
|
|
84
78
|
|
|
79
|
+
def is_initialized(self) -> bool:
|
|
80
|
+
return self._response is not Ellipsis
|
|
85
81
|
|
|
86
82
|
|
|
87
83
|
def any_to_timeout(value: Any) -> Timeout:
|
|
@@ -93,26 +89,3 @@ def any_to_timeout(value: Any) -> Timeout:
|
|
|
93
89
|
return value
|
|
94
90
|
else:
|
|
95
91
|
raise ValueError(f"Could not convert {value} to Timeout")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# class TimeoutException(Exception):
|
|
99
|
-
# def __init__(self, value: NumberLike, limit: NumberLike) -> None:
|
|
100
|
-
# super().__init__()
|
|
101
|
-
# self._value = value
|
|
102
|
-
# self._limit = limit
|
|
103
|
-
|
|
104
|
-
# def __str__(self) -> str:
|
|
105
|
-
# try:
|
|
106
|
-
# value_string = f"{self._value * 1e3:.3f}ms"
|
|
107
|
-
# except (ValueError, TypeError):
|
|
108
|
-
# value_string = "not received"
|
|
109
|
-
|
|
110
|
-
# try:
|
|
111
|
-
# limit_string = f"{self._limit * 1e3:.3f}ms"
|
|
112
|
-
# except (ValueError, TypeError):
|
|
113
|
-
# limit_string = "not received"
|
|
114
|
-
|
|
115
|
-
# return f"{value_string} / {limit_string}"
|
|
116
|
-
|
|
117
|
-
# def __repr__(self) -> str:
|
|
118
|
-
# return self.__str__()
|
syndesi/adapters/visa.py
CHANGED
|
@@ -20,7 +20,7 @@ class Visa(Adapter):
|
|
|
20
20
|
self,
|
|
21
21
|
descriptor: str,
|
|
22
22
|
alias: str = "",
|
|
23
|
-
|
|
23
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
24
24
|
timeout: None | float | Timeout | EllipsisType = ...,
|
|
25
25
|
encoding: str = "utf-8",
|
|
26
26
|
event_callback: Callable[[AdapterSignal], None] | None = None,
|
|
@@ -30,7 +30,7 @@ class Visa(Adapter):
|
|
|
30
30
|
super().__init__(
|
|
31
31
|
VisaDescriptor.from_string(descriptor),
|
|
32
32
|
alias=alias,
|
|
33
|
-
stop_conditions=
|
|
33
|
+
stop_conditions=stop_conditions,
|
|
34
34
|
timeout=timeout,
|
|
35
35
|
encoding=encoding,
|
|
36
36
|
event_callback=event_callback,
|
syndesi/cli/backend_status.py
CHANGED
|
@@ -95,8 +95,6 @@ class BackendStatus:
|
|
|
95
95
|
# Buffer for last N_CONSOLE_LINES log messages
|
|
96
96
|
self.console_lines: list[str] = []
|
|
97
97
|
self.console_lock = threading.Lock() # Lock for thread safety
|
|
98
|
-
# self._backend_logger = BackendLogger() # use_queue=True)
|
|
99
|
-
# self._backend_logger.start()
|
|
100
98
|
log_manager.enable_backend_logging()
|
|
101
99
|
self._start_time = time.time()
|
|
102
100
|
self.conn: NamedConnection | None = None
|
|
@@ -155,7 +153,9 @@ class BackendStatus:
|
|
|
155
153
|
adapter_table = Table(
|
|
156
154
|
"", box=None, caption_justify="right"
|
|
157
155
|
)
|
|
158
|
-
snapshot: dict[str, tuple[bool, list[str]]] = event[
|
|
156
|
+
snapshot: dict[str, tuple[bool, list[str]]] = event[
|
|
157
|
+
1
|
|
158
|
+
]
|
|
159
159
|
unique_clients: set[str] = set()
|
|
160
160
|
for _, (_, adapter_clients) in snapshot.items():
|
|
161
161
|
unique_clients |= set(adapter_clients)
|
|
@@ -191,7 +191,9 @@ class BackendStatus:
|
|
|
191
191
|
pad_edge=False,
|
|
192
192
|
)
|
|
193
193
|
# Update monitoring connections
|
|
194
|
-
monitoring_response: list[tuple[str, str]] = event[
|
|
194
|
+
monitoring_response: list[tuple[str, str]] = event[
|
|
195
|
+
1
|
|
196
|
+
]
|
|
195
197
|
|
|
196
198
|
for connection, desc in monitoring_response:
|
|
197
199
|
if (
|
|
@@ -206,10 +208,6 @@ class BackendStatus:
|
|
|
206
208
|
monitoring_connections.add_row(
|
|
207
209
|
f"[{style[0]}]{connection}[/] [{style[1]}]({desc})[/]"
|
|
208
210
|
)
|
|
209
|
-
# if connection == status_conn:
|
|
210
|
-
# logger_connections.add_row(f"[grey50]{connection}[/]")
|
|
211
|
-
# else:
|
|
212
|
-
# logger_connections.add_row(c_string)
|
|
213
211
|
for _ in range(
|
|
214
212
|
self.CONNECTIONS_MIN_HEIGHT
|
|
215
213
|
- len(monitoring_response)
|
|
@@ -273,4 +271,4 @@ class BackendStatus:
|
|
|
273
271
|
self.console_lines.append(formated_text)
|
|
274
272
|
if len(self.console_lines) > self._n_console_lines:
|
|
275
273
|
self.console_lines = self.console_lines[-self._n_console_lines :]
|
|
276
|
-
self._new_console_line_w.send(b
|
|
274
|
+
self._new_console_line_w.send(b"\x00")
|
syndesi/cli/console.py
CHANGED
|
@@ -222,60 +222,7 @@ class Shell:
|
|
|
222
222
|
FormattedText([(f"class:{style.value}", text)]), style=self._toolkit_styles
|
|
223
223
|
)
|
|
224
224
|
|
|
225
|
-
# def ask(self, question: str):
|
|
226
|
-
# loop = self.session.app.loop
|
|
227
|
-
# fut = asyncio.run_coroutine_threadsafe(self._ask_on_app_loop(question), loop)
|
|
228
|
-
# return fut.result()
|
|
229
|
-
|
|
230
|
-
# async def _ask_on_app_loop(self, question: str):
|
|
231
|
-
# def _blocking_prompt():
|
|
232
|
-
# temp_session = prompt_toolkit.PromptSession()
|
|
233
|
-
# return temp_session.prompt(question)
|
|
234
|
-
# # Or just: return input(question) if styling isn't needed
|
|
235
|
-
|
|
236
|
-
# return await prompt_toolkit.application.run_in_terminal(_blocking_prompt)
|
|
237
|
-
|
|
238
|
-
# def ask(self, question: str):
|
|
239
|
-
# loop = self.session.app.loop
|
|
240
|
-
# fut = asyncio.run_coroutine_threadsafe(self._ask_dialog(question), loop)
|
|
241
|
-
# return fut.result()
|
|
242
|
-
|
|
243
|
-
# async def _ask_dialog(self, question: str):
|
|
244
|
-
# dlg = yes_no_dialog(title="Adapter Disconnected", text=question)
|
|
245
|
-
# return await dlg.run_async()
|
|
246
|
-
|
|
247
225
|
def ask(self, question: str, callback: Callable[[str], None]) -> None:
|
|
248
226
|
self.ask_event.set()
|
|
249
227
|
self.ask_callback = callback
|
|
250
|
-
self.reprompt(question)
|
|
251
|
-
|
|
252
|
-
# loop = self.session.app.loop
|
|
253
|
-
# fut = asyncio.run_coroutine_threadsafe(self._ask_inline(question), loop)
|
|
254
|
-
# return fut.result()
|
|
255
|
-
|
|
256
|
-
# async def _ask_inline(self, question: str) -> bool:
|
|
257
|
-
# from prompt_toolkit.patch_stdout import patch_stdout
|
|
258
|
-
# from prompt_toolkit.shortcuts import prompt
|
|
259
|
-
|
|
260
|
-
# # patch_stdout ensures print() doesn't mess up your REPL display
|
|
261
|
-
# with patch_stdout():
|
|
262
|
-
# ans = await prompt(f"{question} (y/n) ").strip().lower()
|
|
263
|
-
# return ans.startswith("y")
|
|
264
|
-
|
|
265
|
-
# def ask(self, question: str):
|
|
266
|
-
# fut = asyncio.run_coroutine_threadsafe(
|
|
267
|
-
# self._ask_on_app_loop(question), self.session.app.loop
|
|
268
|
-
# )
|
|
269
|
-
# answer = fut.result() # blocks THIS thread until user answers
|
|
270
|
-
# return answer
|
|
271
|
-
|
|
272
|
-
# # on your shell object (runs on the app loop):
|
|
273
|
-
# async def _ask_on_app_loop(self, question):
|
|
274
|
-
# def _blocking_prompt():
|
|
275
|
-
# # Use your existing shell ask/prompt; it runs while the UI is suspended.
|
|
276
|
-
# # If you have a PromptSession: return self.shell.session.prompt(...)
|
|
277
|
-
# return self.session.prompt(question)
|
|
278
|
-
|
|
279
|
-
# self.session.app.run
|
|
280
|
-
# # Suspends rendering & CPR handling safely, runs in a thread pool.
|
|
281
|
-
# return await prompt_toolkit.application.run_in_terminal(_blocking_prompt)
|
|
228
|
+
self.reprompt(question)
|
syndesi/cli/shell.py
CHANGED
|
@@ -173,7 +173,7 @@ class AdapterShell:
|
|
|
173
173
|
backend_port=args.backend_port,
|
|
174
174
|
)
|
|
175
175
|
|
|
176
|
-
self.adapter.set_default_timeout(Timeout(action="
|
|
176
|
+
self.adapter.set_default_timeout(Timeout(action="return_empty"))
|
|
177
177
|
|
|
178
178
|
# Add the protocol
|
|
179
179
|
_format = Format(args.format)
|
|
@@ -205,13 +205,6 @@ class AdapterShell:
|
|
|
205
205
|
def run(self) -> None:
|
|
206
206
|
# try:
|
|
207
207
|
self.adapter.open()
|
|
208
|
-
# except Exception: # TODO : Change this to a suitable exception
|
|
209
|
-
# self.shell.print(
|
|
210
|
-
# f"Failed to open adapter {self.adapter.descriptor}",
|
|
211
|
-
# style=Shell.Style.ERROR,
|
|
212
|
-
# )
|
|
213
|
-
# self.adapter.close() # TODO : Maybe force here ?
|
|
214
|
-
# else:
|
|
215
208
|
self.shell.print(
|
|
216
209
|
f"Opened adapter {self.adapter.descriptor}", style=Shell.Style.NOTE
|
|
217
210
|
)
|
|
@@ -227,12 +220,6 @@ class AdapterShell:
|
|
|
227
220
|
if answer.lower() == "y":
|
|
228
221
|
# try:
|
|
229
222
|
self._protocol.open()
|
|
230
|
-
# except Exception: # TODO : Change this
|
|
231
|
-
# self.shell.print(
|
|
232
|
-
# "Failed to open adapter", style=Shell.Style.WARNING
|
|
233
|
-
# )
|
|
234
|
-
# else:
|
|
235
|
-
# self.shell.print("Adapter opened", style=Shell.Style.NOTE)
|
|
236
223
|
else:
|
|
237
224
|
# Set the stop flag, exit will be effective on reprompt
|
|
238
225
|
self.shell.stop()
|
syndesi/cli/shell_tools.py
CHANGED
syndesi/protocols/delimited.py
CHANGED
|
@@ -107,13 +107,7 @@ class Delimited(Protocol):
|
|
|
107
107
|
command = self._format_command(command)
|
|
108
108
|
self._adapter.write(self._to_bytes(command))
|
|
109
109
|
|
|
110
|
-
def query(
|
|
111
|
-
self,
|
|
112
|
-
data: str,
|
|
113
|
-
timeout: Timeout | None | EllipsisType = ...,
|
|
114
|
-
decode: bool = True,
|
|
115
|
-
full_output: bool = False,
|
|
116
|
-
) -> str | tuple[str, AdapterSignal]:
|
|
110
|
+
def query(self, data: str, timeout: Timeout | None | EllipsisType = ...) -> str:
|
|
117
111
|
"""
|
|
118
112
|
Writes then reads from the device and return the result
|
|
119
113
|
|
|
@@ -130,13 +124,13 @@ class Delimited(Protocol):
|
|
|
130
124
|
"""
|
|
131
125
|
self._adapter.flushRead()
|
|
132
126
|
self.write(data)
|
|
133
|
-
return self.read(timeout=timeout
|
|
127
|
+
return self.read(timeout=timeout)
|
|
134
128
|
|
|
135
129
|
def read_raw(
|
|
136
130
|
self,
|
|
137
131
|
timeout: Timeout | None | EllipsisType = ...,
|
|
138
|
-
|
|
139
|
-
) ->
|
|
132
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
133
|
+
) -> bytes:
|
|
140
134
|
"""
|
|
141
135
|
Reads command and formats it as a str
|
|
142
136
|
|
|
@@ -151,30 +145,28 @@ class Delimited(Protocol):
|
|
|
151
145
|
"""
|
|
152
146
|
|
|
153
147
|
# Send up to the termination
|
|
154
|
-
|
|
155
|
-
timeout=timeout,
|
|
148
|
+
signal = self._adapter.read_detailed(
|
|
149
|
+
timeout=timeout, stop_conditions=stop_conditions
|
|
156
150
|
)
|
|
157
|
-
|
|
158
|
-
return raw_data, signal
|
|
151
|
+
return signal.data()
|
|
159
152
|
|
|
160
153
|
def read_detailed(
|
|
161
154
|
self,
|
|
162
155
|
timeout: Timeout | None | EllipsisType = ...,
|
|
163
|
-
|
|
164
|
-
) ->
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return
|
|
156
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
157
|
+
) -> AdapterReadPayload:
|
|
158
|
+
signal = self._adapter.read_detailed(
|
|
159
|
+
timeout=timeout, stop_conditions=stop_conditions
|
|
160
|
+
)
|
|
161
|
+
return signal
|
|
169
162
|
|
|
170
163
|
def read(
|
|
171
164
|
self,
|
|
172
165
|
timeout: Timeout | None | EllipsisType = ...,
|
|
173
|
-
|
|
174
|
-
decode: bool = True,
|
|
175
|
-
full_output: bool = False,
|
|
166
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
176
167
|
) -> str:
|
|
177
|
-
|
|
168
|
+
signal = self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
|
|
169
|
+
return self._decode(signal.data())
|
|
178
170
|
|
|
179
171
|
def _decode(self, data: bytes) -> str:
|
|
180
172
|
try:
|
|
@@ -188,16 +180,4 @@ class Delimited(Protocol):
|
|
|
188
180
|
# Add the termination back in since it was removed by the adapter
|
|
189
181
|
data_string += self._receive_termination
|
|
190
182
|
|
|
191
|
-
return data_string
|
|
192
|
-
|
|
193
|
-
# @overload
|
|
194
|
-
# def _append_missing_termination(self, data : str) -> str: ...
|
|
195
|
-
# @overload
|
|
196
|
-
# def _append_missing_termination(self, data : bytes) -> bytes: ...
|
|
197
|
-
# def _append_missing_termination(self, data : Union[str, bytes]) -> Union[str, bytes]:
|
|
198
|
-
# if isinstance(data, str):
|
|
199
|
-
# return data + self._receive_termination
|
|
200
|
-
# elif isinstance(data, bytes): # type bytes
|
|
201
|
-
# return data + self._receive_termination.encode(self._encoding)
|
|
202
|
-
# else:
|
|
203
|
-
# raise ValueError(f"Couldn't append termination do {data}")
|
|
183
|
+
return data_string
|
syndesi/protocols/modbus.py
CHANGED
|
@@ -14,7 +14,7 @@ from unittest.mock import DEFAULT
|
|
|
14
14
|
from ..adapters.adapter import Adapter
|
|
15
15
|
from ..adapters.ip import IP
|
|
16
16
|
from ..adapters.serialport import SerialPort
|
|
17
|
-
from ..adapters.stop_condition import Length
|
|
17
|
+
from ..adapters.stop_condition import Continuation, Length
|
|
18
18
|
from ..adapters.timeout import Timeout
|
|
19
19
|
from .protocol import Protocol
|
|
20
20
|
|
|
@@ -328,10 +328,12 @@ class Modbus(Protocol):
|
|
|
328
328
|
def _error_code(self, response: bytes) -> int:
|
|
329
329
|
return response[1]
|
|
330
330
|
|
|
331
|
-
def _parse_pdu(self, _pdu: bytes) -> bytes:
|
|
331
|
+
def _parse_pdu(self, _pdu: bytes | None) -> bytes:
|
|
332
332
|
"""
|
|
333
333
|
Return data from PDU
|
|
334
334
|
"""
|
|
335
|
+
if _pdu is None:
|
|
336
|
+
raise RuntimeError("Failed to read modbus data")
|
|
335
337
|
if self._modbus_type == ModbusType.TCP:
|
|
336
338
|
# Return raw data
|
|
337
339
|
# data = _pdu
|
|
@@ -391,12 +393,13 @@ class Modbus(Protocol):
|
|
|
391
393
|
)
|
|
392
394
|
|
|
393
395
|
n_coil_bytes = ceil(number_of_coils / 8)
|
|
394
|
-
pdu: bytes = self._adapter.query(
|
|
396
|
+
pdu: bytes | None = self._adapter.query(
|
|
395
397
|
self._make_pdu(query),
|
|
396
398
|
# timeout=Timeout(continuation=1),
|
|
397
|
-
|
|
398
|
-
self._length(n_coil_bytes + 2)
|
|
399
|
-
|
|
399
|
+
stop_conditions=[
|
|
400
|
+
Length(self._length(n_coil_bytes + 2)),
|
|
401
|
+
Continuation(time=1),
|
|
402
|
+
], # TODO : convert to multiple stop conditions here
|
|
400
403
|
)
|
|
401
404
|
response = self._parse_pdu(pdu)
|
|
402
405
|
self._raise_if_error(response, exception_codes=EXCEPTIONS)
|
|
@@ -465,7 +468,7 @@ class Modbus(Protocol):
|
|
|
465
468
|
response = self._parse_pdu(
|
|
466
469
|
self._adapter.query(
|
|
467
470
|
self._make_pdu(query),
|
|
468
|
-
|
|
471
|
+
stop_conditions=Length(self._length(byte_count + 2)),
|
|
469
472
|
)
|
|
470
473
|
)
|
|
471
474
|
self._raise_if_error(response, exception_codes=EXCEPTIONS)
|
|
@@ -515,7 +518,7 @@ class Modbus(Protocol):
|
|
|
515
518
|
response = self._parse_pdu(
|
|
516
519
|
self._adapter.query(
|
|
517
520
|
self._make_pdu(query),
|
|
518
|
-
|
|
521
|
+
stop_conditions=Length(self._length(2 + number_of_registers * 2)),
|
|
519
522
|
)
|
|
520
523
|
)
|
|
521
524
|
self._raise_if_error(response, exception_codes=EXCEPTIONS)
|
|
@@ -769,7 +772,7 @@ class Modbus(Protocol):
|
|
|
769
772
|
)
|
|
770
773
|
response = self._parse_pdu(
|
|
771
774
|
self._adapter.query(
|
|
772
|
-
self._make_pdu(query),
|
|
775
|
+
self._make_pdu(query), stop_conditions=Length(self._length(len(query)))
|
|
773
776
|
)
|
|
774
777
|
)
|
|
775
778
|
self._raise_if_error(response, EXCEPTIONS)
|
|
@@ -805,7 +808,7 @@ class Modbus(Protocol):
|
|
|
805
808
|
)
|
|
806
809
|
response = self._parse_pdu(
|
|
807
810
|
self._adapter.query(
|
|
808
|
-
self._make_pdu(query),
|
|
811
|
+
self._make_pdu(query), stop_conditions=Length(self._length(len(query)))
|
|
809
812
|
)
|
|
810
813
|
)
|
|
811
814
|
self._raise_if_error(response, EXCEPTIONS)
|
|
@@ -1198,7 +1201,7 @@ class Modbus(Protocol):
|
|
|
1198
1201
|
)
|
|
1199
1202
|
response = self._parse_pdu(
|
|
1200
1203
|
self._adapter.query(
|
|
1201
|
-
self._make_pdu(query),
|
|
1204
|
+
self._make_pdu(query), stop_conditions=Length(self._length(5))
|
|
1202
1205
|
)
|
|
1203
1206
|
)
|
|
1204
1207
|
self._raise_if_error(response, EXCEPTIONS)
|
|
@@ -1250,7 +1253,7 @@ class Modbus(Protocol):
|
|
|
1250
1253
|
)
|
|
1251
1254
|
response = self._parse_pdu(
|
|
1252
1255
|
self._adapter.query(
|
|
1253
|
-
self._make_pdu(query),
|
|
1256
|
+
self._make_pdu(query), stop_conditions=Length(self._length(5))
|
|
1254
1257
|
)
|
|
1255
1258
|
)
|
|
1256
1259
|
self._raise_if_error(response, EXCEPTIONS)
|
|
@@ -1451,7 +1454,7 @@ class Modbus(Protocol):
|
|
|
1451
1454
|
)
|
|
1452
1455
|
response = self._parse_pdu(
|
|
1453
1456
|
self._adapter.query(
|
|
1454
|
-
self._make_pdu(query),
|
|
1457
|
+
self._make_pdu(query), stop_conditions=Length(self._length(len(query)))
|
|
1455
1458
|
)
|
|
1456
1459
|
)
|
|
1457
1460
|
self._raise_if_error(response, EXCEPTIONS)
|
|
@@ -1521,7 +1524,7 @@ class Modbus(Protocol):
|
|
|
1521
1524
|
response = self._parse_pdu(
|
|
1522
1525
|
self._adapter.query(
|
|
1523
1526
|
self._make_pdu(query),
|
|
1524
|
-
|
|
1527
|
+
stop_conditions=Length(self._length(2 + number_of_read_registers * 2)),
|
|
1525
1528
|
)
|
|
1526
1529
|
)
|
|
1527
1530
|
self._raise_if_error(response, EXCEPTIONS)
|
syndesi/protocols/raw.py
CHANGED
|
@@ -49,33 +49,37 @@ class Raw(Protocol):
|
|
|
49
49
|
self,
|
|
50
50
|
data: bytes,
|
|
51
51
|
timeout: Timeout | None | EllipsisType = ...,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
) -> bytes | tuple[bytes, AdapterSignal]:
|
|
52
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
53
|
+
) -> bytes:
|
|
55
54
|
self._adapter.flushRead()
|
|
56
55
|
self.write(data)
|
|
57
|
-
return self.read(
|
|
58
|
-
timeout=timeout,
|
|
59
|
-
stop_condition=stop_condition,
|
|
60
|
-
full_output=full_output,
|
|
61
|
-
)
|
|
56
|
+
return self.read(timeout=timeout, stop_conditions=stop_conditions)
|
|
62
57
|
|
|
63
|
-
def
|
|
58
|
+
def query_detailed(
|
|
64
59
|
self,
|
|
60
|
+
data: bytes,
|
|
65
61
|
timeout: Timeout | None | EllipsisType = ...,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
63
|
+
) -> AdapterReadPayload:
|
|
64
|
+
self._adapter.flushRead()
|
|
65
|
+
self.write(data)
|
|
66
|
+
return self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
def read(
|
|
69
|
+
self,
|
|
70
|
+
timeout: Timeout | None | EllipsisType = ...,
|
|
71
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
72
|
+
) -> bytes:
|
|
73
|
+
signal = self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
|
|
74
|
+
return signal.data()
|
|
71
75
|
|
|
72
76
|
def read_detailed(
|
|
73
77
|
self,
|
|
74
78
|
timeout: Timeout | None | EllipsisType = ...,
|
|
75
|
-
|
|
76
|
-
) ->
|
|
79
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
80
|
+
) -> AdapterReadPayload:
|
|
77
81
|
return self._adapter.read_detailed(
|
|
78
|
-
timeout=timeout,
|
|
82
|
+
timeout=timeout, stop_conditions=stop_conditions
|
|
79
83
|
)
|
|
80
84
|
|
|
81
85
|
def _on_data_ready_event(self, data: AdapterReadPayload) -> None:
|
syndesi/protocols/scpi.py
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from types import EllipsisType
|
|
7
7
|
|
|
8
|
-
from syndesi.adapters.backend.adapter_backend import
|
|
8
|
+
from syndesi.adapters.backend.adapter_backend import AdapterReadPayload
|
|
9
9
|
|
|
10
10
|
from ..adapters.adapter import Adapter
|
|
11
11
|
from ..adapters.ip import IP
|
|
@@ -105,37 +105,40 @@ class SCPI(Protocol):
|
|
|
105
105
|
self,
|
|
106
106
|
command: str,
|
|
107
107
|
timeout: Timeout | None | EllipsisType = ...,
|
|
108
|
-
|
|
108
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
109
109
|
) -> str:
|
|
110
110
|
self._adapter.flushRead()
|
|
111
111
|
self.write(command)
|
|
112
112
|
|
|
113
|
-
return self.read(timeout=timeout,
|
|
113
|
+
return self.read(timeout=timeout, stop_conditions=stop_conditions)
|
|
114
114
|
|
|
115
115
|
def read_raw(
|
|
116
116
|
self,
|
|
117
117
|
timeout: Timeout | None | EllipsisType = ...,
|
|
118
|
-
|
|
119
|
-
) ->
|
|
120
|
-
|
|
118
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
119
|
+
) -> bytes:
|
|
120
|
+
signal = self.read_detailed(
|
|
121
121
|
timeout=timeout,
|
|
122
|
-
|
|
122
|
+
stop_conditions=stop_conditions,
|
|
123
123
|
)
|
|
124
|
+
return signal.data()
|
|
124
125
|
|
|
125
126
|
def read_detailed(
|
|
126
127
|
self,
|
|
127
128
|
timeout: Timeout | None | EllipsisType = ...,
|
|
128
|
-
|
|
129
|
-
) ->
|
|
129
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
130
|
+
) -> AdapterReadPayload:
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return
|
|
132
|
+
signal = self._adapter.read_detailed(
|
|
133
|
+
timeout=timeout, stop_conditions=stop_conditions
|
|
134
|
+
)
|
|
135
|
+
return signal
|
|
135
136
|
|
|
136
137
|
def read(
|
|
137
138
|
self,
|
|
138
139
|
timeout: Timeout | None | EllipsisType = ...,
|
|
139
|
-
|
|
140
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
140
141
|
) -> str:
|
|
141
|
-
|
|
142
|
+
signal = self.read_detailed(timeout=timeout, stop_conditions=stop_conditions)
|
|
143
|
+
raw_data = signal.data()
|
|
144
|
+
return self._unformatCommand(self._from_bytes(raw_data))
|
syndesi/scripts/syndesi.py
CHANGED
|
@@ -22,9 +22,7 @@ def main() -> None:
|
|
|
22
22
|
prog="syndesi", description="Syndesi command line tool", epilog=""
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
parser.add_argument(
|
|
26
|
-
"--version", action="version", version=f"%(prog)s {__version__}"
|
|
27
|
-
)
|
|
25
|
+
parser.add_argument("--version", action="version", version=f"Syndesi {__version__}")
|
|
28
26
|
parser.add_argument("-v", "--verbose", action="store_true")
|
|
29
27
|
parser.add_argument(
|
|
30
28
|
"command",
|
syndesi/tools/backend_api.py
CHANGED
|
@@ -26,25 +26,22 @@ default_host = LOCALHOST
|
|
|
26
26
|
|
|
27
27
|
EXTRA_BUFFER_RESPONSE_TIME = 1
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
class Action(Enum):
|
|
30
31
|
# All adapters
|
|
31
32
|
SELECT_ADAPTER = "select"
|
|
32
33
|
OPEN = "open" # (descriptor,stop_condition) -> ()
|
|
33
|
-
CLOSE = "close" # (descriptor,force) -> ()
|
|
34
|
-
#FORCE_CLOSE = "force_close" # (descriptor,) -> ()
|
|
34
|
+
CLOSE = "close" # (descriptor,force) -> ()
|
|
35
|
+
# FORCE_CLOSE = "force_close" # (descriptor,) -> ()
|
|
35
36
|
WRITE = "write" # (descriptor,data) -> ()
|
|
36
37
|
READ = "read" # (descriptor,full_output,temporary_timeout,temporary_stop_condition) -> (data,metrics)
|
|
37
|
-
|
|
38
|
+
SET_STOP_CONDITIONs = "set_stop_condition" # (descriptor,stop_condition)
|
|
38
39
|
FLUSHREAD = "flushread"
|
|
39
40
|
START_READ = "start_read" # Start a read (descriptor,response_time)
|
|
40
41
|
RESPONSE_TIMEOUT = "response_timeout"
|
|
41
|
-
#GET_BACKEND_TIME = "get_time"
|
|
42
42
|
|
|
43
43
|
# Signal
|
|
44
44
|
ADAPTER_SIGNAL = "adapter_signal"
|
|
45
|
-
#ADAPTER_EVENT_DATA_READY = "event_adapter_data_ready"
|
|
46
|
-
#ADAPTER_EVENT_DISCONNECTED = "event_adapter_disconnected"
|
|
47
|
-
#ADAPTER_EVENT_READ_INIT = "event_adapter_read_init"
|
|
48
45
|
|
|
49
46
|
# Other
|
|
50
47
|
SET_ROLE_ADAPTER = (
|
|
@@ -72,22 +69,15 @@ class Action(Enum):
|
|
|
72
69
|
ERROR_FAILED_TO_OPEN = "error_failed_to_open"
|
|
73
70
|
|
|
74
71
|
|
|
75
|
-
# def is_event(action: Action) -> bool:
|
|
76
|
-
# return action.value.startswith("event_")
|
|
77
|
-
|
|
78
|
-
|
|
79
72
|
def is_action_error(action: Action) -> bool:
|
|
80
73
|
return action.value.startswith("error_")
|
|
81
74
|
|
|
82
|
-
|
|
83
75
|
class BackendException(Exception):
|
|
84
76
|
pass
|
|
85
77
|
|
|
86
|
-
|
|
87
78
|
class ValidFragment(Protocol):
|
|
88
79
|
data: bytes
|
|
89
80
|
|
|
90
|
-
|
|
91
81
|
@dataclass
|
|
92
82
|
class Fragment:
|
|
93
83
|
data: bytes
|
|
@@ -104,23 +94,6 @@ class Fragment:
|
|
|
104
94
|
# raise IndexError('Cannot index invalid fragment')
|
|
105
95
|
return Fragment(self.data[key], self.timestamp)
|
|
106
96
|
|
|
107
|
-
|
|
108
|
-
# def get_conn_addresses(conn: Connection) -> tuple[str, str]:
|
|
109
|
-
# try:
|
|
110
|
-
# fd = conn.fileno()
|
|
111
|
-
# except OSError:
|
|
112
|
-
# return ("closed", "closed")
|
|
113
|
-
# else:
|
|
114
|
-
# sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
|
|
115
|
-
# try:
|
|
116
|
-
# # address, port = sock.getpeername() # (IP, port) tuple
|
|
117
|
-
# peer_address = sock.getpeername()
|
|
118
|
-
# sock_address = sock.getsockname()
|
|
119
|
-
# return sock_address, peer_address
|
|
120
|
-
# except Exception:
|
|
121
|
-
# return ("error", "closed")
|
|
122
|
-
|
|
123
|
-
|
|
124
97
|
BackendResponse = tuple[object, ...]
|
|
125
98
|
|
|
126
99
|
|
|
@@ -199,10 +172,4 @@ class AdapterBackendStatus(Enum):
|
|
|
199
172
|
|
|
200
173
|
class ClientStatus(Enum):
|
|
201
174
|
DISCONNECTED = 0
|
|
202
|
-
CONNECTED = 1
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
# class StatusSnapshot(TypedDict):
|
|
206
|
-
# type : Literal['snapshot']
|
|
207
|
-
# adapters :
|
|
208
|
-
# #clients : List[str]
|
|
175
|
+
CONNECTED = 1
|
syndesi/tools/backend_logger.py
CHANGED