Re: Async serial communication/threads sharing data

2009-04-11 Thread Jean-Paul Calderone

On Wed, 25 Mar 2009 22:23:25 -0700, John Nagle na...@animats.com wrote:

Jean-Paul Calderone wrote:

On Tue, 24 Mar 2009 22:20:49 -0700, John Nagle na...@animats.com wrote:

Jean-Paul Calderone wrote:
On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood n...@craig-wood.com 
wrote:

Jean-Paul Calderone exar...@divmod.com wrote:
[snip]

   After bringing in all the heavy machinery of Twisted,
you're still polling at 10Hz.  That's disappointing.


Hmm, no?  There's no polling in the latest version of the code I saw.

Jean-Paul


if too_full:
   reactor.callLater(0.1, self.throttle)



Hi John,

You're looking at a different version of the code than what I was talking
about.  After discussing things with Nick, we came up with a version which
includes no polling.  See Nick's message of March 23, at around 1:30 PM for
the code I was referring to - a version of the app which does no polling.

Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-27 Thread JanC
Jean-Paul Calderone wrote:

  These days, serial ports are on the way out, I think.

I don't see generic USB and bluetooth serial devices disappear that fast...

E.g. AFAIK (almost?) all GPS receivers have to be accessed as serial
devices (mine even looks like a generic USB-to-serial device to the kernel).


-- 
JanC
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-25 Thread Jean-Paul Calderone

On Tue, 24 Mar 2009 22:20:49 -0700, John Nagle na...@animats.com wrote:

Jean-Paul Calderone wrote:
On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood n...@craig-wood.com 
wrote:

Jean-Paul Calderone exar...@divmod.com wrote:
[snip]

   After bringing in all the heavy machinery of Twisted,
you're still polling at 10Hz.  That's disappointing.



Hmm, no?  There's no polling in the latest version of the code I saw.

Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-25 Thread John Nagle

Jean-Paul Calderone wrote:

On Tue, 24 Mar 2009 22:20:49 -0700, John Nagle na...@animats.com wrote:

Jean-Paul Calderone wrote:
On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood 
n...@craig-wood.com wrote:

Jean-Paul Calderone exar...@divmod.com wrote:
[snip]

   After bringing in all the heavy machinery of Twisted,
you're still polling at 10Hz.  That's disappointing.



Hmm, no?  There's no polling in the latest version of the code I saw.

Jean-Paul


if too_full:
   reactor.callLater(0.1, self.throttle)

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-24 Thread John Nagle

Hendrik van Rooyen wrote:

Nick Craig-Wood ni...g-wood.com wrote:


I wrote a serial port to TCP proxy (with logging) with twisted.  The
problem I had was that twisted serial ports didn't seem to have any
back pressure.  


Not sure if this is Twisted's fault - 
do python sockets have 
automatic back pressure?

Do Linux sockets have back pressure?


   Yes, and yes.

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-24 Thread John Nagle

Jean-Paul Calderone wrote:
On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood 
n...@craig-wood.com wrote:

Jean-Paul Calderone exar...@divmod.com wrote:
[snip]

   After bringing in all the heavy machinery of Twisted,
you're still polling at 10Hz.  That's disappointing.

