<[EMAIL PROTECTED]> wrote:
> What I actually want to do is to respond immediately if the expected
> string comes in, but not raise a timeout unless it takes longer than
> the maximum time. So if the device I'm communicating with usually
> responds in a second, but _can_ take up to 20 seconds, I don't want to
> do a sleep(20) then read the port since this will slow everything down
> a lot in an average world. I want to keep checking for the expected
> string, and act upon it as soon as I've got it, only raising a timeout
> if I haven't got it after 20 seconds. I guess to do this using non-
> blocking calls I have to do something like:
> timesofar = 0
> returnstring = port.read(1)
> while len(returnstring)<expectedlength:
> if timesofar >= timeout:
> raise SerialException('Timeout')
> time.sleep(checkportinterval)
> timesofar += checkpointinterval
> returnstring += port.read(1)
>
> This seems rather messy. What I've tried this morning is to produce a
> modified version of uspp with a second optional timeout parameter in
> its read() function. If this is present, the timeout given is sent to
> the port using SetCommTimeouts(). If it's not present, the timeouts
> specified when the port was opened are sent. At first sight, with
> minimal testing on Windows, this seems to be working, and will leave
> my application code a lot cleaner than the non-blocking plus sleep
> approach. Of course I don't know whether my method will work on Linux,
> and there may be problems I haven't found yet.
If it works it works - no problem with that - fight the
dragons as you meet them, one at a time.
I normally put something like this in a read function
(from memory, not tested):
error = 0
k = ''
try:
k = port.read(1)
except IoError:
error = 1
return error,k
For this to work, you have to first unblock the port using fcntl:
def unblock(f):
"""given file f sets unblock flag to true"""
fcntl.fcntl(f.fileno(),f.F_SETFL, os.O_NONBLOCK)
Then you put a call to the read in a loop, and use time.time()
to do your time out, resetting a start_time variable at the start,
and every time you get a char, and using short sleeps
(millisec or so) after unsuccessful calls to make it less of a
busy loop.
The side benefit of this is that once you have received a char,
you can change gears and use a shorter time out to detect the
end of message, in a protocol and state agnostic way. - when
the device has stopped sending chars for a little while it has
finished saying what it wants to say. - so its easy to write a
get_a_reply routine with variable time out, moving the action
from the char to the message level:
start_time=time.time()
s = ''
while time.time()-start_time < time_out:
error,k = get_a_char(port)
if error:
time.sleep(0.001)
continue
s += k # keep the first char
start_time = time.time()
while time.time() - start_time < 0.005: # inter char time out
status,k = get_a_char(port)
if error:
time.sleep(0.001)
continue
s +=k
start_time = time.time()
break
return s # return empty string or what was received
Something similar works for me on Suse Linux - not sure if
fcntl works on windows.
And no it isn't pretty. - but then very little of what I write is...
- Hendrik
--
http://mail.python.org/mailman/listinfo/python-list