@@ -40,18 +40,22 @@ def __init__(self, com, baud=115200, timeout=2.0, **kwargs):
4040 """
4141 super ().__init__ (** kwargs )
4242 self .eol = '\r '
43- # The EOL character means the serial connection must be wrapped in a
44- # TextIOWrapper.
4543 rawSerial = serial .Serial (port = com ,
4644 baudrate = baud , timeout = timeout ,
4745 stopbits = serial .STOPBITS_ONE ,
4846 bytesize = serial .EIGHTBITS , parity = serial .PARITY_NONE ,
4947 xonxoff = 0 )
50- # Use a buffer size of 1 in the BufferedRWPair. Without this,
51- # either 8192 chars need to be read before data is passed upwards,
52- # or he buffer needs to be flushed, incurring a serial timeout.
53- self .connection = io .TextIOWrapper (io .BufferedRWPair (rawSerial , rawSerial , 1 ))
54- # Last received wheel position.
48+ # The Thorlabs controller serial implementation is strange.
49+ # Generally, it uses \r as EOL, but error messages use \n.
50+ # A readline after sending a 'pos?\r' command always times out,
51+ # but returns a string terminated by a newline.
52+ # We use TextIOWrapper with newline=None to perform EOL translation
53+ # inbound, but must explicitly append \r to outgoing commands.
54+ # The TextIOWrapper also deals with conversion between unicode
55+ # and bytes.
56+ self .connection = io .TextIOWrapper (rawSerial , newline = None ,
57+ line_buffering = True , # flush on write
58+ write_through = True ) # write out immediately
5559
5660 def initialize (self ):
5761 pass
@@ -62,45 +66,30 @@ def _on_shutdown(self):
6266 def set_position (self , n ):
6367 """Public method to move to position n."""
6468 command = 'pos=%d' % n
65- self .connection .write (command + self .eol )
66- # The serial connection will timeout until new position is reached.
67- # Count timeouts to detect failure to return to responsive state.
68- count = 0
69- maxCount = 10
70- while True :
71- response = self .connection .readline ().strip ()
72- if response == command :
73- # Command echo received - reset counter.
74- count = 0
75- elif response == '>' :
76- # Command input caret received - connection is responsive again.
77- break
78- else :
79- # Increment counter and test against maxCount.
80- count += 1
81- if count > maxCount :
82- self .connection .flush ()
83- raise Exception ('fw102c: Communication error.' )
84- time .sleep (0.1 )
69+ self ._send_command (command )
8570
8671 def get_position (self ):
8772 """Public method to query the current position"""
8873 return int (self ._send_command ('pos?' ))
8974
75+ def _readline (self ):
76+ """A custom _readline to overcome limitations of the serial implementation."""
77+ result = [None ]
78+ while result [- 1 ] not in ('\n ' , '' ):
79+ result .append (self .connection .read ())
80+ return '' .join (result [1 :])
81+
9082 def _send_command (self , command ):
9183 """Send a command and return any result."""
9284 result = None
9385 self .connection .write (command + self .eol )
9486 response = 'dummy'
9587 while response not in [command , '' ]:
9688 # Read until we receive the command echo.
97- response = self .connection . readline ().strip ()
89+ response = self ._readline ().strip ('> \n \r ' )
9890 if command .endswith ('?' ):
9991 # Last response was the command. Next is result.
100- result = self .connection .readline ().strip ()
101- while response not in ['>' , '' ]:
102- # Read until we receive the input caret.
103- response = self .connection .readline ().strip ()
92+ result = self ._readline ().strip ()
10493 return result
10594
10695
0 commit comments