syndesi 0.3.2__py3-none-any.whl → 0.4.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/adapters/adapter.py +126 -165
- syndesi/adapters/auto.py +1 -1
- syndesi/adapters/backend/adapter_backend.py +96 -63
- syndesi/adapters/backend/adapter_session.py +53 -153
- syndesi/adapters/backend/descriptors.py +3 -2
- syndesi/adapters/backend/ip_backend.py +1 -0
- syndesi/adapters/backend/serialport_backend.py +19 -13
- syndesi/adapters/backend/stop_condition_backend.py +99 -243
- syndesi/adapters/backend/visa_backend.py +7 -7
- syndesi/adapters/ip.py +6 -10
- syndesi/adapters/serialport.py +4 -5
- syndesi/adapters/stop_condition.py +47 -26
- syndesi/adapters/timeout.py +2 -2
- syndesi/adapters/visa.py +2 -2
- syndesi/cli/shell_tools.py +95 -97
- syndesi/protocols/delimited.py +16 -21
- syndesi/protocols/modbus.py +17 -14
- syndesi/protocols/raw.py +20 -16
- syndesi/protocols/scpi.py +17 -15
- syndesi/tools/backend_api.py +15 -16
- syndesi/tools/errors.py +28 -0
- syndesi/version.py +1 -1
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/METADATA +2 -1
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/RECORD +28 -28
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/WHEEL +0 -0
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/entry_points.txt +0 -0
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {syndesi-0.3.2.dist-info → syndesi-0.4.1.dist-info}/top_level.txt +0 -0
|
@@ -69,8 +69,9 @@ class IPDescriptor(Descriptor):
|
|
|
69
69
|
|
|
70
70
|
DETECTION_PATTERN = r"(\d+.\d+.\d+.\d+|[\w\.]+):\d+:(UDP|TCP)"
|
|
71
71
|
address: str
|
|
72
|
+
transport: Transport
|
|
72
73
|
port: int | None = None
|
|
73
|
-
transport: Transport | None = None
|
|
74
|
+
#transport: Transport | None = None
|
|
74
75
|
|
|
75
76
|
@staticmethod
|
|
76
77
|
def from_string(string: str) -> "IPDescriptor":
|
|
@@ -78,7 +79,7 @@ class IPDescriptor(Descriptor):
|
|
|
78
79
|
address = parts[0]
|
|
79
80
|
port = int(parts[1])
|
|
80
81
|
transport = IPDescriptor.Transport(parts[2])
|
|
81
|
-
return IPDescriptor(address,
|
|
82
|
+
return IPDescriptor(address, transport, port)
|
|
82
83
|
|
|
83
84
|
def __str__(self) -> str:
|
|
84
85
|
return f"{self.address}:{self.port}:{self.Transport(self.transport).value}"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import time
|
|
8
8
|
|
|
9
|
-
import serial
|
|
9
|
+
import serial
|
|
10
10
|
from serial.serialutil import PortNotOpenError
|
|
11
11
|
|
|
12
12
|
from syndesi.tools.backend_api import AdapterBackendStatus, Fragment
|
|
@@ -83,10 +83,10 @@ class SerialPortBackend(AdapterBackend):
|
|
|
83
83
|
baudrate=self.descriptor.baudrate,
|
|
84
84
|
rtscts=self._rts_cts,
|
|
85
85
|
)
|
|
86
|
-
elif not self._port.isOpen():
|
|
86
|
+
elif not self._port.isOpen(): # type: ignore
|
|
87
87
|
self._port.open()
|
|
88
88
|
|
|
89
|
-
if self._port.isOpen():
|
|
89
|
+
if self._port.isOpen(): # type: ignore
|
|
90
90
|
self._logger.info(f"Adapter {self.descriptor} opened")
|
|
91
91
|
self._status = AdapterBackendStatus.CONNECTED
|
|
92
92
|
return True
|
|
@@ -100,7 +100,7 @@ class SerialPortBackend(AdapterBackend):
|
|
|
100
100
|
if hasattr(self, "_port") and self._port is not None:
|
|
101
101
|
# Close and the read thread will die by itself
|
|
102
102
|
self._port.close()
|
|
103
|
-
self._logger.info("Adapter closed
|
|
103
|
+
self._logger.info("Adapter closed")
|
|
104
104
|
return True
|
|
105
105
|
else:
|
|
106
106
|
return False
|
|
@@ -112,17 +112,17 @@ class SerialPortBackend(AdapterBackend):
|
|
|
112
112
|
return False
|
|
113
113
|
else:
|
|
114
114
|
if self._rts_cts: # Experimental
|
|
115
|
-
self._port.setRTS(True) # type
|
|
115
|
+
self._port.setRTS(True) # type: ignore
|
|
116
116
|
# TODO : Implement auto open
|
|
117
117
|
# if self._status == AdapterBackendStatus.DISCONNECTED:
|
|
118
118
|
# self.open()
|
|
119
|
-
write_start = time.time()
|
|
119
|
+
#write_start = time.time()
|
|
120
120
|
try:
|
|
121
121
|
self._port.write(data)
|
|
122
122
|
except (OSError, PortNotOpenError):
|
|
123
123
|
return False
|
|
124
|
-
write_duration = time.time() - write_start
|
|
125
|
-
self._logger.debug(f"Write [{write_duration * 1e3:.3f}ms]: {repr(data)}")
|
|
124
|
+
# write_duration = time.time() - write_start
|
|
125
|
+
#self._logger.debug(f"Write [{write_duration * 1e3:.3f}ms]: {repr(data)}")
|
|
126
126
|
|
|
127
127
|
return True
|
|
128
128
|
|
|
@@ -130,17 +130,23 @@ class SerialPortBackend(AdapterBackend):
|
|
|
130
130
|
t = time.time()
|
|
131
131
|
|
|
132
132
|
if self._port is None:
|
|
133
|
+
self._logger.debug('Port is None -> b""')
|
|
133
134
|
return Fragment(b"", t)
|
|
134
135
|
else:
|
|
135
136
|
try:
|
|
136
137
|
data = self._port.read_all()
|
|
137
138
|
except (OSError, PortNotOpenError):
|
|
138
|
-
|
|
139
|
+
self._logger.debug('Port error -> b""')
|
|
140
|
+
return Fragment(b"", t)
|
|
139
141
|
else:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
else:
|
|
142
|
+
# This is a test, it seems b"" happens sometimes and disconnects the adapter
|
|
143
|
+
if data is not None and data != b"":
|
|
143
144
|
return Fragment(data, t)
|
|
145
|
+
else:
|
|
146
|
+
return Fragment(b"", t)
|
|
147
|
+
#self._logger.debug('Data is none -> b""')
|
|
148
|
+
# else:
|
|
149
|
+
# self._logger.debug(f'{data=}')
|
|
144
150
|
|
|
145
151
|
# def _start_thread(self):
|
|
146
152
|
# """
|
|
@@ -224,7 +230,7 @@ class SerialPortBackend(AdapterBackend):
|
|
|
224
230
|
|
|
225
231
|
def is_opened(self) -> bool:
|
|
226
232
|
if self._port is not None:
|
|
227
|
-
if self._port.isOpen(): # type
|
|
233
|
+
if self._port.isOpen(): # type: ignore
|
|
228
234
|
return True
|
|
229
235
|
|
|
230
236
|
return False
|
|
@@ -10,25 +10,9 @@ import time
|
|
|
10
10
|
from abc import abstractmethod
|
|
11
11
|
from enum import Enum
|
|
12
12
|
|
|
13
|
-
from syndesi.adapters.stop_condition import StopCondition, Termination, Length,
|
|
13
|
+
from syndesi.adapters.stop_condition import StopCondition, Termination, Length, Continuation, Total, StopConditionType
|
|
14
14
|
|
|
15
15
|
from ...tools.backend_api import Fragment
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# class StopConditionType(Enum):
|
|
19
|
-
# TERMINATION = "termination"
|
|
20
|
-
# LENGTH = "length"
|
|
21
|
-
# LAMBDA = "lambda"
|
|
22
|
-
# TIMEOUT = "timeout"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# class StopConditionDescriptorKey(Enum):
|
|
26
|
-
# TYPE = "type"
|
|
27
|
-
# TERMINATION_SEQUENCE = "sequence"
|
|
28
|
-
# LENGTH_N = "N"
|
|
29
|
-
# TIMEOUT_CONTINUATION = "tc"
|
|
30
|
-
# TIMEOUT_TOTAL = "tt"
|
|
31
|
-
|
|
32
16
|
def termination_in_data(termination: bytes, data: bytes) -> tuple[int | None, int]:
|
|
33
17
|
"""
|
|
34
18
|
Return the position (if it exists) and length of the termination (or part of it) inside data
|
|
@@ -51,61 +35,43 @@ def termination_in_data(termination: bytes, data: bytes) -> tuple[int | None, in
|
|
|
51
35
|
|
|
52
36
|
return p, L
|
|
53
37
|
|
|
54
|
-
class StopConditionBackend:
|
|
55
|
-
def __init__(self, stop_condition : StopCondition) -> None:
|
|
56
|
-
self.stop_condition = stop_condition
|
|
57
|
-
|
|
58
|
-
# Termination
|
|
59
|
-
self._sequence_found_length = 0
|
|
60
|
-
|
|
61
|
-
# Length
|
|
62
|
-
self._counter = 0
|
|
63
38
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
class StopConditionBackend:
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
pass
|
|
67
42
|
|
|
68
43
|
def initiate_read(self) -> None:
|
|
69
|
-
|
|
70
|
-
self._sequence_found_length = 0
|
|
71
|
-
# Length
|
|
72
|
-
self._counter = 0
|
|
73
|
-
# Timeout
|
|
74
|
-
self._start_time = time.time()
|
|
75
|
-
self._last_fragment = self._start_time
|
|
76
|
-
|
|
44
|
+
raise NotImplementedError()
|
|
77
45
|
|
|
78
46
|
def evaluate(
|
|
79
47
|
self, raw_fragment: Fragment) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
48
|
+
raise NotImplementedError()
|
|
80
49
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return self._evaluate_timeout(raw_fragment)
|
|
87
|
-
else:
|
|
88
|
-
raise RuntimeError(f"Invalid stop condition : {self.stop_condition}")
|
|
50
|
+
def type(self) -> StopConditionType:
|
|
51
|
+
raise NotImplementedError()
|
|
52
|
+
|
|
53
|
+
def flush_read(self) -> None:
|
|
54
|
+
raise NotImplementedError()
|
|
89
55
|
|
|
90
|
-
|
|
56
|
+
class TerminationBackend(StopConditionBackend):
|
|
57
|
+
def __init__(self, sequence : bytes) -> None:
|
|
58
|
+
super().__init__()
|
|
59
|
+
self._sequence = sequence
|
|
91
60
|
self._sequence_found_length = 0
|
|
92
|
-
self._counter = 0
|
|
93
|
-
self._start_time = None
|
|
94
|
-
self._last_fragment = None
|
|
95
61
|
|
|
96
|
-
def
|
|
97
|
-
|
|
62
|
+
def initiate_read(self) -> None:
|
|
63
|
+
# Termination
|
|
64
|
+
self._sequence_found_length = 0
|
|
98
65
|
|
|
99
|
-
def
|
|
100
|
-
|
|
66
|
+
def flush_read(self) -> None:
|
|
67
|
+
self._sequence_found_length = 0
|
|
101
68
|
|
|
102
|
-
def
|
|
103
|
-
self.stop_condition : Termination
|
|
69
|
+
def evaluate(self, raw_fragment: Fragment) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
104
70
|
if raw_fragment.data is None:
|
|
105
71
|
raise RuntimeError("Trying to evaluate an invalid fragment")
|
|
106
72
|
|
|
107
73
|
position, length = termination_in_data(
|
|
108
|
-
self.
|
|
74
|
+
self._sequence[self._sequence_found_length :], raw_fragment.data
|
|
109
75
|
)
|
|
110
76
|
stop = False
|
|
111
77
|
deferred = Fragment(b"", None)
|
|
@@ -116,7 +82,7 @@ class StopConditionBackend:
|
|
|
116
82
|
else:
|
|
117
83
|
self._sequence_found_length += length
|
|
118
84
|
|
|
119
|
-
if self._sequence_found_length == len(self.
|
|
85
|
+
if self._sequence_found_length == len(self._sequence):
|
|
120
86
|
# The sequence was found entirely
|
|
121
87
|
deferred = raw_fragment[position + length :]
|
|
122
88
|
self._sequence_found_length = 0
|
|
@@ -129,214 +95,104 @@ class StopConditionBackend:
|
|
|
129
95
|
kept = raw_fragment[:position]
|
|
130
96
|
|
|
131
97
|
return stop, kept, deferred, None
|
|
98
|
+
|
|
99
|
+
def type(self) -> StopConditionType:
|
|
100
|
+
return StopConditionType.TERMINATION
|
|
101
|
+
|
|
102
|
+
class LengthBackend(StopConditionBackend):
|
|
103
|
+
def __init__(self, N : int) -> None:
|
|
104
|
+
super().__init__()
|
|
105
|
+
self._N = N
|
|
106
|
+
self._counter = 0
|
|
107
|
+
|
|
108
|
+
def initiate_read(self) -> None:
|
|
109
|
+
# Length
|
|
110
|
+
self._counter = 0
|
|
111
|
+
|
|
112
|
+
def flush_read(self) -> None:
|
|
113
|
+
self._counter = 0
|
|
132
114
|
|
|
133
|
-
def
|
|
134
|
-
self.
|
|
135
|
-
remaining_bytes = self.stop_condition.N - self._counter
|
|
115
|
+
def evaluate(self, raw_fragment: Fragment) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
116
|
+
remaining_bytes = self._N - self._counter
|
|
136
117
|
kept_fragment = raw_fragment[:remaining_bytes]
|
|
137
118
|
deferred_fragment = raw_fragment[remaining_bytes:]
|
|
138
119
|
self._counter += len(kept_fragment.data)
|
|
139
|
-
remaining_bytes = self.
|
|
120
|
+
remaining_bytes = self._N - self._counter
|
|
140
121
|
# TODO : remaining_bytes <= 0 ? Alongside above TODO maybe
|
|
141
122
|
return remaining_bytes == 0, kept_fragment, deferred_fragment, None
|
|
123
|
+
|
|
124
|
+
def type(self) -> StopConditionType:
|
|
125
|
+
return StopConditionType.LENGTH
|
|
142
126
|
|
|
143
|
-
|
|
144
|
-
|
|
127
|
+
class ContinuationBackend(StopConditionBackend):
|
|
128
|
+
def __init__(self, time : float) -> None:
|
|
129
|
+
super().__init__()
|
|
130
|
+
self._continuation = time
|
|
131
|
+
self._last_fragment: float | None = None
|
|
132
|
+
|
|
133
|
+
def initiate_read(self) -> None:
|
|
134
|
+
self._last_fragment = time.time()
|
|
145
135
|
|
|
146
|
-
|
|
147
|
-
|
|
136
|
+
def flush_read(self) -> None:
|
|
137
|
+
self._last_fragment = None
|
|
138
|
+
|
|
139
|
+
def evaluate(self, raw_fragment: Fragment) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
148
140
|
deferred = Fragment(b"", None)
|
|
149
|
-
|
|
141
|
+
kept = raw_fragment
|
|
150
142
|
|
|
151
143
|
if raw_fragment.timestamp is None:
|
|
152
144
|
raise RuntimeError("Cannot evaluate fragment with no timestamp")
|
|
153
145
|
# last_fragment can be none if no data was ever received
|
|
154
|
-
if self.
|
|
155
|
-
continuation_timestamp = self._last_fragment + self.
|
|
156
|
-
stop
|
|
146
|
+
if self._last_fragment is not None:
|
|
147
|
+
continuation_timestamp = self._last_fragment + self._continuation
|
|
148
|
+
stop = continuation_timestamp <= raw_fragment.timestamp
|
|
157
149
|
next_event_timeout = continuation_timestamp
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
raise RuntimeError("Invalid start time")
|
|
162
|
-
total_timestamp = self._start_time + self.stop_condition.total
|
|
163
|
-
stop |= total_timestamp <= raw_fragment.timestamp
|
|
164
|
-
if next_event_timeout is None:
|
|
165
|
-
next_event_timeout = total_timestamp
|
|
166
|
-
else:
|
|
167
|
-
next_event_timeout = min(next_event_timeout, total_timestamp)
|
|
150
|
+
else:
|
|
151
|
+
stop = False
|
|
152
|
+
next_event_timeout = None
|
|
168
153
|
|
|
169
154
|
return stop, kept, deferred, next_event_timeout
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
# @property
|
|
175
|
-
# @abstractmethod
|
|
176
|
-
# def _TYPE(self) -> StopConditionType:
|
|
177
|
-
# raise NotImplementedError
|
|
178
|
-
|
|
179
|
-
# def __init__(self) -> None:
|
|
180
|
-
# """
|
|
181
|
-
# A condition to stop reading from a device
|
|
182
|
-
|
|
183
|
-
# Cannot be used on its own
|
|
184
|
-
# """
|
|
185
|
-
# self._and = None
|
|
186
|
-
# self._or = None
|
|
187
|
-
|
|
188
|
-
# self._eval_time = None
|
|
189
|
-
|
|
190
|
-
# @abstractmethod
|
|
191
|
-
# def initiate_read(self) -> float | None:
|
|
192
|
-
# """
|
|
193
|
-
# Initiate a read sequence.
|
|
194
|
-
|
|
195
|
-
# The maximum time that should be spent in the next byte read
|
|
196
|
-
# is returned
|
|
197
|
-
|
|
198
|
-
# Returns
|
|
199
|
-
# -------
|
|
200
|
-
# timeout : float or None
|
|
201
|
-
# None is there's no timeout
|
|
202
|
-
# """
|
|
203
|
-
# pass
|
|
204
|
-
|
|
205
|
-
# @abstractmethod
|
|
206
|
-
# def evaluate(
|
|
207
|
-
# self, raw_fragment: Fragment, timestamp: float
|
|
208
|
-
# ) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
209
|
-
# """
|
|
210
|
-
# Evaluate the next received byte
|
|
211
|
-
|
|
212
|
-
# Returns
|
|
213
|
-
# -------
|
|
214
|
-
# stop : bool
|
|
215
|
-
# False if read should continue
|
|
216
|
-
# True if read should stop
|
|
217
|
-
# kept_fragment : bytes
|
|
218
|
-
# Part of the fragment kept for future use
|
|
219
|
-
# deferred_fragment : bytes
|
|
220
|
-
# Part of the fragment that was deferred because of a stop condition
|
|
221
|
-
# """
|
|
222
|
-
# pass
|
|
223
|
-
|
|
224
|
-
# @abstractmethod
|
|
225
|
-
# def flush_read(self) -> None:
|
|
226
|
-
# """
|
|
227
|
-
# Flush input buffer and reset stop-condition
|
|
228
|
-
# """
|
|
229
|
-
# pass
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
# class TerminationBackend(StopConditionBackend):
|
|
235
|
-
# # _TYPE = StopConditionType.TERMINATION
|
|
236
|
-
# def flush_read(self) -> None:
|
|
237
|
-
# self._sequence_found_length = 0
|
|
238
|
-
|
|
239
|
-
# def __repr__(self) -> str:
|
|
240
|
-
# return self.__str__()
|
|
241
|
-
|
|
242
|
-
# def __str__(self) -> str:
|
|
243
|
-
# return f"TerminationBackend({repr(self._sequence)})"
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
# # TODO : Add a "allow_longer" parameter ? If more than N data is received, keep it instead of raising an error ?
|
|
247
|
-
# class LengthBackend(StopConditionBackend):
|
|
248
|
-
# # _TYPE = StopConditionType.LENGTH
|
|
249
|
-
|
|
250
155
|
|
|
156
|
+
def type(self) -> StopConditionType:
|
|
157
|
+
return StopConditionType.TIMEOUT
|
|
251
158
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
# def flush_read(self) -> None:
|
|
259
|
-
# self._counter = 0
|
|
159
|
+
class TotalBackend(StopConditionBackend):
|
|
160
|
+
def __init__(self, time : float) -> None:
|
|
161
|
+
super().__init__()
|
|
162
|
+
self._total = time
|
|
163
|
+
self._start_time : float | None = None
|
|
260
164
|
|
|
165
|
+
def initiate_read(self) -> None:
|
|
166
|
+
self._start_time = time.time()
|
|
261
167
|
|
|
262
|
-
|
|
263
|
-
|
|
168
|
+
def flush_read(self) -> None:
|
|
169
|
+
self._start_time = None
|
|
264
170
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
# or total (total communication time exceeds a given value)
|
|
171
|
+
def evaluate(self, raw_fragment: Fragment) -> tuple[bool, Fragment, Fragment, float | None]:
|
|
172
|
+
kept = raw_fragment
|
|
173
|
+
deferred = Fragment(b"", None)
|
|
269
174
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
# continuation : float
|
|
273
|
-
# total : float
|
|
274
|
-
# """
|
|
275
|
-
# super().__init__()
|
|
276
|
-
# self._start_time: float | None = None
|
|
277
|
-
# self._last_fragment: float | None = None
|
|
278
|
-
# self._continuation = continuation
|
|
279
|
-
# self._total = total
|
|
175
|
+
if raw_fragment.timestamp is None:
|
|
176
|
+
raise RuntimeError("Cannot evaluate fragment with no timestamp")
|
|
280
177
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
178
|
+
if self._start_time is None:
|
|
179
|
+
raise RuntimeError("Invalid start time")
|
|
180
|
+
total_timestamp = self._start_time + self._total
|
|
181
|
+
stop = total_timestamp <= raw_fragment.timestamp
|
|
284
182
|
|
|
183
|
+
return stop, kept, deferred, total_timestamp
|
|
285
184
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
# def __init__(self, _lambda : Callable) -> None:
|
|
301
|
-
# super().__init__()
|
|
302
|
-
# self._lambda = _lambda
|
|
303
|
-
|
|
304
|
-
# def initiate_read(self) -> Union[float, None]:
|
|
305
|
-
# return None
|
|
306
|
-
|
|
307
|
-
# def evaluate(self, fragment: bytes) -> Tuple[bool, Union[float, None]]:
|
|
308
|
-
# lambda_return, N = self._lambda(fragment)
|
|
309
|
-
# match lambda_return:
|
|
310
|
-
# case self.LambdaReturn.ERROR:
|
|
311
|
-
# raise RuntimeError(f"Couldn't apply Lambda condition on fragment : {fragment}")
|
|
312
|
-
# case self.LambdaReturn.VALID:
|
|
313
|
-
# return True, fragment, b''
|
|
314
|
-
# case self.LambdaReturn.KEEP_N:
|
|
315
|
-
# return True, fragment[:N], fragment[N:]
|
|
316
|
-
# case self.LambdaReturn.CONTINUE:
|
|
317
|
-
# return False, fragment, b'' # TODO : Check this
|
|
318
|
-
|
|
319
|
-
# def __repr__(self) -> str:
|
|
320
|
-
# return self.__str__()
|
|
321
|
-
|
|
322
|
-
# def __str__(self) -> str:
|
|
323
|
-
# return f'Lambda(...)'
|
|
324
|
-
|
|
325
|
-
# def stop_conditions_to_backends(stop_conditions: list[StopCondition]) -> list["StopConditionBackend"]:
|
|
326
|
-
# output = []
|
|
327
|
-
# for stop_condition in stop_conditions:
|
|
328
|
-
# if isinstance(stop_condition, Termination):
|
|
329
|
-
# output.append(TerminationBackend(
|
|
330
|
-
# sequence=stop_condition.sequence
|
|
331
|
-
# ))
|
|
332
|
-
# elif isinstance(stop_condition, Length):
|
|
333
|
-
# output.append(LengthBackend(
|
|
334
|
-
# N=stop_condition.N
|
|
335
|
-
# ))
|
|
336
|
-
# elif isinstance(stop_condition, TimeoutStopCondition):
|
|
337
|
-
# output.append(TimeoutStopConditionBackend(
|
|
338
|
-
# continuation=stop_condition.continuation,
|
|
339
|
-
# total=stop_condition.total,
|
|
340
|
-
# ))
|
|
341
|
-
|
|
342
|
-
# return output
|
|
185
|
+
def type(self) -> StopConditionType:
|
|
186
|
+
return StopConditionType.TIMEOUT
|
|
187
|
+
|
|
188
|
+
def stop_condition_to_backend(stop_condition : StopCondition) -> StopConditionBackend:
|
|
189
|
+
if isinstance(stop_condition, Termination):
|
|
190
|
+
return TerminationBackend(stop_condition.sequence)
|
|
191
|
+
elif isinstance(stop_condition, Length):
|
|
192
|
+
return LengthBackend(stop_condition.N)
|
|
193
|
+
elif isinstance(stop_condition, Continuation):
|
|
194
|
+
return ContinuationBackend(stop_condition.continuation)
|
|
195
|
+
elif isinstance(stop_condition, Total):
|
|
196
|
+
return TotalBackend(stop_condition.total)
|
|
197
|
+
else:
|
|
198
|
+
raise RuntimeError(f'Invalid stop condition : {stop_condition}')
|
|
@@ -24,14 +24,14 @@ from .descriptors import VisaDescriptor
|
|
|
24
24
|
|
|
25
25
|
# --- Typing-only imports so mypy knows pyvisa symbols without requiring it at runtime
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
|
-
import pyvisa
|
|
28
|
-
from pyvisa.resources import Resource
|
|
27
|
+
import pyvisa # type: ignore
|
|
28
|
+
from pyvisa.resources import Resource # type: ignore
|
|
29
29
|
|
|
30
30
|
# --- Runtime optional import
|
|
31
31
|
try:
|
|
32
32
|
import pyvisa as _pyvisa_runtime
|
|
33
33
|
except Exception:
|
|
34
|
-
_pyvisa_runtime = None
|
|
34
|
+
_pyvisa_runtime = None
|
|
35
35
|
|
|
36
36
|
pyvisa: ModuleType | None = _pyvisa_runtime # type: ignore
|
|
37
37
|
|
|
@@ -105,8 +105,8 @@ class VisaBackend(AdapterBackend):
|
|
|
105
105
|
|
|
106
106
|
if self._status == AdapterBackendStatus.DISCONNECTED:
|
|
107
107
|
# These attributes exist on pyvisa resources
|
|
108
|
-
self._inst.write_termination = ""
|
|
109
|
-
self._inst.read_termination = None
|
|
108
|
+
self._inst.write_termination = ""
|
|
109
|
+
self._inst.read_termination = None
|
|
110
110
|
|
|
111
111
|
self._inst_lock = threading.Lock()
|
|
112
112
|
self._status = AdapterBackendStatus.CONNECTED
|
|
@@ -136,7 +136,7 @@ class VisaBackend(AdapterBackend):
|
|
|
136
136
|
super().write(data)
|
|
137
137
|
with self._inst_lock:
|
|
138
138
|
if self._inst is not None:
|
|
139
|
-
self._inst.write_raw(data)
|
|
139
|
+
self._inst.write_raw(data)
|
|
140
140
|
return True
|
|
141
141
|
|
|
142
142
|
def _socket_read(self) -> Fragment:
|
|
@@ -169,7 +169,7 @@ class VisaBackend(AdapterBackend):
|
|
|
169
169
|
try:
|
|
170
170
|
while True:
|
|
171
171
|
# Read up to an error
|
|
172
|
-
payload += inst.read_bytes(1)
|
|
172
|
+
payload += inst.read_bytes(1)
|
|
173
173
|
inst.timeout = 0
|
|
174
174
|
except pyvisa.VisaIOError:
|
|
175
175
|
# Timeout
|
syndesi/adapters/ip.py
CHANGED
|
@@ -28,9 +28,9 @@ class IP(Adapter):
|
|
|
28
28
|
self,
|
|
29
29
|
address: str,
|
|
30
30
|
port: int | None = None,
|
|
31
|
-
transport: str =
|
|
31
|
+
transport: str = DEFAULT_PROTOCOL.value,
|
|
32
32
|
timeout: Timeout | NumberLike | None | EllipsisType = ...,
|
|
33
|
-
stop_conditions: StopCondition |
|
|
33
|
+
stop_conditions: StopCondition | EllipsisType | list[StopCondition] = ...,
|
|
34
34
|
alias: str = "",
|
|
35
35
|
encoding: str = "utf-8",
|
|
36
36
|
event_callback: Callable[[AdapterSignal], None] | None = None,
|
|
@@ -63,11 +63,7 @@ class IP(Adapter):
|
|
|
63
63
|
descriptor=IPDescriptor(
|
|
64
64
|
address=address,
|
|
65
65
|
port=port,
|
|
66
|
-
transport=(
|
|
67
|
-
IPDescriptor.Transport(transport.upper())
|
|
68
|
-
if transport is not None
|
|
69
|
-
else self.DEFAULT_PROTOCOL
|
|
70
|
-
),
|
|
66
|
+
transport=IPDescriptor.Transport(transport.upper())
|
|
71
67
|
),
|
|
72
68
|
alias=alias,
|
|
73
69
|
timeout=timeout,
|
|
@@ -80,8 +76,8 @@ class IP(Adapter):
|
|
|
80
76
|
)
|
|
81
77
|
self.descriptor: IPDescriptor
|
|
82
78
|
|
|
83
|
-
if self.descriptor.transport is None:
|
|
84
|
-
|
|
79
|
+
#if self.descriptor.transport is not None:
|
|
80
|
+
self._logger.info(f"Setting up {self.descriptor.transport.value} IP adapter")
|
|
85
81
|
|
|
86
82
|
self.set_default_timeout(self._default_timeout())
|
|
87
83
|
|
|
@@ -102,7 +98,7 @@ class IP(Adapter):
|
|
|
102
98
|
if self.descriptor.port is None:
|
|
103
99
|
self.descriptor.port = port
|
|
104
100
|
|
|
105
|
-
def set_default_transport(self, transport : str | IPDescriptor.Transport):
|
|
101
|
+
def set_default_transport(self, transport : str | IPDescriptor.Transport) -> None:
|
|
106
102
|
"""
|
|
107
103
|
Sets the default IP transport protocol
|
|
108
104
|
|
syndesi/adapters/serialport.py
CHANGED
|
@@ -20,7 +20,7 @@ class SerialPort(Adapter):
|
|
|
20
20
|
port: str,
|
|
21
21
|
baudrate: int | None = None,
|
|
22
22
|
timeout: Timeout | NumberLike | None | EllipsisType = ...,
|
|
23
|
-
|
|
23
|
+
stop_conditions: StopCondition | list[StopCondition] | EllipsisType = ...,
|
|
24
24
|
alias: str = "",
|
|
25
25
|
rts_cts: bool = False, # rts_cts experimental
|
|
26
26
|
event_callback: Callable[[AdapterSignal], None] | None = None,
|
|
@@ -39,7 +39,7 @@ class SerialPort(Adapter):
|
|
|
39
39
|
super().__init__(
|
|
40
40
|
descriptor=descriptor,
|
|
41
41
|
timeout=timeout,
|
|
42
|
-
stop_conditions=
|
|
42
|
+
stop_conditions=stop_conditions,
|
|
43
43
|
alias=alias,
|
|
44
44
|
event_callback=event_callback,
|
|
45
45
|
backend_address=backend_address,
|
|
@@ -48,9 +48,8 @@ class SerialPort(Adapter):
|
|
|
48
48
|
self.descriptor: SerialPortDescriptor
|
|
49
49
|
|
|
50
50
|
self._logger.info(
|
|
51
|
-
f"Setting up SerialPort adapter {self.descriptor}, timeout={timeout} and
|
|
51
|
+
f"Setting up SerialPort adapter {self.descriptor}, timeout={timeout} and stop_conditions={self._stop_conditions}"
|
|
52
52
|
)
|
|
53
|
-
# self._port = None
|
|
54
53
|
|
|
55
54
|
self.open()
|
|
56
55
|
|
|
@@ -78,4 +77,4 @@ class SerialPort(Adapter):
|
|
|
78
77
|
|
|
79
78
|
def close(self, force: bool = False) -> None:
|
|
80
79
|
super().close(force)
|
|
81
|
-
self._logger.info("Adapter closed
|
|
80
|
+
self._logger.info("Adapter closed")
|