public inbox for gentoo-embedded@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-embedded] serial port handling question
@ 2010-01-13 23:52 David Relson
  2010-01-14  2:55 ` Peter Stuge
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: David Relson @ 2010-01-13 23:52 UTC (permalink / raw
  To: gentoo-embedded

G'day,

I'm porting some old DOS code to Linux for a medical device that is
being upgraded.  Among other goodies, it has a sensor that sends data at
115KB to an onboard NS16550A (or equivalent).  

The sensor is controlled (in part) by setting RTS on and off. I looked
high and low (pun intended) for an ioctl or similar call that would
allow this level of control and couldn't find anything. I finally ended
up using the ollowing lines of code: 

 outb(inportb(MCR) |  0x02, MCR);  //DTR,RTS=ON
 outb(inportb(MCR) & ~0x02, MCR);  //DTR=ON,RTS=OFF

Directly tweaking the I/O port runs against the grain, but it's the
only thing I've found that works.

Is there a better way to control the chip?

Regards,

David



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-13 23:52 [gentoo-embedded] serial port handling question David Relson
@ 2010-01-14  2:55 ` Peter Stuge
  2010-01-14  4:30   ` David Relson
  2010-01-14  2:56 ` Daniel Stonier
  2010-01-14 10:05 ` Bob Dunlop
  2 siblings, 1 reply; 13+ messages in thread
From: Peter Stuge @ 2010-01-14  2:55 UTC (permalink / raw
  To: gentoo-embedded

David Relson wrote:
> I'm porting some old DOS code to Linux for a medical device that is
> being upgraded.

Interesting, this business.


> The sensor is controlled (in part) by setting RTS on and off.

What is controlled, exactly? What is RTS being used for? If it is
indeed flow control then you are lucky and can simply enable hardware
flow control for the serial port, and Linux will then take care of
everything for you.

If not flow control and some other signalling, you have to write a
line discipline driver. I have done both this and serial drivers
(also related to DOS era equipment) and documentation is not the
greatest. Let me know if you would like some help.


> I looked high and low (pun intended) for an ioctl or similar call
> that would allow this level of control and couldn't find anything.

The best thing out there is tcsetattr() and friends.

By switching between baud rate 0 and something else you can reliably
and easily control both RTS and DTR, and nothing but RTS and DTR, but
always both at the same time.

Line disciplines can call the tty_throttle() and tty_unthrottle()
functions in the serial driver, which will then control RTS
accordingly, but the default TTY line discipline does not expose any
API that will result in throttle function calls.


>  outb(inportb(MCR) |  0x02, MCR);  //DTR,RTS=ON
>  outb(inportb(MCR) & ~0x02, MCR);  //DTR=ON,RTS=OFF
> 
> Directly tweaking the I/O port runs against the grain, but it's the
> only thing I've found that works.

Not only against the grain, it can mess up internal state in the
kernel serial layer and worst case lead to a kernel BUG_ON (kernel
hangs) or best case serial port hang (unhang e.g. by closing all file
handles for the port and opening again). It is not at all nice to
change these signals behind Linux' back.


//Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-13 23:52 [gentoo-embedded] serial port handling question David Relson
  2010-01-14  2:55 ` Peter Stuge
