|
Home > Archive > Unix Programming > January 2006 > serial ports: how do I know data has been sent?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
serial ports: how do I know data has been sent?
|
|
| Simon Elliott 2006-01-16, 6:05 pm |
| If I write a byte to a serial port via write(), and hardware flow
control is enabled, is there any way of determining when the byte is
actually sent? I appreciate that the byte could be lying around in the
output buffer for a long time, potentially forever.
Or to put it another way, is there a way of getting a count of the
bytes in the output buffer which still haven't been sent?
--
Simon Elliott http://www.ctsn.co.uk
| |
| James Carlson 2006-01-16, 6:05 pm |
| "Simon Elliott" <Simon at ctsn.co.uk> writes:
> If I write a byte to a serial port via write(), and hardware flow
> control is enabled, is there any way of determining when the byte is
> actually sent? I appreciate that the byte could be lying around in the
> output buffer for a long time, potentially forever.
Basically, no.
Even if you could get this, what on Earth would you do with it?
Knowing that the byte has left the building doesn't tell you much. It
certainly doesn't prove that the other system has received it yet or
done anything useful with it.
The closest you can get is to do TCSBRK with the argument set non-zero
(1 is customary). This will return when the buffer has "drained."
What "drained" means depends on the implementation of the operating
system and the drivers.
> Or to put it another way, is there a way of getting a count of the
> bytes in the output buffer which still haven't been sent?
TIOCOUTQ works on some systems, but can give only an approximate
number even in the best of worlds.
--
James Carlson, KISS Network <james.d.carlson@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
| |
| Simon Elliott 2006-01-16, 6:05 pm |
| On 16/01/2006, James Carlson wrote:
> "Simon Elliott" <Simon at ctsn.co.uk> writes:
>
> Basically, no.
>
> Even if you could get this, what on Earth would you do with it?
> Knowing that the byte has left the building doesn't tell you much. It
> certainly doesn't prove that the other system has received it yet or
> done anything useful with it.
What if you're sending data to a modem and you want to do something to
the modem once it's got all the data? I suppose you could use a
tcsetattr() with TCSADRAIN, but would it block?
> The closest you can get is to do TCSBRK with the argument set non-zero
> (1 is customary). This will return when the buffer has "drained."
> What "drained" means depends on the implementation of the operating
> system and the drivers.
I was hoping for a non blocking solution.
[vbcol=seagreen]
> TIOCOUTQ works on some systems, but can give only an approximate
> number even in the best of worlds.
I only really need to know zero or non zero, not an accurate number.
--
Simon Elliott http://www.ctsn.co.uk
| |
| David Schwartz 2006-01-17, 3:11 am |
|
"Simon Elliott" <Simon at ctsn.co.uk> wrote in message
news:43cba7ee$0$87295$bed64819@news.gradwell.net...
> If I write a byte to a serial port via write(), and hardware flow
> control is enabled, is there any way of determining when the byte is
> actually sent? I appreciate that the byte could be lying around in the
> output buffer for a long time, potentially forever.
>
> Or to put it another way, is there a way of getting a count of the
> bytes in the output buffer which still haven't been sent?
Ask the device. After all, what difference is it to you whether it's in
your send buffer or the device's receive buffer?
DS
| |
| James Carlson 2006-01-17, 8:03 am |
| "Simon Elliott" <Simon at ctsn.co.uk> writes:
>
> What if you're sending data to a modem and you want to do something to
> the modem once it's got all the data? I suppose you could use a
> tcsetattr() with TCSADRAIN, but would it block?
To the modem itself or to some peer?
If it's to the modem itself (downloading some firmware, perhaps), then
I'd suggest using a null command -- just "AT" and wait for "OK."
If it's to a peer, then you'll probably want to wait until you know
the peer's done something useful with the data. That usually requires
some sort of application-layer acknowledgment, and not just seeing the
last bit leave the system.
If you just want to send break, ioctl(fd,TCSBRK,0) will wait for drain
and then send break.
>
> I was hoping for a non blocking solution.
There aren't any, besides multithreading. Serial ports can be
difficult beasts.
Even if there were one, you couldn't use it. There's no way to wake
up asynchronously on "output done" in UNIX. You'd end up needing to
poll, and that's probably worse than just about any other solution.
>
>
> I only really need to know zero or non zero, not an accurate number.
Good luck ... I don't think that TIOCOUTQ is really what you want, but
if it works, I guess I won't argue.
--
James Carlson, KISS Network <james.d.carlson@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
| |
| Simon Elliott 2006-01-17, 6:05 pm |
| On 17/01/2006, David Schwartz wrote:
>
> Ask the device. After all, what difference is it to you whether
> it's in your send buffer or the device's receive buffer?
A couple of examples from real life, where luckily I was using DOS and
could therefore do whatever I wanted with the serial ports:
1/ Controlling a network of pressure transducers which used RS485, from
a PC serial port via a RS232-485 converter which IIRC used RTS to grab
the bus. It was fairly important to drop RTS _after_ the last character
had been sent, but not too long after.
2/ Controlling a data collection device which continously transmitted
garbage till it had been sent a "wake up" command.
--
Simon Elliott http://www.ctsn.co.uk
| |
| Mark Hobley 2006-01-17, 8:49 pm |
| Simon Elliott <Simon at ctsn.co.uk> wrote:
> If I write a byte to a serial port via write(), and hardware flow
> control is enabled, is there any way of determining when the byte is
> actually sent? I appreciate that the byte could be lying around in the
> output buffer for a long time, potentially forever.
>
> Or to put it another way, is there a way of getting a count of the
> bytes in the output buffer which still haven't been sent?
>
Depending on your implementation, you could consider using ACK/NAK.
Regards,
Mark.
--
Mark Hobley
393 Quinton Road West
QUINTON
Birmingham
B32 1QE
Telephone: (0121) 247 1596
International: 0044 121 247 1596
Email: markhobley at hotpop dot donottypethisbit com
http://markhobley.yi.org/
| |
| David Schwartz 2006-01-18, 2:50 am |
|
"Simon Elliott" <Simon at ctsn.co.uk> wrote in message
news:43cd7413$0$87294$bed64819@news.gradwell.net...
> On 17/01/2006, David Schwartz wrote:
[vbcol=seagreen]
> A couple of examples from real life, where luckily I was using DOS and
> could therefore do whatever I wanted with the serial ports:
> 1/ Controlling a network of pressure transducers which used RS485, from
> a PC serial port via a RS232-485 converter which IIRC used RTS to grab
> the bus. It was fairly important to drop RTS _after_ the last character
> had been sent, but not too long after.
I'm not precisely sure I understand what you're saying. If you're saying
there was something you had to do, out of the data band but not part of the
normal handshaking protocol, after all the data was sent and before the
device acknowledged any data in-band, then the device is badly broken.
Essentially, it is *NOT* RS232 at that point.
> 2/ Controlling a data collection device which continously transmitted
> garbage till it had been sent a "wake up" command.
A device that sends garbage has to send you something to assure you that
the garbage has ended. Knowing that you sent it the wake up doesn't
synchronize to the incoming data stream. A given byte of received data could
have been sent before or after the wake up was received and processed. So
there'd still have to be some synchronization from the device.
DS
| |
| James Carlson 2006-01-18, 7:51 am |
| "Simon Elliott" <Simon at ctsn.co.uk> writes:
> A couple of examples from real life, where luckily I was using DOS and
> could therefore do whatever I wanted with the serial ports:
>
> 1/ Controlling a network of pressure transducers which used RS485, from
> a PC serial port via a RS232-485 converter which IIRC used RTS to grab
> the bus. It was fairly important to drop RTS _after_ the last character
> had been sent, but not too long after.
That's a line discipline. Having an RTS envelope on the data (and
presumably listening to CTS in response to RTS) is a well-known
standard RS-232 behavior. It's _not_ the default way that modems are
typically used -- which is more of an industry standard than an actual
standard -- but it's defined by the written standards themselves.
It should be selectable and, in my opinion, implemented as a part of
the system itself. In other words, likely in the kernel, and
certainly not part of an application program. It's an architectural
issue.
> 2/ Controlling a data collection device which continously transmitted
> garbage till it had been sent a "wake up" command.
I think the best you can do is send the special command, drain, then
flush pending input. Even then, it's possible that you could get
confused by timing elements that don't work out well.
Assuming that the "good" data has some pattern to it, you might be
able to repeat that command (or some "no-op" type command) until
you're in sync. That should cover most of the important cases of
confusion. If it has no usable pattern, then I think you may be sunk.
A separate but related issue here is what to do if the data you
receive some time *after* that "wake up" sequence are garbled.
Hardware isn't perfect, and errors do happen. You need a scheme that
will allow you to detect this problem and recover from it. I suspect
it's likely that this scheme, if it's robust at all, would cover for
the start-up confusion problem as well.
(This sounds a bit like a typical mouse or keyboard. They can be hard
to deal with at times.)
--
James Carlson, KISS Network <james.d.carlson@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
| |
| Simon Elliott 2006-01-20, 6:03 pm |
| On 18/01/2006, David Schwartz wrote:
>
>
> I'm not precisely sure I understand what you're saying. If you're
> saying there was something you had to do, out of the data band but
> not part of the normal handshaking protocol, after all the data was
> sent and before the device acknowledged any data in-band, then the
> device is badly broken. Essentially, it is NOT RS232 at that point.
Possibly not, but it's quite a common scenario.
Many RS232-485 converters connect RTS to the RS-485 controller such
that RTS high enables the RS-485 controller, and RTS low puts the
controller into the tristate condition. So to send a command to one of
the RS425 slave devices, you'd raise RTS, send the characters, then
once the final character has left the UART, drop RTS. Dropping RTS
frees the bus for the slave device to reply. The converter we used also
required CTS to be high as it used this for power.
Easy enough to implement for a 16550A on a PC running DOS, seemingly
much harder to implement portably on a unix box!
The alternative would be to source a proper RS-485 controller card and
drivers, which the user would need to install. Far simpler to use a
converter, if the software can be made to cope with it!
I suspect that USB devices are making all this a moot point...
>
> A device that sends garbage has to send you something to assure
> you that the garbage has ended. Knowing that you sent it the wake up
> doesn't synchronize to the incoming data stream. A given byte of
> received data could have been sent before or after the wake up was
> received and processed. So there'd still have to be some
> synchronization from the device.
Yes, But you can make the window you need to search through much
smaller.
Also useful for verifying that necessary attached devices are present,
or still present. If after a few tens of milliseconds no bytes have
even left the UART, you know that you don't have to wait perhaps
several seconds for a reply from the device.
--
Simon Elliott http://www.ctsn.co.uk
| |
| Simon Elliott 2006-01-30, 8:42 am |
| On 18/01/2006, James Carlson wrote:
>
> That's a line discipline. Having an RTS envelope on the data (and
> presumably listening to CTS in response to RTS) is a well-known
> standard RS-232 behavior. It's not the default way that modems are
> typically used -- which is more of an industry standard than an actual
> standard -- but it's defined by the written standards themselves.
>
> It should be selectable and, in my opinion, implemented as a part of
> the system itself. In other words, likely in the kernel, and
> certainly not part of an application program. It's an architectural
> issue.
Agreed, in an ideal world. But I want to be able to deploy apps which
use the serial port as required, without requiring the user to
recompile the kernel.
>
> I think the best you can do is send the special command, drain, then
> flush pending input. Even then, it's possible that you could get
> confused by timing elements that don't work out well.
The problem with draining is that it seems to be a blocking operation.
> Assuming that the "good" data has some pattern to it, you might be
> able to repeat that command (or some "no-op" type command) until
> you're in sync. That should cover most of the important cases of
> confusion. If it has no usable pattern, then I think you may be sunk.
Even in the DOS days, there were issues with bytes queued up the uart's
FIFOs...
> A separate but related issue here is what to do if the data you
> receive some time after that "wake up" sequence are garbled.
> hardware isn't perfect, and errors do happen. You need a scheme that
> will allow you to detect this problem and recover from it. I suspect
> it's likely that this scheme, if it's robust at all, would cover for
> the start-up confusion problem as well.
Yes, that's a good point.
--
Simon Elliott http://www.ctsn.co.uk
| |
| Simon Elliott 2006-01-30, 8:42 am |
| On 17/01/2006, James Carlson wrote:
>
> To the modem itself or to some peer?
To the modem. We once developed a windows app which sent voice data to
a modem in 8000Hz ADPCM format. The timings for this were sometimes (in
practice) quite critical.
> If it's to the modem itself (downloading some firmware, perhaps), then
> I'd suggest using a null command -- just "AT" and wait for "OK."
>
> If it's to a peer, then you'll probably want to wait until you know
> the peer's done something useful with the data. That usually requires
> some sort of application-layer acknowledgment, and not just seeing the
> last bit leave the system.
>
> If you just want to send break, ioctl(fd,TCSBRK,0) will wait for drain
> and then send break.
Won't that block?
> Good luck ... I don't think that TIOCOUTQ is really what you want, but
> if it works, I guess I won't argue.
I think we'll need the luck - especially if we want to port this to a
few other unix variants...
--
Simon Elliott http://www.ctsn.co.uk
| |
| James Carlson 2006-01-30, 8:42 am |
| "Simon Elliott" <Simon at ctsn.co.uk> writes:
>
> Won't that block?
Yes. Why is blocking a concern? Can your application use threads or
separate processes to deal with blocking?
>
> I think we'll need the luck - especially if we want to port this to a
> few other unix variants...
Indeed.
--
James Carlson, KISS Network <james.d.carlson@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
|
|
|
|
|