John Nagle
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-23 Thread Hendrik van Rooyen
Nick Craig-Wood ni...g-wood.com wrote:

 
 I wrote a serial port to TCP proxy (with logging) with twisted.  The
 problem I had was that twisted serial ports didn't seem to have any
 back pressure.  By that I mean I could pump data into a 9600 baud
 serial port at 10 Mbit/s.  Twisted would then buffer the data for me
 using 10s or 100s or Megabytes of RAM.  No data would be lost, but
 there would be hours of latency and my program would use up all my RAM
 and explode.
 
 What I wanted to happen was for twisted to stop taking the data when
 the serial port buffer was full and to only take the data at 9600
 baud.
 
 I never did solve that problem :-(
 

Not sure if this is Twisted's fault - 
do python sockets have 
automatic back pressure?
Do Linux sockets have back pressure?

- Hendrik

--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-23 Thread Nick Craig-Wood
Jean-Paul Calderone exar...@divmod.com wrote:
  On Sun, 22 Mar 2009 12:30:04 -0500, Nick Craig-Wood n...@craig-wood.com 
 wrote:
 I wrote a serial port to TCP proxy (with logging) with twisted.  The
 problem I had was that twisted serial ports didn't seem to have any
 back pressure.  By that I mean I could pump data into a 9600 baud
 serial port at 10 Mbit/s.  Twisted would then buffer the data for me
 using 10s or 100s or Megabytes of RAM.  No data would be lost, but
 there would be hours of latency and my program would use up all my RAM
 and explode.
 
 What I wanted to happen was for twisted to stop taking the data when
 the serial port buffer was full and to only take the data at 9600
 baud.
 
  This is what Twisted's producers and consumers let you do.  There's a
  document covering these features:
 
  http://twistedmatrix.com/projects/core/documentation/howto/producers.html
 
  In the case of a TCP to serial forwarder, you don't actually have to
  implement either a producer or a consumer, since both the TCP connection
  and the serial connection are already both producers and consumers.  All
  you need to do is hook them up to each other so that when the send buffer
  of one fills up, the other one gets paused, and when the buffer is empty
  again, it gets resumed.

I eventually came up with this which seems to work, but I'm not sure
it is the best way of doing it as it had to mess about with the
twisted internals to get the number of bytes in the serial port
output buffer.

class SerialPort(protocol.Protocol):
Create a serial port connection and pass data from it to a known list of 
TCP ports.

def __init__(self, port, reactor, baudrate, log_name=None):
self.tcp_ports = []
self.serial = serialport.SerialPort(self, reactor, port, baudrate, 
rtscts=0)
self.log = None
if log_name is not None:
self.log = file('%s-0' % log_name, 'w')

def write(self, data):
Write data to the serial port.
self.serial.write(data)
if self.log:
self.log.write(data)
self.throttle()

def throttle(self):

Pause the inputs if there is too much data in the output buffer

bytes_in_buffer = len(self.serial.dataBuffer) + self.serial._tempDataLen
too_full = bytes_in_buffer  1024
for tcp_port in self.tcp_ports:
if too_full:
tcp_port.transport.pauseProducing()
else:
tcp_port.transport.resumeProducing()
if too_full:
reactor.callLater(0.1, self.throttle)

-- 
Nick Craig-Wood n...@craig-wood.com -- http://www.craig-wood.com/nick
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-23 Thread Jean-Paul Calderone

On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood n...@craig-wood.com wrote:

Jean-Paul Calderone exar...@divmod.com wrote:
[snip]


 In the case of a TCP to serial forwarder, you don't actually have to
 implement either a producer or a consumer, since both the TCP connection
 and the serial connection are already both producers and consumers.  All
 you need to do is hook them up to each other so that when the send buffer
 of one fills up, the other one gets paused, and when the buffer is empty
 again, it gets resumed.


I eventually came up with this which seems to work, but I'm not sure
it is the best way of doing it as it had to mess about with the
twisted internals to get the number of bytes in the serial port
output buffer.


This is sort of on the right track.  Here's how to do it without
touching implementation details:



class SerialPort(protocol.Protocol):
   Create a serial port connection and pass data from it to a known list of TCP 
ports.

   def __init__(self, port, reactor, baudrate, log_name=None):
   self.tcp_ports = []
   self.serial = serialport.SerialPort(self, reactor, port, baudrate, 
rtscts=0)


Here, register this object to receive buffer full and not-full events from
the serial port:

   self.serial.registerProducer(self, True)

And an attribute to keep track of our state:

   self.paused = False


   self.log = None
   if log_name is not None:
   self.log = file('%s-0' % log_name, 'w')



I'm not exactly sure where `self.tcp_ports´ gets populated, so I'll make a 
method to do it:

   def addPort(self, port):
   if self.paused:
   port.transport.pauseProducing()
   self.tcp_ports.append(port)

Now a method to handle serial port buffer full events:

   def pauseProducing(self):
   self.paused = True
   for port in self.tcp_ports:
   port.transport.pauseProducing()

And a method to handle buffer no longer full events:

   def resumeProducing(self):
   self.paused = False
   for port in self.tcp_ports:
   port.transport.resumeProducing()

With these, you can get rid of `throttle´ entirely.  


   def write(self, data):
   Write data to the serial port.
   self.serial.write(data)
   if self.log:
   self.log.write(data)
   self.throttle()

   def throttle(self):
   
   Pause the inputs if there is too much data in the output buffer
   
   bytes_in_buffer = len(self.serial.dataBuffer) +  self.serial._tempDataLen
   too_full = bytes_in_buffer  1024
   for tcp_port in self.tcp_ports:
   if too_full:
   tcp_port.transport.pauseProducing()
   else:
   tcp_port.transport.resumeProducing()
   if too_full:
   reactor.callLater(0.1, self.throttle)



Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-23 Thread Nick Craig-Wood
Jean-Paul Calderone exar...@divmod.com wrote:
  On Mon, 23 Mar 2009 05:30:04 -0500, Nick Craig-Wood n...@craig-wood.com 
 wrote:
 Jean-Paul Calderone exar...@divmod.com wrote:
  [snip]
 
   In the case of a TCP to serial forwarder, you don't actually have to
   implement either a producer or a consumer, since both the TCP connection
   and the serial connection are already both producers and consumers.  All
   you need to do is hook them up to each other so that when the send buffer
   of one fills up, the other one gets paused, and when the buffer is empty
   again, it gets resumed.
 
 I eventually came up with this which seems to work, but I'm not sure
 it is the best way of doing it as it had to mess about with the
 twisted internals to get the number of bytes in the serial port
 output buffer.
 
  This is sort of on the right track.  Here's how to do it without
  touching implementation details:

Thank you for that!

See below for the complete prog with your suggested modifications.

That seems to solve the problem - I can see the writer pausing and
unpausing at the serial port rate.

  write 16446
  write 6430
  pause producing
  resume producing
  write 65536
  write 56724
  pause producing
  resume producing
  write 65536
  write 65536
  pause producing

It has exposed a problem with the sender not throttling properly now,
but I guess that is progress!

Thanks for your help

Here is the complete program FYI with your suggested mods.

#!/usr/bin/python
Transfer data between a serial port and one (or more) TCP
connections.
options:
-h, --help:this help
-p, --port=PORT: port, a number, default = 0 or a device name
-b, --baud=BAUD: baudrate, default 115200
-t, --tcp=PORT: TCP port number, default 1234
-l, --log: log data streams to 'snifter-0', 'snifter-1'
-L, --log_name=NAME: log data streams to 'NAME-0', 'NAME-1'


import sys
import getopt
from twisted.internet import reactor, protocol, serialport
from zope.interface import implements
from twisted.internet import protocol, interfaces

# FIXME set serial buffer size? SEND_LIMIT

class SerialPort(protocol.Protocol):
Create a serial port connection and pass data from it to a
known list of
TCP ports.

def __init__(self, port, reactor, baudrate, log_name=None):
self.tcp_ports = []
self.serial = serialport.SerialPort(self, reactor, port,
baudrate, rtscts=0)
self.serial.registerProducer(self, True)
self.paused = False
self.log = None
if log_name is not None:
self.log = file('%s-0' % log_name, 'w')

def add_tcp(self, tcp_port):
Add a TCPPort to those receiving serial data.
if self.paused:
tcp_port.transport.pauseProducing()
self.tcp_ports.append(tcp_port)

def del_tcp(self, tcp_port):
Remove a TCPPort from the those receiving serial data.
self.tcp_ports.remove(tcp_port)

def write(self, data):
Write data to the serial port.
self.serial.write(data)
if self.log:
self.log.write(data)

def pauseProducing(self):
Pause producing event
print pause producing
self.paused = True
for port in self.tcp_ports:
port.transport.pauseProducing()

def resumeProducing(self):
Resume producing event
print resume producing
self.paused = False
for port in self.tcp_ports:
port.transport.resumeProducing()

def stopProducing(self):
Stop producing event
print stop producing

def dataReceived(self, data):
Pass any received data to the list of TCPPorts.
for tcp_port in self.tcp_ports:
tcp_port.write(data)

class TCPPort(protocol.Protocol):
Create a TCP server connection and pass data from it to the
serial port.

def __init__(self, serial, log_name, index):
Add this TCPPort to the SerialPort.
self.serial = serial
self.serial.add_tcp(self)
self.log = None
if log_name is not None:
self.log = file('%s-%d' % (log_name, index+1), 'w')

def __del__(self):
Remove this TCPPort from the SerialPort.
self.serial.del_tcp(self)

def dataReceived(self, data):
Pass received data to the SerialPort.
print write, len(data)
self.serial.write(data)

def write(self, data):
Write data to the TCP port.
self.transport.write(data)
if self.log is not None:
self.log.write(data)

class TCPPortFactory(protocol.ServerFactory):
Factory to create TCPPort protocol instances, an instanced
SerialPort must be passed in.

def __init__(self, serial, log_name=None):
self.serial = serial
self.log_name = log_name
self.index = 0

def buildProtocol(self, addr):
Build a TCPPort, passing in the instanced SerialPort.
p = TCPPort(self.serial, self.log_name, self.index)
 

Re: Async serial communication/threads sharing data

2009-03-22 Thread Hendrik van Rooyen
Nick Timkovich prom@gmail.com wrote:


 I've been working on a program that will talk to an embedded device
 over the serial port, using some basic binary communications with
 messages 4-10 bytes long or so.  Most of the nuts and bolts problems
 I've been able to solve, and have learned a little about the threading
 library to avoid blocking all action while waiting for responses
 (which can take 50 ms to 10 s).  Ultimately, this program will test
 the device on the COM port by sending it messages and collecting
 responses for 10k-100k cycles; a cycle being:
  1. tell it to switch a relay,
  2. get it's response from the event,
  3. ask it for some measurements,
  4. get measurements,
  5. repeat.
 Later I would like to develop a GUI as well, but not a big issue now
 (another reason to use threads? not sure).
 
 The overall structure of what I should do is not very apparent to me
 on how to efficiently deal with the communications.  Have the main
 loop handle the overall timing of how often to run the test cycle,
 then have a thread deal with all the communications, and within that
 another thread that just receives data?  My main issue is with how to
 exchange data between different threads; can I just do something like
 have a global list of messages, appending, modifying, and removing as
 needed?  Does the threading.Lock object just prevent every other
 thread from running, or is it bound somehow to a specific object (like
 my list)?

What I have been doing for similar stuff is to modularize using processes
and pipes instead of queues.
This allows you to have the communications in one process, in which
you hide all the protocol issues, and allows you to deal with the resulting
data at a slightly higher level of abstraction.
Such a structure also makes it easier to have different user interfaces -
command line or GUI, it does not matter as the commands and responses
to the comms module can be standardised via an input and output
pipe to and from the comms module.

HTH
- Hendrik

--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-22 Thread Nick Timkovich
On Mar 21, 9:19 pm, Jean-Paul Calderone exar...@divmod.com wrote:
 On Sat, 21 Mar 2009 13:52:21 -0700 (PDT), Nick Timkovich 
 prometheus...@gmail.com wrote:
 I've been working on a program that will talk to an embedded device
 over the serial port, using some basic binary communications with
 messages 4-10 bytes long or so.  Most of the nuts and bolts problems
 I've been able to solve, and have learned a little about the threading
 library to avoid blocking all action while waiting for responses
 (which can take 50 ms to 10 s).  Ultimately, this program will test
 the device on the COM port by sending it messages and collecting
 responses for 10k-100k cycles; a cycle being:
  1. tell it to switch a relay,
  2. get it's response from the event,
  3. ask it for some measurements,
  4. get measurements,
  5. repeat.
 Later I would like to develop a GUI as well, but not a big issue now
 (another reason to use threads? not sure).

 Twisted includes serial port support and will let you integrate with a
 GUI toolkit.  Since Twisted encourages you to write programs which deal
 with things asynchronously in a single thread, if you use it, your
 concerns about data exchange, locking, and timing should be addressed
 as a simple consequence of your overall program structure.

 Jean-Paul

I've looked at Twisted a little bit because of some searches on serial
port comm turning up advice for it.  However, there seems to be no/
minimal documentation for the serial portions, like they are some old
relic that nobody uses from this seemingly massive package.  Do you
have any examples or somewhere in particular you could point me?

Thanks for the responses,
Nick
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-22 Thread Jean-Paul Calderone

On Sun, 22 Mar 2009 03:13:36 -0700 (PDT), Nick Timkovich 
prometheus...@gmail.com wrote:

On Mar 21, 9:19 pm, Jean-Paul Calderone exar...@divmod.com wrote:

On Sat, 21 Mar 2009 13:52:21 -0700 (PDT), Nick Timkovich 
prometheus...@gmail.com wrote:
I've been working on a program that will talk to an embedded device
over the serial port, using some basic binary communications with
messages 4-10 bytes long or so.  Most of the nuts and bolts problems
I've been able to solve, and have learned a little about the threading
library to avoid blocking all action while waiting for responses
(which can take 50 ms to 10 s).  Ultimately, this program will test
the device on the COM port by sending it messages and collecting
responses for 10k-100k cycles; a cycle being:
 1. tell it to switch a relay,
 2. get it's response from the event,
 3. ask it for some measurements,
 4. get measurements,
 5. repeat.
Later I would like to develop a GUI as well, but not a big issue now
(another reason to use threads? not sure).

Twisted includes serial port support and will let you integrate with a
GUI toolkit.  Since Twisted encourages you to write programs which deal
with things asynchronously in a single thread, if you use it, your
concerns about data exchange, locking, and timing should be addressed
as a simple consequence of your overall program structure.

Jean-Paul


I've looked at Twisted a little bit because of some searches on serial
port comm turning up advice for it.  However, there seems to be no/
minimal documentation for the serial portions, like they are some old
relic that nobody uses from this seemingly massive package.  Do you
have any examples or somewhere in particular you could point me?


It's true that the serial port support in Twisted isn't the most used
feature. :)  These days, serial ports are on the way out, I think.  That
said, much of the way a serial port is used in Twisted is the same as the
way a TCP connection is used.  This means that the Twisted documentation
for TCP connections is largely applicable to using serial ports.  The only
major difference is how you set up the connection.  You can see examples
of using the serial port support here (one of them seems to suggest that
it won't work on Windows, but I think this is a mistake):

 http://twistedmatrix.com/projects/core/documentation/examples/gpsfix.py
 http://twistedmatrix.com/projects/core/documentation/examples/mouse.py

The 2nd to last line of each example shows how to connect to the serial
port.  These basic documents describe how to implement a protocol.  Though
in the context of TCP, the protocol implementation ideas apply to working
with serial ports as well:

 http://twistedmatrix.com/projects/core/documentation/howto/servers.html
 http://twistedmatrix.com/projects/core/documentation/howto/clients.html

You can ignore the parts about factories, since they're not used with serial
ports.

Hope this helps,

Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-22 Thread Nick Craig-Wood
Jean-Paul Calderone exar...@divmod.com wrote:
  It's true that the serial port support in Twisted isn't the most used
  feature. :)  These days, serial ports are on the way out, I think.  That
  said, much of the way a serial port is used in Twisted is the same as the
  way a TCP connection is used.  This means that the Twisted documentation
  for TCP connections is largely applicable to using serial ports.  The only
  major difference is how you set up the connection.  You can see examples
  of using the serial port support here (one of them seems to suggest that
  it won't work on Windows, but I think this is a mistake):
 
http://twistedmatrix.com/projects/core/documentation/examples/gpsfix.py
http://twistedmatrix.com/projects/core/documentation/examples/mouse.py
 
  The 2nd to last line of each example shows how to connect to the serial
  port.  These basic documents describe how to implement a protocol.  Though
  in the context of TCP, the protocol implementation ideas apply to working
  with serial ports as well:
 
http://twistedmatrix.com/projects/core/documentation/howto/servers.html
http://twistedmatrix.com/projects/core/documentation/howto/clients.html
 
  You can ignore the parts about factories, since they're not used with serial
  ports.

I wrote a serial port to TCP proxy (with logging) with twisted.  The
problem I had was that twisted serial ports didn't seem to have any
back pressure.  By that I mean I could pump data into a 9600 baud
serial port at 10 Mbit/s.  Twisted would then buffer the data for me
using 10s or 100s or Megabytes of RAM.  No data would be lost, but
there would be hours of latency and my program would use up all my RAM
and explode.

What I wanted to happen was for twisted to stop taking the data when
the serial port buffer was full and to only take the data at 9600
baud.

I never did solve that problem :-(

-- 
Nick Craig-Wood n...@craig-wood.com -- http://www.craig-wood.com/nick
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-22 Thread Jean-Paul Calderone

On Sun, 22 Mar 2009 12:30:04 -0500, Nick Craig-Wood n...@craig-wood.com wrote:

[snip]

I wrote a serial port to TCP proxy (with logging) with twisted.  The
problem I had was that twisted serial ports didn't seem to have any
back pressure.  By that I mean I could pump data into a 9600 baud
serial port at 10 Mbit/s.  Twisted would then buffer the data for me
using 10s or 100s or Megabytes of RAM.  No data would be lost, but
there would be hours of latency and my program would use up all my RAM
and explode.

What I wanted to happen was for twisted to stop taking the data when
the serial port buffer was full and to only take the data at 9600
baud.

I never did solve that problem :-(



This is what Twisted's producers and consumers let you do.  There's a
document covering these features:

http://twistedmatrix.com/projects/core/documentation/howto/producers.html

In the case of a TCP to serial forwarder, you don't actually have to
implement either a producer or a consumer, since both the TCP connection
and the serial connection are already both producers and consumers.  All
you need to do is hook them up to each other so that when the send buffer
of one fills up, the other one gets paused, and when the buffer is empty
again, it gets resumed.

Hope this helps!

Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-21 Thread Paul Rubin
Nick Timkovich prometheus...@gmail.com writes:
 My main issue is with how to
 exchange data between different threads; can I just do something like
 have a global list of messages, appending, modifying, and removing as
 needed?  Does the threading.Lock object just prevent every other
 thread from running, or is it bound somehow to a specific object (like
 my list)?

The favored approach to this is to use the Queue module, which gives a
thread-safe double ended queue.  This is cleaner than messing with
lower level synchronization primitives like Lock.  You use Queues as
communications channels between threads.
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-21 Thread Scott David Daniels

Nick Timkovich wrote:

I've been working on a program that will talk to an embedded device
over the serial port, using some basic binary communications with
messages 4-10 bytes long or so...  Ultimately, this program ...
[send] messages and collecting responses for 10k-100k cycles ...


Here's a simple structure:
One thread talks to the device, it passes commands to the device,
collects the response, and (when a full response is collected),
sends the response back.  Queues have all the locking needed, so
most of us just use Queues to communicate between threads (as
Paul Rubin has suggested).  For example:

   def thread_body(command_queue, result_queue):
   for command, reps in iter(command_queue.get, None):
   result = []
   try:
   for n in range(reps):
   device.send(command)
   result.append(device.read(reply_length(command))
   finally:
   result_queue.put(result)

Then you just do something like:
import queue
commands = queue.Queue()
replies = queue.Queue()
start_some_thread(thread_body, commands, replies)
...
some loop:
commands.put(fetch_voltage, 50)
print(replies.get())
...
commands.put(None)

Here the device-talker works away while it can, waiting
until it has a command, and waiting for all replies or
some failure to get back to the caller.
The caller may either block for thread replies, or use
replies.get(timeout=7.25) or replies.get(block=False)
to wait (or not) and get a queue.Empty exception to signal
no data yet.

 Does the threading.Lock object just prevent every other thread from
 running, or is it bound somehow to a specific object (like my list)?

A Lock instance can be used to protect as many resources as you like;
it really only decides who gets the lock; you decide what you only do
while holding the lock (the other threads are running, except those
waiting for the lock).

--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list


Re: Async serial communication/threads sharing data

2009-03-21 Thread Jean-Paul Calderone

On Sat, 21 Mar 2009 13:52:21 -0700 (PDT), Nick Timkovich 
prometheus...@gmail.com wrote:

I've been working on a program that will talk to an embedded device
over the serial port, using some basic binary communications with
messages 4-10 bytes long or so.  Most of the nuts and bolts problems
I've been able to solve, and have learned a little about the threading
library to avoid blocking all action while waiting for responses
(which can take 50 ms to 10 s).  Ultimately, this program will test
the device on the COM port by sending it messages and collecting
responses for 10k-100k cycles; a cycle being:
1. tell it to switch a relay,
2. get it's response from the event,
3. ask it for some measurements,
4. get measurements,
5. repeat.
Later I would like to develop a GUI as well, but not a big issue now
(another reason to use threads? not sure).


Twisted includes serial port support and will let you integrate with a
GUI toolkit.  Since Twisted encourages you to write programs which deal
with things asynchronously in a single thread, if you use it, your
concerns about data exchange, locking, and timing should be addressed
as a simple consequence of your overall program structure.

Jean-Paul
--
http://mail.python.org/mailman/listinfo/python-list