@ 2010-01-14  2:56 ` Daniel Stonier
  2010-01-14  3:47   ` Peter Stuge
  2010-01-14 10:05 ` Bob Dunlop
  2 siblings, 1 reply; 13+ messages in thread
From: Daniel Stonier @ 2010-01-14  2:56 UTC (permalink / raw
  To: gentoo-embedded

I've never actually used the RTS on - always had it off. But just in
case you didn't find the details there's a setting in the termios
options structure for rts - have you tried that?

'man termios' - look for CRTSCTS.

I usually use a bit of code to set the flag off for my connections:

*******************************

termios options;
// Disable Flow control
#if defined(CRTSCTS)
    options.c_cflag &= ~CRTSCTS; // Disable hardware flow control (old)
#elif defined (CNEW_RTSCTS)
    options.c_cflag &= ~CNEW_RTSCTS; // Disable hardware flow control (new)
#endif
tcsetattr(file_descriptor,TCSAFLUSH,&options);

*******************************

Above, file_descriptor is the handle you get back from the previously
called open(...).

2010/1/14 David Relson <relson@osagesoftware.com>
>
> G'day,
>
> I'm porting some old DOS code to Linux for a medical device that is
> being upgraded.  Among other goodies, it has a sensor that sends data at
> 115KB to an onboard NS16550A (or equivalent).
>
> The sensor is controlled (in part) by setting RTS on and off. I looked
> high and low (pun intended) for an ioctl or similar call that would
> allow this level of control and couldn't find anything. I finally ended
> up using the ollowing lines of code:
>
>  outb(inportb(MCR) |  0x02, MCR);  //DTR,RTS=ON
>  outb(inportb(MCR) & ~0x02, MCR);  //DTR=ON,RTS=OFF
>
> Directly tweaking the I/O port runs against the grain, but it's the
> only thing I've found that works.
>
> Is there a better way to control the chip?
>
> Regards,
>
> David
>



--
Phone : +82-10-5400-3296 (010-5400-3296)
HomePage: http://snorriheim.dnsdojo.com/
Yujin Robot: http://www.yujinrobot.com/
Projects: http://snorriheim.dnsdojo.com/redmine/projects
Embedded Control Libraries: http://snorriheim.dnsdojo.com/redmine/wiki/ecl



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14  2:56 ` Daniel Stonier
@ 2010-01-14  3:47   ` Peter Stuge
  2010-01-14  4:09     ` David Relson
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stuge @ 2010-01-14  3:47 UTC (permalink / raw
  To: gentoo-embedded

Daniel Stonier wrote:
> there's a setting in the termios options structure for rts - have
> you tried that?
> 
> 'man termios' - look for CRTSCTS.

Note that this flag does not directly control RTS, but rather it
instructs the kernel whether RTS/CTS signalling should be used for
flow control or not.

As David noticed, there is no API for directly controlling RTS in
Linux, it can only be done by the serial driver itself or a line
discipline driver.


//Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14  3:47   ` Peter Stuge
@ 2010-01-14  4:09     ` David Relson
  0 siblings, 0 replies; 13+ messages in thread
From: David Relson @ 2010-01-14  4:09 UTC (permalink / raw
  To: gentoo-embedded

On Thu, 14 Jan 2010 04:47:53 +0100
Peter Stuge wrote:

> Daniel Stonier wrote:
> > there's a setting in the termios options structure for rts - have
> > you tried that?
> > 
> > 'man termios' - look for CRTSCTS.
> 
> Note that this flag does not directly control RTS, but rather it
> instructs the kernel whether RTS/CTS signalling should be used for
> flow control or not.
> 
> As David noticed, there is no API for directly controlling RTS in
> Linux, it can only be done by the serial driver itself or a line
> discipline driver.
> 
> 
> //Peter

Hello Peter and Daniel,

Information greatly appreciated.  I'll digest it tomorrow when I'm more
alert.

After bashing my head against the wall (including experimentation with
CRTSCTS), I spent a while reading drivers/serial/8250.c and found that
CRTSCTS used only for enabling AFE (automatic flowcontrol enabled).
Not having adequate specs for the protocol or hardware involved,
there's some mystery as to exactly why RTS is used as it is.

For certain, it'll be interesting tomorrow to learn more of termios and
line discipline drivers (a new term for me).

Ciao,

David



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14  2:55 ` Peter Stuge
@ 2010-01-14  4:30   ` David Relson
  2010-01-14  5:08     ` Peter Stuge
  0 siblings, 1 reply; 13+ messages in thread
From: David Relson @ 2010-01-14  4:30 UTC (permalink / raw
  To: gentoo-embedded

On Thu, 14 Jan 2010 03:55:07 +0100
Peter Stuge wrote:

> David Relson wrote:
> > I'm porting some old DOS code to Linux for a medical device that is
> > being upgraded.
> 
> Interesting, this business.

And it feels so good when one stops banging one's head against the wall.


> > The sensor is controlled (in part) by setting RTS on and off.
> 
> What is controlled, exactly? What is RTS being used for? If it is
> indeed flow control then you are lucky and can simply enable hardware
> flow control for the serial port, and Linux will then take care of
> everything for you.

Not sure (insufficient documentation).  The functions setting and
clearing RTS have names like RS485_RTS_Receiver_Enable and
RS485_RTS_Transmitter_Enable.  My query as to the meaning/purpose of
the routines is awaiting an answer..
 
> If not flow control and some other signalling, you have to write a
> line discipline driver. I have done both this and serial drivers
> (also related to DOS era equipment) and documentation is not the
> greatest. Let me know if you would like some help.
> 
> 
> > I looked high and low (pun intended) for an ioctl or similar call
> > that would allow this level of control and couldn't find anything.
> 
> The best thing out there is tcsetattr() and friends.
> 
> By switching between baud rate 0 and something else you can reliably
> and easily control both RTS and DTR, and nothing but RTS and DTR, but
> always both at the same time.

The RS485 routines mentionned above only change RTS.  DTR remains on.
Attempts to change both (using CRTSCTS and tcsetattr()) didn't work.
 
> Line disciplines can call the tty_throttle() and tty_unthrottle()
> functions in the serial driver, which will then control RTS
> accordingly, but the default TTY line discipline does not expose any
> API that will result in throttle function calls.
>  
> >  outb(inportb(MCR) |  0x02, MCR);  //DTR,RTS=ON
> >  outb(inportb(MCR) & ~0x02, MCR);  //DTR=ON,RTS=OFF
> > 
> > Directly tweaking the I/O port runs against the grain, but it's the
> > only thing I've found that works.
> 
> Not only against the grain, it can mess up internal state in the
> kernel serial layer and worst case lead to a kernel BUG_ON (kernel
> hangs) or best case serial port hang (unhang e.g. by closing all file
> handles for the port and opening again). It is not at all nice to
> change these signals behind Linux' back.

I'm well aware of the hackish nature of my "solution".  It'll be
interesting to see what unwanted side effects show up to bite me.

David



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14  4:30   ` David Relson
@ 2010-01-14  5:08     ` Peter Stuge
  2010-01-14 10:53       ` Peter Bell
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stuge @ 2010-01-14  5:08 UTC (permalink / raw
  To: gentoo-embedded

David Relson wrote:
> > > The sensor is controlled (in part) by setting RTS on and off.
> > 
> > What is controlled, exactly? What is RTS being used for? If it is
> > indeed flow control then you are lucky and can simply enable
> > hardware flow control for the serial port, and Linux will then
> > take care of everything for you.
> 
> Not sure (insufficient documentation).  The functions setting and
> clearing RTS have names like RS485_RTS_Receiver_Enable and
> RS485_RTS_Transmitter_Enable.

That definately suggests that RTS/CTS would be used for flow control.


> My query as to the meaning/purpose of the routines is awaiting an
> answer..

Hopefully they will confirm that it's for flow control.

Then you can simply ignore everything related to RTS, as Linux will
take care of it for you. Just read from the opened tty device and
you'll get data when there is some. Linux also buffers writes, so if
a write() call succeeds then data will eventually go out on the port.


> The RS485 routines mentionned above only change RTS.  DTR remains on.
> Attempts to change both (using CRTSCTS and tcsetattr()) didn't work.

With tcsetattr() you'd use B0 in the CBAUD field to unset both
signals, and any B value other than B0 to set them. You can use
cfsetispeed() and cfsetospeed() to conveniently change only the
baudrate in a struct termios, but since it will also affect DTR I
don't think that this will work.


> I'm well aware of the hackish nature of my "solution".

What happens if you remove the code that touches the registers and
simply let Linux handle flow control? I suspect you could remove some
of the code surrounding the outb() calls as well, since the Linux
serial layer implements very thorough flow control.


> It'll be interesting to see what unwanted side effects show up to
> bite me.

Unfortunately the problems may not show up until far into the future,
with lots of installations possibly out in the field..


//Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-13 23:52 [gentoo-embedded] serial port handling question David Relson
  2010-01-14  2:55 ` Peter Stuge
  2010-01-14  2:56 ` Daniel Stonier
@ 2010-01-14 10:05 ` Bob Dunlop
  2010-01-14 12:29   ` David Relson
  2 siblings, 1 reply; 13+ messages in thread
From: Bob Dunlop @ 2010-01-14 10:05 UTC (permalink / raw
  To: gentoo-embedded

On Wed, Jan 13 at 06:52, David Relson wrote:
...
> Directly tweaking the I/O port runs against the grain, but it's the
> only thing I've found that works.
> 
> Is there a better way to control the chip?


I know others have commented on using automatic settings for flow control 
etc, but if you need to control the lines directly there are an often
neglected set of ioctls to do this. 

Some snippets of code, last used on x86 four years ago but it looks like
the hooks are still in the kernel and a fair number of device drivers.

    unsigned int flags;

    /* Raise RTS and DTR.
     * Linux will have already done this but some Unix system don't and
     * some wait for DCD before doing so, so make it explicit.
     */
    flags = TIOCM_RTS | TIOCM_DTR;
    if ( ioctl( fd, TIOCMBIS, &flags ) != 0 )
    {
        fprintf( stderr,"Failed to raise RTS and DTR.  Errno %d\n", errno );
        /* Possibly not fatal so we continue */
    }

    ... 

    /* Drop RTS */
    flags = TIOCM_RTS;
    if ( ioctl( fd, TIOCMBIC, &flags ) != 0 )
    {
        fprintf( stderr,"Failed to clear RTS.  Errno %d\n", errno );
    }

As well as set and clear there is a get (TIOCMGET) useful for checking DCD.

-- 
        Bob Dunlop



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [gentoo-embedded] serial port handling question
  2010-01-14  5:08     ` Peter Stuge
@ 2010-01-14 10:53       ` Peter Bell
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Bell @ 2010-01-14 10:53 UTC (permalink / raw
  To: gentoo-embedded

RS485 is a half-duplex bus, so this looks like a transmit enable rather than
flow control - and generally the transmit enable timing is quite critical,
since you have to leave it asserted until the last bit is sent from the UART
(so the normal "interrupt of THRE or FIFO low" is useless - you have to use
a TDRE interrupt), and then needs to be very quickly turned around before
the addressed device comes back with it's response.

If you don't want to bitbash the control registers in userland you are just
going to have to add a special mode to the driver, I'm afraid - none of the
RS485 implementations I've ever seen will work correctly using the flow
control semantics that the kernel implements.

Pete
-----Original Message-----
From: Peter Stuge [mailto:peter@stuge.se] 
Sent: Thursday, January 14, 2010 1:08 PM
To: gentoo-embedded@lists.gentoo.org
Subject: Re: [gentoo-embedded] serial port handling question

David Relson wrote:
> > > The sensor is controlled (in part) by setting RTS on and off.
> > 
> > What is controlled, exactly? What is RTS being used for? If it is
> > indeed flow control then you are lucky and can simply enable
> > hardware flow control for the serial port, and Linux will then
> > take care of everything for you.
> 
> Not sure (insufficient documentation).  The functions setting and
> clearing RTS have names like RS485_RTS_Receiver_Enable and
> RS485_RTS_Transmitter_Enable.

That definately suggests that RTS/CTS would be used for flow control.


> My query as to the meaning/purpose of the routines is awaiting an
> answer..

Hopefully they will confirm that it's for flow control.

Then you can simply ignore everything related to RTS, as Linux will
take care of it for you. Just read from the opened tty device and
you'll get data when there is some. Linux also buffers writes, so if
a write() call succeeds then data will eventually go out on the port.


> The RS485 routines mentionned above only change RTS.  DTR remains on.
> Attempts to change both (using CRTSCTS and tcsetattr()) didn't work.

With tcsetattr() you'd use B0 in the CBAUD field to unset both
signals, and any B value other than B0 to set them. You can use
cfsetispeed() and cfsetospeed() to conveniently change only the
baudrate in a struct termios, but since it will also affect DTR I
don't think that this will work.


> I'm well aware of the hackish nature of my "solution".

What happens if you remove the code that touches the registers and
simply let Linux handle flow control? I suspect you could remove some
of the code surrounding the outb() calls as well, since the Linux
serial layer implements very thorough flow control.


> It'll be interesting to see what unwanted side effects show up to
> bite me.

Unfortunately the problems may not show up until far into the future,
with lots of installations possibly out in the field..


//Peter
 

__________ Information from ESET NOD32 Antivirus, version of virus signature
database 4770 (20100114) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
 




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14 10:05 ` Bob Dunlop
@ 2010-01-14 12:29   ` David Relson
  2010-01-14 16:17     ` Peter Stuge
  0 siblings, 1 reply; 13+ messages in thread
From: David Relson @ 2010-01-14 12:29 UTC (permalink / raw
  To: gentoo-embedded; +Cc: bob.dunlop

On Thu, 14 Jan 2010 10:05:31 +0000
Bob Dunlop wrote:

> On Wed, Jan 13 at 06:52, David Relson wrote:
> ...
> > Directly tweaking the I/O port runs against the grain, but it's the
> > only thing I've found that works.
> > 
> > Is there a better way to control the chip?
> 
> 
> I know others have commented on using automatic settings for flow
> control etc, but if you need to control the lines directly there are
> an often neglected set of ioctls to do this. 
> 
> Some snippets of code, last used on x86 four years ago but it looks
> like the hooks are still in the kernel and a fair number of device
> drivers.
> 
>     unsigned int flags;
> 
>     /* Raise RTS and DTR.
>      * Linux will have already done this but some Unix system don't
> and
>      * some wait for DCD before doing so, so make it explicit.
>      */
>     flags = TIOCM_RTS | TIOCM_DTR;
>     if ( ioctl( fd, TIOCMBIS, &flags ) != 0 )
>     {
>         fprintf( stderr,"Failed to raise RTS and DTR.  Errno %d\n",
> errno ); /* Possibly not fatal so we continue */
>     }
> 
>     ... 
> 
>     /* Drop RTS */
>     flags = TIOCM_RTS;
>     if ( ioctl( fd, TIOCMBIC, &flags ) != 0 )
>     {
>         fprintf( stderr,"Failed to clear RTS.  Errno %d\n", errno );
>     }
> 
> As well as set and clear there is a get (TIOCMGET) useful for
> checking DCD.
> 
> -- 
>         Bob Dunlop

Sweet!  Very sweet!

This sounds exactly like what I want.  I saw the TIOCM_xxx symbols
being used in serial8250_get_mctrl() and serial8250_set_mctrl(), but
didn't know how to access those functions.

I'll test it later this morning when I get to work.

Regards,

David



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14 12:29   ` David Relson
@ 2010-01-14 16:17     ` Peter Stuge
  2010-01-14 16:21       ` Relson, David
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stuge @ 2010-01-14 16:17 UTC (permalink / raw
  To: gentoo-embedded

David Relson wrote:
> > but if you need to control the lines directly there are an often
> > neglected set of ioctls to do this.

Nice! I thought I had looked at all paths into uart_update_mctrl()
but clearly not. Thanks for pointing it out!


> This sounds exactly like what I want.
> I'll test it later this morning when I get to work.

It should work well.


//Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [gentoo-embedded] serial port handling question
  2010-01-14 16:17     ` Peter Stuge
@ 2010-01-14 16:21       ` Relson, David
  2010-01-14 16:29         ` Peter Stuge
  0 siblings, 1 reply; 13+ messages in thread
From: Relson, David @ 2010-01-14 16:21 UTC (permalink / raw
  To: gentoo-embedded

'Tis working perfectly for /dev/ttyS2.  

/dev/ttyS4 is seg-faulting for unknown reasons -- most certainly a flaw
unrelated to the ioctl.

Regards,
 
David
-----Original Message-----
From: Peter Stuge [mailto:peter@stuge.se] 
Sent: Thursday, January 14, 2010 11:18 AM
To: gentoo-embedded@lists.gentoo.org
Subject: Re: [gentoo-embedded] serial port handling question

David Relson wrote:
> > but if you need to control the lines directly there are an often
> > neglected set of ioctls to do this.

Nice! I thought I had looked at all paths into uart_update_mctrl()
but clearly not. Thanks for pointing it out!


> This sounds exactly like what I want.
> I'll test it later this morning when I get to work.

It should work well.


//Peter




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-embedded] serial port handling question
  2010-01-14 16:21       ` Relson, David
@ 2010-01-14 16:29         ` Peter Stuge
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Stuge @ 2010-01-14 16:29 UTC (permalink / raw
  To: gentoo-embedded

Relson, David wrote:
> 'Tis working perfectly for /dev/ttyS2.  
> 
> /dev/ttyS4 is seg-faulting for unknown reasons -- most certainly a
> flaw unrelated to the ioctl.

Is ttyS2 and ttyS4 using the same driver? What does

cat /proc/tty/driver/*

give?


//Peter



^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-01-14 16:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-01-13 23:52 [gentoo-embedded] serial port handling question David Relson
2010-01-14  2:55 ` Peter Stuge
2010-01-14  4:30   ` David Relson
2010-01-14  5:08     ` Peter Stuge
2010-01-14 10:53       ` Peter Bell
2010-01-14  2:56 ` Daniel Stonier
2010-01-14  3:47   ` Peter Stuge
2010-01-14  4:09     ` David Relson
2010-01-14 10:05 ` Bob Dunlop
2010-01-14 12:29   ` David Relson
2010-01-14 16:17     ` Peter Stuge
2010-01-14 16:21       ` Relson, David
2010-01-14 16:29         ` Peter Stuge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox