88import os
99from errno import EAGAIN , EINTR , EINVAL , ENOTTY , EWOULDBLOCK
1010from fcntl import ioctl
11- from select import select
1211from struct import pack
1312from types import TracebackType
1413from typing import Optional , Type , TypedDict
1514
1615from .errors import SerialReadError , SerialWriteError
17- from .handlers import ReadTimeoutHandler
1816from .utilities import no_op
1917
2018# **************************************************************************************
@@ -156,61 +154,19 @@ def read(self, size: int = 1) -> bytes:
156154 if size == 0 :
157155 return b""
158156
159- # Initialize a bytearray to accumulate incoming data:
160- read : bytearray = bytearray ()
161-
162- # Convert timeout from seconds to milliseconds, as required by ReadTimeoutHandler:
163- timer = ReadTimeoutHandler (timeout = self ._timeout * 1000 )
164-
165- timer .start ()
166-
167- # Continue reading until we have collected the requested number of bytes
168- # or until the overall timeout period has elapsed.
169- while len (read ) < size :
170- # Check if the timeout has expired:
171- if timer .has_expired ():
172- raise SerialReadError (
173- f"Read timeout after { self ._timeout } s, got { len (read )} /{ size } bytes"
174- )
175-
176- # Wait for readability with the remaining time budget
177- remaining = timer .remaining ()
157+ try :
158+ # Blocking read call to read from the USBTMC device:
159+ data : bytes = os .read (self ._fd , size )
160+ except OSError as e :
161+ raise SerialReadError (f"Reading from USBTMC device failed: { e } " ) from e
178162
179- r , _ , _ = select (
180- [self ._fd ],
181- [],
182- [],
183- max (0.0 , min (self ._timeout , (remaining or 0.0 ) / 1000.0 )),
163+ # If the port was ready but returned no data, treat it as a disconnection.
164+ if not data :
165+ raise SerialReadError (
166+ "The device reported readiness to read but returned no data."
184167 )
185168
186- if not r :
187- raise SerialReadError (
188- f"Read timeout after { self ._timeout } s (no data ready)"
189- )
190-
191- try :
192- chunk : bytes = os .read (self ._fd , size - len (read ))
193- except OSError as e :
194- # Retry on non-fatal errors and propagate others upwards:
195- if e .errno in (
196- EAGAIN ,
197- EWOULDBLOCK ,
198- EINTR ,
199- ):
200- continue
201- raise SerialReadError (f"Reading from USBTMC device failed: { e } " ) from e
202-
203- # If the port was ready but returned no data, treat it as a disconnection.
204- if not chunk :
205- raise SerialReadError (
206- "The device reported readiness to read but returned no data."
207- )
208-
209- # If the chunk read was successful, append it to the data:
210- read .extend (chunk )
211-
212- # Finally, return the accumulated data:
213- return bytes (read )
169+ return data
214170
215171 def readline (self , eol : bytes = b"\n " , maximum_bytes : int = - 1 ) -> bytes :
216172 """
@@ -231,65 +187,36 @@ def readline(self, eol: bytes = b"\n", maximum_bytes: int = -1) -> bytes:
231187 # Initialize a bytearray to accumulate incoming data:
232188 read : bytearray = bytearray ()
233189
234- # Convert timeout from seconds to milliseconds, as required by ReadTimeoutHandler:
235- timer = ReadTimeoutHandler (timeout = self ._timeout * 1000 )
236-
237- timer .start ()
238-
239190 # Determine how many bytes to read in this chunk:
240191 chunk_size = 1024
241192
242- # Continue reading until we have collected the requested number of bytes
243- # or until the overall timeout period has elapsed:
244193 while True :
245194 # Check if we have read enough bytes to satisfy max_bytes:
246195 if maximum_bytes > 0 and len (read ) >= maximum_bytes :
247- break
196+ # We have reached the maximum allowed bytes; return what we have:
197+ return bytes (read )
248198
249- # Check if the timeout has expired:
250- if timer .has_expired ():
251- raise SerialReadError (
252- f"Read timeout after { self ._timeout } s, got { len (read )} bytes"
253- )
254-
255- # Wait for readability with the remaining time budget:
256- remaining = timer .remaining ()
257-
258- r , _ , _ = select (
259- [self ._fd ],
260- [],
261- [],
262- max (0.0 , min (self ._timeout , (remaining or 0.0 ) / 1000.0 )),
263- )
199+ # If maximum_bytes is set, do not read past it:
200+ if maximum_bytes > 0 :
201+ remaining = maximum_bytes - len (read )
264202
265- # If no file descriptors are ready, return partial data if any is available:
266- if not r :
267- if len (read ) > 0 :
203+ # If the remaining bytes is less than or equal to zero, return what we have:
204+ if remaining <= 0 :
268205 return bytes (read )
269206
270- raise SerialReadError (
271- f"Read timeout after { self ._timeout } s (no data ready)"
272- )
273-
274- # Limit read size if maximum_bytes is used:
275- if maximum_bytes > 0 :
276- chunk_size = min (chunk_size , maximum_bytes - len (read ))
207+ # Adjust chunk size to not exceed maximum_bytes:
208+ chunk_size = min (1024 , remaining )
277209
278210 try :
211+ # Blocking read call to read from the USBTMC device:
279212 chunk : bytes = os .read (self ._fd , chunk_size )
280213 except OSError as e :
281- # Retry on non-fatal errors and propagate others upwards:
282- if e .errno in (
283- EAGAIN ,
284- EWOULDBLOCK ,
285- EINTR ,
286- ):
287- continue
288- raise SerialReadError (f"Reading from USBTMC device failed: { e } " )
214+ raise SerialReadError (f"Reading from USBTMC device failed: { e } " ) from e
289215
290- # If the port was ready but returned no data, return partial data if any :
216+ # If the port returned no data at all :
291217 if not chunk :
292218 if len (read ) > 0 :
219+ # Return whatever we have so far.
293220 return bytes (read )
294221 raise SerialReadError (
295222 "The device reported readiness to read but returned no data."
@@ -303,9 +230,6 @@ def readline(self, eol: bytes = b"\n", maximum_bytes: int = -1) -> bytes:
303230 index = read .index (eol ) + len (eol )
304231 return bytes (read [:index ])
305232
306- # Finally, return the accumulated data:
307- return bytes (read )
308-
309233 def write (self , data : bytes ) -> int :
310234 """
311235 Write all of `data` to the USBTMC device, retrying on transient errors.
@@ -338,14 +262,8 @@ def write(self, data: bytes) -> int:
338262 try :
339263 n = os .write (self ._fd , data [written :])
340264 except OSError as e :
341- # Retry on transient POSIX errors:
265+ # Retry on transient POSIX errors for a blocking descriptor :
342266 if e .errno in (EAGAIN , EWOULDBLOCK , EINTR ):
343- _ , w , _ = select ([], [self ._fd ], [], self ._timeout )
344-
345- if not w :
346- raise SerialWriteError (
347- f"Write timeout after { self ._timeout } s (not writable)"
348- )
349267 continue
350268 raise SerialWriteError (f"Writing to USBTMC device failed: { e } " ) from e
351269
0 commit comments