<[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

Reply via email to