syndesi 0.4.2__py3-none-any.whl → 0.5.0__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/__init__.py +22 -2
- syndesi/adapters/adapter.py +332 -489
- syndesi/adapters/adapter_worker.py +820 -0
- syndesi/adapters/auto.py +58 -25
- syndesi/adapters/descriptors.py +38 -0
- syndesi/adapters/ip.py +203 -71
- syndesi/adapters/serialport.py +154 -25
- syndesi/adapters/stop_conditions.py +354 -0
- syndesi/adapters/timeout.py +58 -21
- syndesi/adapters/visa.py +236 -11
- syndesi/cli/console.py +51 -16
- syndesi/cli/shell.py +95 -47
- syndesi/cli/terminal_tools.py +8 -8
- syndesi/component.py +315 -0
- syndesi/protocols/delimited.py +92 -107
- syndesi/protocols/modbus.py +2368 -868
- syndesi/protocols/protocol.py +186 -33
- syndesi/protocols/raw.py +45 -62
- syndesi/protocols/scpi.py +65 -102
- syndesi/remote/remote.py +188 -0
- syndesi/scripts/syndesi.py +12 -2
- syndesi/tools/errors.py +49 -31
- syndesi/tools/log_settings.py +21 -8
- syndesi/tools/{log.py → logmanager.py} +24 -13
- syndesi/tools/types.py +9 -7
- syndesi/version.py +5 -1
- {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/METADATA +1 -1
- syndesi-0.5.0.dist-info/RECORD +41 -0
- syndesi/adapters/backend/__init__.py +0 -0
- syndesi/adapters/backend/adapter_backend.py +0 -438
- syndesi/adapters/backend/adapter_manager.py +0 -48
- syndesi/adapters/backend/adapter_session.py +0 -346
- syndesi/adapters/backend/backend.py +0 -438
- syndesi/adapters/backend/backend_status.py +0 -0
- syndesi/adapters/backend/backend_tools.py +0 -66
- syndesi/adapters/backend/descriptors.py +0 -153
- syndesi/adapters/backend/ip_backend.py +0 -149
- syndesi/adapters/backend/serialport_backend.py +0 -241
- syndesi/adapters/backend/stop_condition_backend.py +0 -219
- syndesi/adapters/backend/timed_queue.py +0 -39
- syndesi/adapters/backend/timeout.py +0 -252
- syndesi/adapters/backend/visa_backend.py +0 -197
- syndesi/adapters/ip_server.py +0 -102
- syndesi/adapters/stop_condition.py +0 -90
- syndesi/cli/backend_console.py +0 -96
- syndesi/cli/backend_status.py +0 -274
- syndesi/cli/backend_wrapper.py +0 -61
- syndesi/scripts/syndesi_backend.py +0 -37
- syndesi/tools/backend_api.py +0 -175
- syndesi/tools/backend_logger.py +0 -64
- syndesi/tools/exceptions.py +0 -16
- syndesi/tools/internal.py +0 -0
- syndesi-0.4.2.dist-info/RECORD +0 -60
- {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/WHEEL +0 -0
- {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/entry_points.txt +0 -0
- {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {syndesi-0.4.2.dist-info → syndesi-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
# File : adapterbackend.py
|
|
2
|
-
# Author : Sébastien Deriaz
|
|
3
|
-
# License : GPL
|
|
4
|
-
#
|
|
5
|
-
# The adapter backend is the background class that manages communication
|
|
6
|
-
# with one particular device. It is always instanciated in a backend client
|
|
7
|
-
|
|
8
|
-
import logging
|
|
9
|
-
import socket
|
|
10
|
-
import time
|
|
11
|
-
from abc import ABC, abstractmethod
|
|
12
|
-
from collections.abc import Generator
|
|
13
|
-
from dataclasses import dataclass
|
|
14
|
-
from enum import Enum
|
|
15
|
-
from multiprocessing.connection import Connection
|
|
16
|
-
from threading import Thread
|
|
17
|
-
from typing import Protocol
|
|
18
|
-
|
|
19
|
-
from ...tools.backend_api import AdapterBackendStatus, Fragment
|
|
20
|
-
from ...tools.log_settings import LoggerAlias
|
|
21
|
-
from ..stop_condition import StopConditionType
|
|
22
|
-
from .descriptors import Descriptor
|
|
23
|
-
from .stop_condition_backend import (
|
|
24
|
-
ContinuationBackend,
|
|
25
|
-
StopConditionBackend,
|
|
26
|
-
TotalBackend,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class HasFileno(Protocol):
|
|
31
|
-
def fileno(self) -> int:
|
|
32
|
-
return -1
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Selectable = HasFileno | int
|
|
36
|
-
|
|
37
|
-
DEFAULT_STOP_CONDITION = None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class SocketReadException(Exception):
|
|
41
|
-
pass
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# STOP_DESIGNATORS = {
|
|
45
|
-
# # "timeout": {
|
|
46
|
-
# # TimeoutType.RESPONSE: "TR",
|
|
47
|
-
# # TimeoutType.CONTINUATION: "TC",
|
|
48
|
-
# # TimeoutType.TOTAL: "TT",
|
|
49
|
-
# # },
|
|
50
|
-
# "stop_condition": {TerminationBackend: "ST", LengthBackend: "SL"},
|
|
51
|
-
# "previous-buffer": "PB",
|
|
52
|
-
# }
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class Origin(Enum):
|
|
56
|
-
TIMEOUT = "timeout"
|
|
57
|
-
STOP_CONDITION = "stop_condition"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class AdapterSignal:
|
|
61
|
-
pass
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class AdapterDisconnected(AdapterSignal):
|
|
65
|
-
def __str__(self) -> str:
|
|
66
|
-
return "Adapter disconnected"
|
|
67
|
-
|
|
68
|
-
def __repr__(self) -> str:
|
|
69
|
-
return self.__str__()
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# @dataclass
|
|
73
|
-
# class AdapterReadInit(AdapterSignal):
|
|
74
|
-
# end_delay : float | None
|
|
75
|
-
|
|
76
|
-
# def __str__(self) -> str:
|
|
77
|
-
# return f"Read init (end delay : {self.end_delay})"
|
|
78
|
-
|
|
79
|
-
# def __repr__(self) -> str:
|
|
80
|
-
# return self.__str__()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@dataclass
|
|
84
|
-
class AdapterResponseTimeout(AdapterSignal):
|
|
85
|
-
identifier: int
|
|
86
|
-
|
|
87
|
-
def __str__(self) -> str:
|
|
88
|
-
return "Response timeout"
|
|
89
|
-
|
|
90
|
-
def __repr__(self) -> str:
|
|
91
|
-
return self.__str__()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
@dataclass
|
|
95
|
-
class AdapterReadPayload(AdapterSignal):
|
|
96
|
-
fragments: list[Fragment]
|
|
97
|
-
stop_timestamp: float
|
|
98
|
-
stop_condition_type: StopConditionType
|
|
99
|
-
previous_read_buffer_used: bool
|
|
100
|
-
response_timestamp: float | None
|
|
101
|
-
# Only used by client and set by frontend
|
|
102
|
-
response_delay: float | None = None
|
|
103
|
-
|
|
104
|
-
def data(self) -> bytes:
|
|
105
|
-
return b"".join([f.data for f in self.fragments])
|
|
106
|
-
|
|
107
|
-
def __str__(self) -> str:
|
|
108
|
-
return f"Read payload : {self.data()!r}"
|
|
109
|
-
|
|
110
|
-
def __repr__(self) -> str:
|
|
111
|
-
return self.__str__()
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
# This class holds a request made by the client to know if a response
|
|
115
|
-
# is received without the specified time frame
|
|
116
|
-
@dataclass
|
|
117
|
-
class ResponseRequest:
|
|
118
|
-
timestamp: float
|
|
119
|
-
identifier: int
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def nmin(a: float | None, b: float | None) -> float | None:
|
|
123
|
-
if a is None and b is None:
|
|
124
|
-
return None
|
|
125
|
-
elif a is None:
|
|
126
|
-
return b
|
|
127
|
-
elif b is None:
|
|
128
|
-
return a
|
|
129
|
-
else:
|
|
130
|
-
return min(a, b)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
class AdapterBackend(ABC):
|
|
134
|
-
class ThreadCommands(Enum):
|
|
135
|
-
STOP = b"0"
|
|
136
|
-
|
|
137
|
-
class AdapterTimeoutEventOrigin(Enum):
|
|
138
|
-
TIMEOUT = 0
|
|
139
|
-
RESPONSE_REQUEST = 1
|
|
140
|
-
|
|
141
|
-
def __init__(self, descriptor: Descriptor) -> None:
|
|
142
|
-
"""
|
|
143
|
-
Adapter instance
|
|
144
|
-
|
|
145
|
-
Parameters
|
|
146
|
-
----------
|
|
147
|
-
timeout : float or Timeout instance
|
|
148
|
-
Default timeout is Timeout(response=5, continuation=0.2, total=None)
|
|
149
|
-
stop_condition : StopCondition or None
|
|
150
|
-
Default to None
|
|
151
|
-
"""
|
|
152
|
-
self._logger = logging.getLogger(LoggerAlias.ADAPTER_BACKEND.value)
|
|
153
|
-
|
|
154
|
-
super().__init__()
|
|
155
|
-
|
|
156
|
-
# TODO : Switch to multiple stop conditios
|
|
157
|
-
self._stop_conditions: list[StopConditionBackend] = [
|
|
158
|
-
ContinuationBackend(time=0.1)
|
|
159
|
-
]
|
|
160
|
-
self.descriptor = descriptor
|
|
161
|
-
self._thread: Thread | None = None
|
|
162
|
-
self._status = AdapterBackendStatus.DISCONNECTED
|
|
163
|
-
self._thread_commands_read, self._thread_commands_write = socket.socketpair()
|
|
164
|
-
self.backend_signal: Connection | None = None
|
|
165
|
-
self.fragments: list[Fragment] = []
|
|
166
|
-
self._next_timeout_timestamp: float | None = None
|
|
167
|
-
# _response_time indicates if the frontend asked for a read
|
|
168
|
-
# None : No ask
|
|
169
|
-
# float : Ask for a response to happen at the specified value at max
|
|
170
|
-
self._response_request: ResponseRequest | None = None
|
|
171
|
-
self._response_request_start: float | None = None
|
|
172
|
-
|
|
173
|
-
self._first_fragment = True
|
|
174
|
-
|
|
175
|
-
# Buffer for data that has been pulled from the queue but
|
|
176
|
-
# not used because of termination or length stop condition
|
|
177
|
-
self._previous_buffer = Fragment(b"", None)
|
|
178
|
-
|
|
179
|
-
self._last_write_time = time.time()
|
|
180
|
-
|
|
181
|
-
def set_stop_conditions(self, stop_conditions: list[StopConditionBackend]) -> None:
|
|
182
|
-
"""
|
|
183
|
-
Overwrite the stop-condition
|
|
184
|
-
|
|
185
|
-
Parameters
|
|
186
|
-
----------
|
|
187
|
-
stop_condition : StopCondition
|
|
188
|
-
"""
|
|
189
|
-
self._stop_conditions = stop_conditions
|
|
190
|
-
|
|
191
|
-
def flush_read(self) -> bool:
|
|
192
|
-
"""
|
|
193
|
-
Flush the input buffer
|
|
194
|
-
"""
|
|
195
|
-
self._logger.debug("Flush")
|
|
196
|
-
self._previous_buffer = Fragment(b"", None)
|
|
197
|
-
self._response_request = None
|
|
198
|
-
self.fragments = []
|
|
199
|
-
for stop_condition in self._stop_conditions:
|
|
200
|
-
stop_condition.flush_read()
|
|
201
|
-
return True
|
|
202
|
-
|
|
203
|
-
def previous_read_buffer_empty(self) -> bool:
|
|
204
|
-
"""
|
|
205
|
-
Check whether the previous read buffer is empty
|
|
206
|
-
|
|
207
|
-
Returns
|
|
208
|
-
-------
|
|
209
|
-
empty : bool
|
|
210
|
-
"""
|
|
211
|
-
return self._previous_buffer.data == b""
|
|
212
|
-
|
|
213
|
-
@abstractmethod
|
|
214
|
-
def open(self) -> bool:
|
|
215
|
-
"""
|
|
216
|
-
Start communication with the device
|
|
217
|
-
"""
|
|
218
|
-
pass
|
|
219
|
-
|
|
220
|
-
def close(self) -> bool:
|
|
221
|
-
"""
|
|
222
|
-
Stop communication with the device
|
|
223
|
-
"""
|
|
224
|
-
self._status = AdapterBackendStatus.DISCONNECTED
|
|
225
|
-
return True
|
|
226
|
-
|
|
227
|
-
def write(self, data: bytes) -> bool:
|
|
228
|
-
"""
|
|
229
|
-
Send data to the device
|
|
230
|
-
|
|
231
|
-
Parameters
|
|
232
|
-
----------
|
|
233
|
-
data : bytes or str
|
|
234
|
-
"""
|
|
235
|
-
self._last_write_time = time.time()
|
|
236
|
-
self._logger.debug(f"Write {repr(data)}")
|
|
237
|
-
return True
|
|
238
|
-
|
|
239
|
-
@abstractmethod
|
|
240
|
-
def selectable(self) -> HasFileno | None:
|
|
241
|
-
"""
|
|
242
|
-
Return an object with a fileno() method (e.g., socket, Connection) suitable for use with select/poll.
|
|
243
|
-
"""
|
|
244
|
-
raise NotImplementedError
|
|
245
|
-
|
|
246
|
-
@abstractmethod
|
|
247
|
-
def _socket_read(self) -> Fragment:
|
|
248
|
-
raise NotImplementedError
|
|
249
|
-
|
|
250
|
-
def _fragments_to_string(self, fragments: list[Fragment]) -> str:
|
|
251
|
-
if len(fragments) > 0:
|
|
252
|
-
return "+".join(repr(f.data) for f in fragments)
|
|
253
|
-
else:
|
|
254
|
-
return str([])
|
|
255
|
-
|
|
256
|
-
def on_socket_ready(self) -> Generator[AdapterSignal, None, None]:
|
|
257
|
-
fragment = self._socket_read()
|
|
258
|
-
if fragment.timestamp is not None and self._last_write_time is not None:
|
|
259
|
-
fragment_delta_t = fragment.timestamp - self._last_write_time
|
|
260
|
-
else:
|
|
261
|
-
fragment_delta_t = float("nan")
|
|
262
|
-
if fragment.data == b"":
|
|
263
|
-
self.close()
|
|
264
|
-
yield AdapterDisconnected()
|
|
265
|
-
else:
|
|
266
|
-
self._logger.debug(
|
|
267
|
-
f"New fragment {fragment_delta_t:+.3f} {fragment}"
|
|
268
|
-
+ (" (first)" if self._first_fragment else "")
|
|
269
|
-
)
|
|
270
|
-
if self._status == AdapterBackendStatus.CONNECTED:
|
|
271
|
-
t = time.time()
|
|
272
|
-
|
|
273
|
-
# If there's a response request, disable it if there's a timeout stop condition
|
|
274
|
-
# The stop-condition will do the job
|
|
275
|
-
|
|
276
|
-
if self._response_request is not None:
|
|
277
|
-
for stop_condition in self._stop_conditions:
|
|
278
|
-
if isinstance(
|
|
279
|
-
stop_condition, (ContinuationBackend, TotalBackend)
|
|
280
|
-
):
|
|
281
|
-
self._response_request = None
|
|
282
|
-
break
|
|
283
|
-
|
|
284
|
-
while True:
|
|
285
|
-
if self._first_fragment:
|
|
286
|
-
self._first_fragment = False
|
|
287
|
-
self._read_start_timestamp = t
|
|
288
|
-
for stop_condition in self._stop_conditions:
|
|
289
|
-
stop_condition.initiate_read()
|
|
290
|
-
|
|
291
|
-
stop = False
|
|
292
|
-
kept = fragment
|
|
293
|
-
|
|
294
|
-
# Run each stop condition one after the other, if a stop is reached, stop evaluating
|
|
295
|
-
stop_condition_type: StopConditionType
|
|
296
|
-
for stop_condition in self._stop_conditions:
|
|
297
|
-
(
|
|
298
|
-
stop,
|
|
299
|
-
kept,
|
|
300
|
-
self._previous_buffer,
|
|
301
|
-
self._next_timeout_timestamp,
|
|
302
|
-
) = stop_condition.evaluate(kept)
|
|
303
|
-
if stop:
|
|
304
|
-
stop_condition_type = stop_condition.type()
|
|
305
|
-
break
|
|
306
|
-
|
|
307
|
-
# if kept.data != b'':
|
|
308
|
-
# self.fragments.append(kept)
|
|
309
|
-
|
|
310
|
-
self.fragments.append(kept)
|
|
311
|
-
|
|
312
|
-
if stop:
|
|
313
|
-
self._first_fragment = True
|
|
314
|
-
self._logger.debug(
|
|
315
|
-
f"Payload {self._fragments_to_string(self.fragments)} ({stop_condition_type.value})"
|
|
316
|
-
)
|
|
317
|
-
if (
|
|
318
|
-
self._response_request_start is None
|
|
319
|
-
or len(self.fragments) == 0
|
|
320
|
-
):
|
|
321
|
-
response_delay = None
|
|
322
|
-
else:
|
|
323
|
-
if self.fragments[0].timestamp is None:
|
|
324
|
-
response_delay = None
|
|
325
|
-
else:
|
|
326
|
-
response_delay = (
|
|
327
|
-
self.fragments[0].timestamp
|
|
328
|
-
- self._response_request_start
|
|
329
|
-
)
|
|
330
|
-
self._response_request_start = None
|
|
331
|
-
yield AdapterReadPayload(
|
|
332
|
-
fragments=self.fragments,
|
|
333
|
-
stop_timestamp=t,
|
|
334
|
-
stop_condition_type=stop_condition_type,
|
|
335
|
-
previous_read_buffer_used=False,
|
|
336
|
-
response_timestamp=self.fragments[0].timestamp,
|
|
337
|
-
response_delay=response_delay,
|
|
338
|
-
)
|
|
339
|
-
self._next_timeout_timestamp = None # Experiment !
|
|
340
|
-
self.fragments.clear()
|
|
341
|
-
|
|
342
|
-
if len(self._previous_buffer.data) > 0 and stop:
|
|
343
|
-
# If there's a previous buffer, put it in the fragment and loop again
|
|
344
|
-
# Only loop if there's a stop (oterwise a stop would never happen again)
|
|
345
|
-
fragment = self._previous_buffer
|
|
346
|
-
|
|
347
|
-
else:
|
|
348
|
-
# If not, quit now
|
|
349
|
-
break
|
|
350
|
-
|
|
351
|
-
return None
|
|
352
|
-
|
|
353
|
-
def start_read(self, response_time: float, identifier: int) -> None:
|
|
354
|
-
"""
|
|
355
|
-
Start a read operation. This is a signal from the frontend. The only goal is to set the response time
|
|
356
|
-
and tell the frontend if nothing arrives within a set time
|
|
357
|
-
"""
|
|
358
|
-
self._response_request_start = time.time()
|
|
359
|
-
self._logger.debug(f"Setup read [{identifier}] in {response_time:.3f} s")
|
|
360
|
-
self._response_request = ResponseRequest(
|
|
361
|
-
self._response_request_start + response_time, identifier
|
|
362
|
-
)
|
|
363
|
-
|
|
364
|
-
@abstractmethod
|
|
365
|
-
def is_opened(self) -> bool:
|
|
366
|
-
"""
|
|
367
|
-
Return True if adapter is opened, False otherwise
|
|
368
|
-
"""
|
|
369
|
-
|
|
370
|
-
def __str__(self) -> str:
|
|
371
|
-
return self.descriptor.__str__()
|
|
372
|
-
|
|
373
|
-
def __repr__(self) -> str:
|
|
374
|
-
return self.__str__()
|
|
375
|
-
|
|
376
|
-
def on_timeout_event(self) -> AdapterSignal | None:
|
|
377
|
-
t = time.time()
|
|
378
|
-
|
|
379
|
-
if self._next_timeout_origin == self.AdapterTimeoutEventOrigin.TIMEOUT:
|
|
380
|
-
self._next_timeout_timestamp = None
|
|
381
|
-
self._first_fragment = True
|
|
382
|
-
if self._response_request_start is None or len(self.fragments) == 0:
|
|
383
|
-
response_delay = None
|
|
384
|
-
else:
|
|
385
|
-
if self.fragments[0].timestamp is not None:
|
|
386
|
-
response_delay = (
|
|
387
|
-
self.fragments[0].timestamp - self._response_request_start
|
|
388
|
-
)
|
|
389
|
-
else:
|
|
390
|
-
response_delay = None
|
|
391
|
-
self._response_request_start = None
|
|
392
|
-
|
|
393
|
-
output = AdapterReadPayload(
|
|
394
|
-
stop_timestamp=t,
|
|
395
|
-
stop_condition_type=StopConditionType.TIMEOUT,
|
|
396
|
-
previous_read_buffer_used=False,
|
|
397
|
-
fragments=self.fragments,
|
|
398
|
-
response_timestamp=(
|
|
399
|
-
self.fragments[0].timestamp if len(self.fragments) > 0 else None
|
|
400
|
-
),
|
|
401
|
-
response_delay=response_delay,
|
|
402
|
-
)
|
|
403
|
-
# Reset response request
|
|
404
|
-
if self._response_request is not None:
|
|
405
|
-
self._response_request = None
|
|
406
|
-
self._response_request_start = None
|
|
407
|
-
# Clear all of the fragments
|
|
408
|
-
self.fragments = []
|
|
409
|
-
return output
|
|
410
|
-
|
|
411
|
-
elif (
|
|
412
|
-
self._next_timeout_origin == self.AdapterTimeoutEventOrigin.RESPONSE_REQUEST
|
|
413
|
-
):
|
|
414
|
-
if self._response_request is not None:
|
|
415
|
-
signal = AdapterResponseTimeout(self._response_request.identifier)
|
|
416
|
-
self._response_request = None
|
|
417
|
-
return signal
|
|
418
|
-
|
|
419
|
-
return None
|
|
420
|
-
|
|
421
|
-
def get_next_timeout(self) -> float | None:
|
|
422
|
-
min_timestamp = None
|
|
423
|
-
self._next_timeout_origin = None
|
|
424
|
-
|
|
425
|
-
if self._next_timeout_timestamp is not None:
|
|
426
|
-
min_timestamp = self._next_timeout_timestamp
|
|
427
|
-
self._next_timeout_origin = self.AdapterTimeoutEventOrigin.TIMEOUT
|
|
428
|
-
|
|
429
|
-
if self._response_request is not None:
|
|
430
|
-
if (
|
|
431
|
-
min_timestamp is None
|
|
432
|
-
or self._response_request.timestamp < min_timestamp
|
|
433
|
-
):
|
|
434
|
-
min_timestamp = self._response_request.timestamp
|
|
435
|
-
self._next_timeout_origin = (
|
|
436
|
-
self.AdapterTimeoutEventOrigin.RESPONSE_REQUEST
|
|
437
|
-
)
|
|
438
|
-
return min_timestamp
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# File : adapter_manager.py
|
|
2
|
-
# Author : Sébastien Deriaz
|
|
3
|
-
# License : GPL
|
|
4
|
-
#
|
|
5
|
-
# The adapter manager instanciates adapters based on a given descriptor
|
|
6
|
-
# It is used by the backend to create adapters
|
|
7
|
-
|
|
8
|
-
# from .adapter_backend import AdapterBackend
|
|
9
|
-
# from .descriptors import Descriptor, IPDescriptor, SerialPortDescriptor, VisaDescriptor
|
|
10
|
-
# from .ip_backend import IPBackend
|
|
11
|
-
# from .serialport_backend import SerialPortBackend
|
|
12
|
-
# from .visa_backend import VisaBackend
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# class AdapterManager:
|
|
16
|
-
# def __init__(self) -> None:
|
|
17
|
-
# self.adapters : Dict[str, AdapterBackend] = {}
|
|
18
|
-
|
|
19
|
-
# def get_adapter(self, descriptor: Descriptor) -> AdapterBackend:
|
|
20
|
-
# string_descriptor = str(descriptor)
|
|
21
|
-
# if string_descriptor not in self.adapters:
|
|
22
|
-
# # The adapter doesn't exist, create it
|
|
23
|
-
# if isinstance(
|
|
24
|
-
# descriptor, SerialPortDescriptor
|
|
25
|
-
# ): # Add mandatory timeout and stop_condition here ?
|
|
26
|
-
# self.adapters[string_descriptor] = SerialPortBackend(
|
|
27
|
-
# descriptor=SerialPortDescriptor(
|
|
28
|
-
# port=descriptor.port, baudrate=descriptor.baudrate
|
|
29
|
-
# )
|
|
30
|
-
# )
|
|
31
|
-
# elif isinstance(descriptor, IPDescriptor):
|
|
32
|
-
# self.adapters[string_descriptor] = IPBackend(descriptor=descriptor)
|
|
33
|
-
# elif isinstance(descriptor, VisaDescriptor):
|
|
34
|
-
# self.adapters[string_descriptor] = VisaBackend(descriptor=descriptor)
|
|
35
|
-
# else:
|
|
36
|
-
# raise ValueError(f"Unsupported descriptor : {descriptor}")
|
|
37
|
-
|
|
38
|
-
# return self.adapters[string_descriptor]
|
|
39
|
-
|
|
40
|
-
# def close_adapter(self, descriptor: Descriptor):
|
|
41
|
-
# string_decriptor = str(descriptor)
|
|
42
|
-
# if string_decriptor in self.adapters:
|
|
43
|
-
# adapter = self.adapters.pop(string_decriptor)
|
|
44
|
-
# adapter.close()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# # The singleton instance
|
|
48
|
-
# adapterManager = AdapterManager()
|