pySerial: write in a blocking mode

A

Alejandro

Hi:

I'm using pySerial to talk to a RS232 to RS485 converter. In order to
control the converter, I need to control the DTR line to enable/disable
de RS485 driver. In particular, I need to :

write a character to the serial port
set the DTR line to level 1 _after_ the last bit of the character is
send

So I tried this (ser is the serial port object):

ser.write(x)
ser.setDTR(1)

The problem with this is that the ser.write function returns before the
character is send, and thus, the DTR line is set too soon. (I checked
this behaivour with an osciloscope).

I thought that seting the writeTimeout parameter could help, but then I
realized that the write function wait "up to this time", so it doesn't
work.

Then I tried waiting some time with time.sleep() after ser.write, but
the shortest time for time.sleep is to big, and non deterministic, so I
think this is not an option.

Does anybody know how to do a ser.write() in a blocking way?

Regards,
Alejandro.
 
P

Peter Hansen

Alejandro said:
I'm using pySerial to talk to a RS232 to RS485 converter. In order to
control the converter, I need to control the DTR line to enable/disable
de RS485 driver.

This seems a little odd to me. We've used several RS232-RS485
converters without needing to do that. Maybe a more sophisticated
device would eliminate this need?
Does anybody know how to do a ser.write() in a blocking way?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/flushfilebuffers.asp

(If that link is broken, it's the docs for the FlushFileBuffers routine.
This doesn't appear to be exposed in Pyserial, but you could probably
subclass serial.Serial and add it yourself pretty easily. The Pyserial
source is quite accessible.)

Disclaimer: I haven't tried using that routine myself, but the docs
imply it is supposed to do what you want. Unfortunately, I doubt
there's any particular guarantee about whether the data has only left
the Windows buffers, or whether it has also left the transmit buffer of
the UART *and* that the stop bit itself has even been transmitted. What
you're trying to do is a hard realtime operation, and unless it's
directly supported you could be up against an impossible task using
Windows. (But it seems you already knew that. :)

-Peter
 
A

Alejandro

Peter said:
This seems a little odd to me. We've used several RS232-RS485
converters without needing to do that. Maybe a more sophisticated
device would eliminate this need?

Yes. The device is very simple (I made it).
What you're trying to do is a hard realtime operation, and unless it's
directly supported you could be up against an impossible task using
Windows. (But it seems you already knew that. :)

I know it can be difficult/impossible. By the way, I am coding in
Linux, but want my code to be portable between Windows and Linux(!).

I will rethink the whole issue. May be I will use the time.sleep
alternative, taking a good margin to manage the uncertainty of the
delay.
 
G

Grant Edwards

Hi:

I'm using pySerial to talk to a RS232 to RS485 converter. In order to
control the converter, I need to control the DTR line to enable/disable
de RS485 driver. In particular, I need to :

write a character to the serial port
set the DTR line to level 1 _after_ the last bit of the character is
send

So I tried this (ser is the serial port object):

ser.write(x)
ser.setDTR(1)
ser.write(x)
ser.drainOutput()
ser.setDTR(1)

The problem with this is that the ser.write function returns before the
character is send, and thus, the DTR line is set too soon. (I checked
this behaivour with an osciloscope).

I thought that seting the writeTimeout parameter could help, but then I
realized that the write function wait "up to this time", so it doesn't
work.

Then I tried waiting some time with time.sleep() after ser.write, but
the shortest time for time.sleep is to big, and non deterministic, so I
think this is not an option.

Linux is not a real-time operating system. The
ser.drainOutput() call is going to have the same granularity
and non-determinism as time.sleep().

It sounds like you need a serial board that supports
half-duplex operation.
 
P

pdalet

Hi

I have developped a python script to control a rs232c rs485 converter,
named pyRS485
with pythoncard on windows.

ftp-champo.ac-toulouse.fr/pub/btseo/pdalet/python/
python 2.4 Electronics Applications 20050902.exe

The best solution is to send the last character with interrupt. when
the TDR is empty
an interrupt is generated. An interrupt program is executed to change
the state of dtr. Not evident on Windows and linux.

I have used temporisation, with different values for a slow pc and
speed pc.

Philippe Marie dit Dalet
FIGEAC
FRANCE


Grant Edwards a écrit :
 
P

Peter Hansen

Alejandro said:
Yes. The device is very simple (I made it).

Perhaps a very simple change to it would make it as convenient as the
commercial products. I vaguely recall (not having checked for over a
decade) that all they do is set the outgoing DTR line whenever there is
data being transmitted by the PC, by using something like a 555 timer
with a very short delay (effectively watching the start bit and any zero
bits that are transmitted). There are probably even example circuits
based on this or better approaches available on the net.

-Peter
 
A

Alejandro

Peter said:
Perhaps a very simple change to it would make it as convenient as the
commercial products. I vaguely recall (not having checked for over a
decade) that all they do is set the outgoing DTR line whenever there is
data being transmitted by the PC, by using something like a 555 timer
with a very short delay (effectively watching the start bit and any zero
bits that are transmitted). There are probably even example circuits
based on this or better approaches available on the net.

You are right. For instance, the 485COSR converter, from B&B
electronics, does precisely that. The schematic is in the datasheet
(http://tinyurl.com/ro6qy).

I will try this route.

Thanks for the help.
 
G

Grant Edwards

The best solution is to send the last character with
interrupt. when the TDR is empty an interrupt is generated. An
interrupt program is executed to change the state of dtr.

No. That doesn't work. You have to wait until the transmit
_shift_register_ is empty, not the transmit data register. If
you shut off DTR as soon as the transmit data register is
empty, you'll cut off the last character. The transmit data
register will go empty as soon as the last byte has been loaded
into the shift register. At that point the last byte hasn't
been sent yet.

And on the 16450 and 16550 UARTS there _is_no_interrupt_ for
transmit shift register empty.

Even if you poll for the shift register empty status bit, some
implimentations set that bit too early and you'll cut off part
or all of the last stop bit.

Trust me. I've fought with this issue on PCs for 15 years.
 
G

Grant Edwards

Perhaps a very simple change to it would make it as convenient as the
commercial products. I vaguely recall (not having checked for over a
decade) that all they do is set the outgoing DTR line whenever there is
data being transmitted by the PC, by using something like a 555 timer
with a very short delay (effectively watching the start bit and any zero
bits that are transmitted). There are probably even example circuits
based on this or better approaches available on the net.

That approach works pretty well as long as you can tolerate an
extra byte-time delay after the last stop bit before DTR or RTS
or whatever changes state.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,787
Messages
2,569,627
Members
45,329
Latest member
InezZ76898

Latest Threads

Top