fcntl, serial ports and serial signals on RS232.

M

Max Kotasek

Hello to all out there,

I'm trying to figure out how to parse the responses from fcntl.ioctl()
calls that modify the serial lines in a way that asserts that the line
is now changed. For example I may want to drop RTS explicitly, and
assert that the line has been dropped before returning.

Here is a brief snippet of code that I've been using to do that, but
not sure what to do with the returned response:

def set_RTS(self, state=True):
if self.fd is None:
return 0

p = struct.pack('I', termios.TIOCM_RTS)
if state:
return fcntl.ioctl(self.fd, termios.TIOCMBIS, p)
else:
return fcntl.ioctl(self.fd, termios.TIOCMBIC, p)

The problem is I get responses like '\x01\x00\x00\x00', or
'\x02\x00\x00\x00' and I'm not sure what they mean. I tried doing
illogical things like settings CTS using the TIOCM_CTS flag and I end
up just getting back a slightly different binary packed 32 bit integer
(in that case '\x20\x00\x00\x00'). The above example has self.fd
being defined as os.open('/dev/ttyS0', os.O_RDWR | os.O_NONBLOCK).

Is someone familiar with manipulating serial signals like this in
python? Am I even taking the right approach by using the fcntl.ioctl
call? The environment is a ubuntu 8.04 distribution. Unfortunately
due to other limitations, I can't use/extend pyserial, though I would
like to.

I appreciate any advice on this matter,
Max
 
A

Anssi Saari

Max Kotasek said:
Hello to all out there,

I'm trying to figure out how to parse the responses from fcntl.ioctl()
calls that modify the serial lines in a way that asserts that the line
is now changed. For example I may want to drop RTS explicitly, and
assert that the line has been dropped before returning.

Here is a brief snippet of code that I've been using to do that, but
not sure what to do with the returned response:

def set_RTS(self, state=True):
if self.fd is None:
return 0

p = struct.pack('I', termios.TIOCM_RTS)
if state:
return fcntl.ioctl(self.fd, termios.TIOCMBIS, p)
else:
return fcntl.ioctl(self.fd, termios.TIOCMBIC, p)

The problem is I get responses like '\x01\x00\x00\x00', or
'\x02\x00\x00\x00' and I'm not sure what they mean.

I'm not an expert in this by any means. However, I don't think that
fcntl call actually returns the port status after the bit setting. But
why not check it explicitly with termios.TIOCMGET? At least then I
seem to be able to toggle the RTS bit (bit 2) in the register. Here
are the trivial functions I used:

def set_rts(fd):
print "Setting RTS."
p = struct.pack('I', termios.TIOCM_RTS)
fcntl.ioctl(fd, termios.TIOCMBIS, p)

def clear_rts(fd):
print "Clearing RTS."
p = struct.pack('I', termios.TIOCM_RTS)
fcntl.ioctl(fd, termios.TIOCMBIC, p)

def get_status(fd):
print "Querying RTS state."
stat = struct.pack('I', 0)
rc = fcntl.ioctl(fd, termios.TIOCMGET, stat)
if struct.unpack('I', rc)[0] & termios.TIOCM_RTS:
print "RTS bit is on."
else:
print "RTS bit is off."


It seems to me also that RTS is always on after the port has been
opened. I didn't dig out my voltmeter or anything to check this,
though.
 
G

Grant Edwards

I'm trying to figure out how to parse the responses from fcntl.ioctl()
calls that modify the serial lines in a way that asserts that the line
is now changed.

Two comments:

1) None of the Linux serial drivers I've worked on return line states
except when you call TIOCMGET.

2) If the TIOCMBI[S|C] call returned a 'success' value, then the
line was set to what you requested.

If you want to read back the state that you just wrote, you can call
TIOCMGET, but for the "output" pins it's always going to return the
last value that was written.
For example I may want to drop RTS explicitly, and
assert that the line has been dropped before returning.

Call TIOCMSET. If it doesn't return an error, then you're done.
Here is a brief snippet of code that I've been using to do that, but
not sure what to do with the returned response:

What returned response?

The only thing that is returned by TIOCMBIS/TIOCMBIC is a status value
of 0 for success and <0 for failure. IIRC, that value is checked by
Python's fcntl.ioctl wrapper and it will raise an exception on
failure.
Is someone familiar with manipulating serial signals like this in
python?
Yes.

Am I even taking the right approach by using the fcntl.ioctl call?

Yes. When you set/clear RTS or DTR do they not go up/down?

Even if you can't use pyserial, it's a good source for example code.
 
G

Grant Edwards

It seems to me also that RTS is always on after the port has been
opened. I didn't dig out my voltmeter or anything to check this,
though.

IIRC, that's generally true: RTS and DTR are both set to "on" by the
tty layer's open() handler _if_ the device's useage count was 0. If
you open an already open port, then the RTS and DTR lines are left
alone.
 
M

Max Kotasek

I'm trying to figure out how to parse the responses fromfcntl.ioctl()
calls that modify the serial lines in a way that asserts that the line
is now changed.

Two comments:

  1) None of the Linux serial drivers I've worked on return line states
     except when you call TIOCMGET.

  2) If the TIOCMBI[S|C] call returned a 'success' value, then the
     line was set to what you requested.

If you want to read back the state that you just wrote, you can call
TIOCMGET, but for the "output" pins it's always going to return the
last value that was written.
For example I may want to drop RTS explicitly, and
assert that the line has been dropped before returning.

Call TIOCMSET.  If it doesn't return an error, then you're done.
Here is a brief snippet of code that I've been using to do that, but
not sure what to do with the returned response:

What returned response?

The only thing that is returned by TIOCMBIS/TIOCMBIC is a status value
of 0 for success and <0 for failure. IIRC, that value is checked by
Python'sfcntl.ioctl wrapper and it will raise an exception on
failure.
Is someone familiar with manipulating serial signals like this in
python?
Yes.

Am I even taking the right approach by using thefcntl.ioctl call?

Yes.  When you set/clear RTS or DTR do they not go up/down?

Even if you can't use pyserial, it's a good source for example code.


I appreciate the feedback. I'm working in an environment with a lot
of changing factors, it's nice to have a piece not act unexpectedly.

Max
 

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

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top