syndesi 0.1.4__py3-none-any.whl → 0.3.1__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 +3 -0
- syndesi/__main__.py +4 -0
- syndesi/adapters/__init__.py +3 -3
- syndesi/adapters/adapter.py +528 -0
- syndesi/adapters/auto.py +49 -0
- syndesi/adapters/backend/adapter_backend.py +364 -0
- syndesi/adapters/backend/adapter_manager.py +49 -0
- syndesi/adapters/backend/adapter_session.py +363 -0
- syndesi/adapters/backend/backend.py +369 -0
- syndesi/{descriptors/syndesi/__init__.py → adapters/backend/backend_status.py} +0 -0
- syndesi/adapters/backend/backend_tools.py +55 -0
- syndesi/adapters/backend/descriptors.py +140 -0
- syndesi/adapters/backend/ip_backend.py +137 -0
- syndesi/adapters/backend/serialport_backend.py +232 -0
- syndesi/adapters/backend/stop_condition_backend.py +319 -0
- syndesi/adapters/backend/timed_queue.py +39 -0
- syndesi/adapters/backend/timeout.py +252 -0
- syndesi/adapters/backend/visa_backend.py +179 -0
- syndesi/adapters/ip.py +75 -65
- syndesi/adapters/ip_server.py +102 -0
- syndesi/adapters/serialport.py +74 -0
- syndesi/adapters/stop_condition.py +102 -0
- syndesi/adapters/timeout.py +99 -0
- syndesi/adapters/visa.py +38 -54
- {tests → syndesi/cli}/__init__.py +0 -0
- syndesi/cli/adapter_shell.py +210 -0
- syndesi/cli/backend_console.py +88 -0
- syndesi/cli/backend_status.py +212 -0
- syndesi/cli/backend_wrapper.py +50 -0
- syndesi/cli/shell.py +269 -0
- syndesi/protocols/__init__.py +8 -3
- syndesi/protocols/delimited.py +145 -45
- syndesi/protocols/modbus.py +1561 -0
- syndesi/protocols/protocol.py +71 -0
- syndesi/protocols/raw.py +45 -60
- syndesi/protocols/scpi.py +154 -33
- syndesi/scripts/__init__.py +0 -0
- syndesi/scripts/syndesi.py +52 -0
- syndesi/scripts/syndesi_backend.py +43 -0
- syndesi/tools/backend_api.py +190 -0
- syndesi/tools/backend_logger.py +53 -0
- syndesi/tools/errors.py +18 -0
- syndesi/tools/exceptions.py +7 -1
- syndesi/tools/internal.py +0 -0
- syndesi/tools/log.py +143 -0
- syndesi/tools/log_settings.py +16 -0
- syndesi/tools/types.py +87 -46
- syndesi/version.py +3 -0
- {syndesi-0.1.4.dist-info → syndesi-0.3.1.dist-info}/METADATA +24 -22
- syndesi-0.3.1.dist-info/RECORD +56 -0
- {syndesi-0.1.4.dist-info → syndesi-0.3.1.dist-info}/WHEEL +1 -1
- syndesi-0.3.1.dist-info/entry_points.txt +3 -0
- {syndesi-0.1.4.dist-info → syndesi-0.3.1.dist-info/licenses}/LICENSE +194 -194
- syndesi-0.3.1.dist-info/top_level.txt +1 -0
- syndesi/adapters/IP.py +0 -81
- syndesi/adapters/VISA.py +0 -50
- syndesi/adapters/iadapter.py +0 -73
- syndesi/adapters/serial.py +0 -37
- syndesi/descriptors/IP.py +0 -9
- syndesi/descriptors/Serial.py +0 -10
- syndesi/descriptors/VISA.py +0 -31
- syndesi/descriptors/__init__.py +0 -1
- syndesi/descriptors/descriptor.py +0 -9
- syndesi/descriptors/ip.py +0 -9
- syndesi/descriptors/syndesi/Syndesi.py +0 -9
- syndesi/descriptors/syndesi/_device.py +0 -25
- syndesi/descriptors/syndesi/devices.py +0 -10
- syndesi/descriptors/syndesi/frame.py +0 -133
- syndesi/descriptors/syndesi/network.py +0 -41
- syndesi/descriptors/syndesi/payload.py +0 -11
- syndesi/descriptors/syndesi/sdid.py +0 -21
- syndesi/descriptors/visa.py +0 -31
- syndesi/protocols/commands.py +0 -56
- syndesi/protocols/iprotocol.py +0 -14
- syndesi/protocols/sdp.py +0 -14
- syndesi/tools/stop_conditions.py +0 -148
- syndesi-0.1.4.data/scripts/syndesi +0 -1
- syndesi-0.1.4.dist-info/RECORD +0 -42
- syndesi-0.1.4.dist-info/top_level.txt +0 -2
- {experiments → syndesi/adapters/backend}/__init__.py +0 -0
|
@@ -0,0 +1,364 @@
|
|
|
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 uuid
|
|
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 time import time
|
|
18
|
+
from typing import Union, Optional, List, Protocol
|
|
19
|
+
|
|
20
|
+
from ...tools.backend_api import AdapterBackendStatus, Fragment
|
|
21
|
+
from ...tools.log_settings import LoggerAlias
|
|
22
|
+
from .descriptors import Descriptor
|
|
23
|
+
from .stop_condition_backend import (
|
|
24
|
+
LengthBackend,
|
|
25
|
+
StopConditionBackend,
|
|
26
|
+
StopConditionType,
|
|
27
|
+
TerminationBackend,
|
|
28
|
+
TimeoutStopConditionBackend
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
class HasFileno(Protocol):
|
|
32
|
+
def fileno(self) -> int:
|
|
33
|
+
return -1
|
|
34
|
+
|
|
35
|
+
Selectable = Union[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
|
+
received_response_in_time: bool
|
|
75
|
+
uuid: uuid.UUID
|
|
76
|
+
|
|
77
|
+
def __str__(self) -> str:
|
|
78
|
+
return f"Read init {str(self.uuid)[:5]}... {'in time' if self.received_response_in_time else 'not in time'}"
|
|
79
|
+
|
|
80
|
+
def __repr__(self) -> str:
|
|
81
|
+
return self.__str__()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass
|
|
85
|
+
class AdapterReadPayload(AdapterSignal):
|
|
86
|
+
fragments: list[Fragment]
|
|
87
|
+
stop_timestamp: float
|
|
88
|
+
stop_condition_type: StopConditionType
|
|
89
|
+
previous_read_buffer_used: bool
|
|
90
|
+
# Only used by client
|
|
91
|
+
response_time: float | None = None
|
|
92
|
+
|
|
93
|
+
def data(self) -> bytes:
|
|
94
|
+
return b"".join([f.data for f in self.fragments])
|
|
95
|
+
|
|
96
|
+
def __str__(self) -> str:
|
|
97
|
+
return f"Read payload : {self.data()!r}"
|
|
98
|
+
|
|
99
|
+
def __repr__(self) -> str:
|
|
100
|
+
return self.__str__()
|
|
101
|
+
|
|
102
|
+
# This class holds a request made by the client to know if a response
|
|
103
|
+
# is received without the specified time frame
|
|
104
|
+
@dataclass
|
|
105
|
+
class ResponseRequest:
|
|
106
|
+
timestamp : float
|
|
107
|
+
uuid : uuid.UUID
|
|
108
|
+
|
|
109
|
+
class AdapterBackend(ABC):
|
|
110
|
+
class ThreadCommands(Enum):
|
|
111
|
+
STOP = b"0"
|
|
112
|
+
|
|
113
|
+
class AdapterTimeoutEventOrigin(Enum):
|
|
114
|
+
TIMEOUT = 0
|
|
115
|
+
RESPONSE_READ_INIT = 1
|
|
116
|
+
|
|
117
|
+
def __init__(self, descriptor: Descriptor) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Adapter instance
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
timeout : float or Timeout instance
|
|
124
|
+
Default timeout is Timeout(response=5, continuation=0.2, total=None)
|
|
125
|
+
stop_condition : StopCondition or None
|
|
126
|
+
Default to None
|
|
127
|
+
"""
|
|
128
|
+
self._logger = logging.getLogger(LoggerAlias.ADAPTER_BACKEND.value)
|
|
129
|
+
|
|
130
|
+
super().__init__()
|
|
131
|
+
|
|
132
|
+
# TODO : Switch to multiple stop conditios
|
|
133
|
+
self._stop_condition: StopConditionBackend = TimeoutStopConditionBackend(continuation=0.1, total=None)
|
|
134
|
+
self.descriptor = descriptor
|
|
135
|
+
self._thread: Thread | None = None
|
|
136
|
+
self._status = AdapterBackendStatus.DISCONNECTED
|
|
137
|
+
self._thread_commands_read, self._thread_commands_write = socket.socketpair()
|
|
138
|
+
self.backend_signal: Optional[Connection] = None
|
|
139
|
+
self.fragments : List[Fragment] = []
|
|
140
|
+
self._start_read_timestamp : Optional[float] = None
|
|
141
|
+
# self._data_out_queue = []
|
|
142
|
+
self._next_timeout_timestamp : Optional[float] = None
|
|
143
|
+
# _response_time indicates if the frontend asked for a read
|
|
144
|
+
# None : No ask
|
|
145
|
+
# float : Ask for a response to happen at the specified value at max
|
|
146
|
+
self._response_request : Optional[ResponseRequest] = None
|
|
147
|
+
|
|
148
|
+
self._first_fragment = True
|
|
149
|
+
|
|
150
|
+
# Buffer for data that has been pulled from the queue but
|
|
151
|
+
# not used because of termination or length stop condition
|
|
152
|
+
self._previous_buffer = Fragment(b"", None)
|
|
153
|
+
|
|
154
|
+
self._last_write_time = time()
|
|
155
|
+
|
|
156
|
+
def set_stop_condition(self, stop_condition : StopConditionBackend) -> None:
|
|
157
|
+
"""
|
|
158
|
+
Overwrite the stop-condition
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
stop_condition : StopCondition
|
|
163
|
+
"""
|
|
164
|
+
self._stop_condition = stop_condition
|
|
165
|
+
|
|
166
|
+
def flush_read(self) -> bool:
|
|
167
|
+
"""
|
|
168
|
+
Flush the input buffer
|
|
169
|
+
"""
|
|
170
|
+
self._logger.debug("Flush")
|
|
171
|
+
self._previous_buffer = Fragment(b"", None)
|
|
172
|
+
self._response_request = None
|
|
173
|
+
self.fragments = []
|
|
174
|
+
if self._stop_condition is not None:
|
|
175
|
+
self._stop_condition.flush_read()
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
def previous_read_buffer_empty(self) -> bool:
|
|
179
|
+
"""
|
|
180
|
+
Check whether the previous read buffer is empty
|
|
181
|
+
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
empty : bool
|
|
185
|
+
"""
|
|
186
|
+
return self._previous_buffer.data == b""
|
|
187
|
+
|
|
188
|
+
@abstractmethod
|
|
189
|
+
def open(self) -> bool:
|
|
190
|
+
"""
|
|
191
|
+
Start communication with the device
|
|
192
|
+
"""
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
def close(self) -> bool:
|
|
196
|
+
"""
|
|
197
|
+
Stop communication with the device
|
|
198
|
+
"""
|
|
199
|
+
self._logger.debug("Closing adapter and stopping read thread")
|
|
200
|
+
# self._thread_commands_write.send(self.ThreadCommands.STOP.value)
|
|
201
|
+
# if self._thread is not None and self._thread.is_alive():
|
|
202
|
+
# try:
|
|
203
|
+
# self._thread.join()
|
|
204
|
+
# except RuntimeError:
|
|
205
|
+
# # If the thread cannot be joined, then so be it
|
|
206
|
+
# pass
|
|
207
|
+
self._status = AdapterBackendStatus.DISCONNECTED
|
|
208
|
+
return True
|
|
209
|
+
|
|
210
|
+
def write(self, data: bytes) -> bool:
|
|
211
|
+
"""
|
|
212
|
+
Send data to the device
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
data : bytes or str
|
|
217
|
+
"""
|
|
218
|
+
self._last_write_time = time()
|
|
219
|
+
self._logger.debug(f"Write {repr(data)}")
|
|
220
|
+
return True
|
|
221
|
+
|
|
222
|
+
@abstractmethod
|
|
223
|
+
def selectable(self) -> Optional[HasFileno]:
|
|
224
|
+
"""
|
|
225
|
+
Return an object with a fileno() method (e.g., socket, Connection) suitable for use with select/poll.
|
|
226
|
+
"""
|
|
227
|
+
raise NotImplementedError
|
|
228
|
+
|
|
229
|
+
@abstractmethod
|
|
230
|
+
def _socket_read(self) -> Fragment:
|
|
231
|
+
raise NotImplementedError
|
|
232
|
+
|
|
233
|
+
def on_socket_ready(self) -> Generator[AdapterSignal, None, None]:
|
|
234
|
+
fragment = self._socket_read()
|
|
235
|
+
if fragment.timestamp is not None and self._last_write_time is not None:
|
|
236
|
+
fragment_delta_t = fragment.timestamp - self._last_write_time
|
|
237
|
+
else:
|
|
238
|
+
fragment_delta_t = float("nan")
|
|
239
|
+
self._logger.debug(f"New fragment {fragment_delta_t:+.3f} {fragment}")
|
|
240
|
+
if fragment.data == b"":
|
|
241
|
+
self.close()
|
|
242
|
+
yield AdapterDisconnected()
|
|
243
|
+
|
|
244
|
+
else:
|
|
245
|
+
if self._status == AdapterBackendStatus.CONNECTED:
|
|
246
|
+
t = time()
|
|
247
|
+
|
|
248
|
+
while True:
|
|
249
|
+
if self._first_fragment:
|
|
250
|
+
self._logger.debug('First fragment')
|
|
251
|
+
self._read_start_time = t
|
|
252
|
+
self._stop_condition.initiate_read()
|
|
253
|
+
self._first_fragment = False
|
|
254
|
+
if self._response_request is not None:
|
|
255
|
+
received_response_in_time = t < self._response_request.timestamp
|
|
256
|
+
# The frontend asked for a response, tell it
|
|
257
|
+
yield AdapterReadInit(
|
|
258
|
+
received_response_in_time, self._response_request.uuid
|
|
259
|
+
)
|
|
260
|
+
self._response_request = None
|
|
261
|
+
|
|
262
|
+
stop, kept, self._previous_buffer, self._next_timeout_timestamp = (
|
|
263
|
+
self._stop_condition.evaluate(fragment, t)
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
self.fragments.append(kept)
|
|
267
|
+
|
|
268
|
+
if stop:
|
|
269
|
+
self._logger.debug('Stop')
|
|
270
|
+
self._first_fragment = True
|
|
271
|
+
yield AdapterReadPayload(
|
|
272
|
+
fragments=self.fragments,
|
|
273
|
+
stop_timestamp=t,
|
|
274
|
+
stop_condition_type=self._stop_condition._TYPE,
|
|
275
|
+
previous_read_buffer_used=False,
|
|
276
|
+
response_time=(
|
|
277
|
+
t - self._start_read_timestamp
|
|
278
|
+
if self._start_read_timestamp is not None
|
|
279
|
+
else None
|
|
280
|
+
),
|
|
281
|
+
)
|
|
282
|
+
self.fragments.clear()
|
|
283
|
+
|
|
284
|
+
if len(self._previous_buffer.data) > 0 and stop:
|
|
285
|
+
# If there's a previous buffer, put it in the fragment and loop again
|
|
286
|
+
# Only loop if there's a stop (oterwise a stop would never happen again)
|
|
287
|
+
fragment = self._previous_buffer
|
|
288
|
+
|
|
289
|
+
else:
|
|
290
|
+
# If not, quit now
|
|
291
|
+
break
|
|
292
|
+
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
def start_read(self, response_time: float, uuid: uuid.UUID) -> None:
|
|
296
|
+
"""
|
|
297
|
+
Start a read operation. This is a signal from the frontend. The only goal is to set the response time
|
|
298
|
+
and tell the frontend if nothing arrives within a set time
|
|
299
|
+
"""
|
|
300
|
+
t = time()
|
|
301
|
+
self._start_read_timestamp = t
|
|
302
|
+
self._logger.debug(f"Setup read {str(uuid)[:5]}... in {response_time:.3f} s")
|
|
303
|
+
self._response_request = ResponseRequest(t + response_time, uuid)
|
|
304
|
+
|
|
305
|
+
@abstractmethod
|
|
306
|
+
def is_opened(self) -> bool:
|
|
307
|
+
"""
|
|
308
|
+
Return True if adapter is opened, False otherwise
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
def __str__(self) -> str:
|
|
312
|
+
return self.descriptor.__str__()
|
|
313
|
+
|
|
314
|
+
def __repr__(self) -> str:
|
|
315
|
+
return self.__str__()
|
|
316
|
+
|
|
317
|
+
def on_timeout_event(self) -> Optional[AdapterSignal]:
|
|
318
|
+
t = time()
|
|
319
|
+
|
|
320
|
+
if self._next_timeout_origin == self.AdapterTimeoutEventOrigin.TIMEOUT:
|
|
321
|
+
self._next_timeout_timestamp = None
|
|
322
|
+
self._first_fragment = True
|
|
323
|
+
output = AdapterReadPayload(
|
|
324
|
+
stop_timestamp=t,
|
|
325
|
+
stop_condition_type=self._stop_condition._TYPE,
|
|
326
|
+
previous_read_buffer_used=False,
|
|
327
|
+
fragments=self.fragments,
|
|
328
|
+
response_time=(
|
|
329
|
+
t - self._start_read_timestamp
|
|
330
|
+
if self._start_read_timestamp is not None
|
|
331
|
+
else None
|
|
332
|
+
),
|
|
333
|
+
)
|
|
334
|
+
# Clear all of the fragments
|
|
335
|
+
self.fragments = []
|
|
336
|
+
return output
|
|
337
|
+
|
|
338
|
+
elif (
|
|
339
|
+
self._next_timeout_origin
|
|
340
|
+
== self.AdapterTimeoutEventOrigin.RESPONSE_READ_INIT
|
|
341
|
+
):
|
|
342
|
+
if self._response_request is not None:
|
|
343
|
+
uuid = self._response_request.uuid
|
|
344
|
+
self._response_request = None
|
|
345
|
+
return AdapterReadInit(False, uuid)
|
|
346
|
+
|
|
347
|
+
return None
|
|
348
|
+
|
|
349
|
+
def get_next_timeout(self) -> Optional[float]:
|
|
350
|
+
min_timestamp = None
|
|
351
|
+
self._next_timeout_origin = None
|
|
352
|
+
|
|
353
|
+
if self._next_timeout_timestamp is not None:
|
|
354
|
+
min_timestamp = self._next_timeout_timestamp
|
|
355
|
+
self._next_timeout_origin = self.AdapterTimeoutEventOrigin.TIMEOUT
|
|
356
|
+
|
|
357
|
+
if self._response_request is not None:
|
|
358
|
+
if min_timestamp is None or self._response_request.timestamp < min_timestamp:
|
|
359
|
+
min_timestamp = self._response_request.timestamp
|
|
360
|
+
self._next_timeout_origin = (
|
|
361
|
+
self.AdapterTimeoutEventOrigin.RESPONSE_READ_INIT
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
return min_timestamp
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
|
|
16
|
+
# class AdapterManager:
|
|
17
|
+
# def __init__(self) -> None:
|
|
18
|
+
# self.adapters : Dict[str, AdapterBackend] = {}
|
|
19
|
+
|
|
20
|
+
# def get_adapter(self, descriptor: Descriptor) -> AdapterBackend:
|
|
21
|
+
# string_descriptor = str(descriptor)
|
|
22
|
+
# if string_descriptor not in self.adapters:
|
|
23
|
+
# # The adapter doesn't exist, create it
|
|
24
|
+
# if isinstance(
|
|
25
|
+
# descriptor, SerialPortDescriptor
|
|
26
|
+
# ): # Add mandatory timeout and stop_condition here ?
|
|
27
|
+
# self.adapters[string_descriptor] = SerialPortBackend(
|
|
28
|
+
# descriptor=SerialPortDescriptor(
|
|
29
|
+
# port=descriptor.port, baudrate=descriptor.baudrate
|
|
30
|
+
# )
|
|
31
|
+
# )
|
|
32
|
+
# elif isinstance(descriptor, IPDescriptor):
|
|
33
|
+
# self.adapters[string_descriptor] = IPBackend(descriptor=descriptor)
|
|
34
|
+
# elif isinstance(descriptor, VisaDescriptor):
|
|
35
|
+
# self.adapters[string_descriptor] = VisaBackend(descriptor=descriptor)
|
|
36
|
+
# else:
|
|
37
|
+
# raise ValueError(f"Unsupported descriptor : {descriptor}")
|
|
38
|
+
|
|
39
|
+
# return self.adapters[string_descriptor]
|
|
40
|
+
|
|
41
|
+
# def close_adapter(self, descriptor: Descriptor):
|
|
42
|
+
# string_decriptor = str(descriptor)
|
|
43
|
+
# if string_decriptor in self.adapters:
|
|
44
|
+
# adapter = self.adapters.pop(string_decriptor)
|
|
45
|
+
# adapter.close()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# # The singleton instance
|
|
49
|
+
# adapterManager = AdapterManager()
|