I am testing code for serial port communication. I am using synchronous IO for now to keep things simple. I have observed that when the PC recieves XOFF the program pauses, no more printing in the console window. When the program recieves XON it starts running again.
What method exists to find out if my program's serial port has earlier recieved XOFF (regardless of synchronous and asynchronous IO) since the COM port driver shall prevent the port from sending any characters out in this case and I better check if XOFF was recieved before calling writefile().
I think that one way is to use the ClearCommError() with COMSTAT struct. Is this the only way? I get this impression by reading https://msdn.microsoft.com/en-us/library/ff802693.aspx
If that is so, it certainly appears a strange way of doing that.
Related
I have a C++ program which uses Windows sockets to communicate in the LAN with another instance of the same program. This works in general. For a few customers it doesn't.
Socket creation, listen and accept succeed. The computer who created the socket can send() a message and the second computer will recv() it. However, when it sends a reply (using send(), successfully), this doesn't arrive at the first computer.
If I artificially increase the message size, send() reports to send the first 65564(!) bytes successfully, but when I call it again for the rest, it returns -1 and WSAGetLastError return 183 (ERROR_ALREADY_EXISTS). Again, nothing arrives at the first computer. Firewalls / AV programs are already turned off.
It seems to me as if send() is keeping the data in some kind of "outbox" without really sending it. What could cause such a thing?
I'm experiencing a frustrating behaviour of windows sockets that I cant find any info on, so I thought I'd try here.
My problem is as follows:
I have a C++ application that serves as a device driver, communicating with a serial device connected
through a serial to TCP/IP converter.
The serial protocol requires a lot of single byte messages to be communicated between the device and
my software. I noticed that these small messages are only sent about 3 times after startup, after which they are no longer actually transmitted (checked with wireshark). All the while, the send() method keeps returning > 0, indicating that the message has been copied to it's send buffer.
I'm using blocking sockets.
I discovered this issue because this particular driver eventually has to drop it's connection when the send buffer is completely filled (select() fails due to this after about 5 hours, but it happens much sooner when I reduce SO_SNDBUF size).
I checked, and noticed that when I call send with messages of 2 bytes or larger, transmission never fails.
Any input would be very much appreciated, I am out of ideas how to fix this.
This is a rare case when you should set TCP_NODELAY so that the sends are written individually, not coalesced. But I think you have another problem as well. Are you sure you're reading everything that's being sent back? And acting on it properly? It sounds like an application protocol problem to me.
I'm writing program that should control a piece of scientific hardware over COM-port. The program itself is written in wxWidgets and uses ctb library. To test, it before I connect it to 300k€ equipment, I use com0com (Null-modem emulator) to forward COM2 port. To emulate my hardware I use wxTerminal (COM3). Altogether it works nice. One can debug not only in VS or DB but also see the whole data transfer in wxTerminal.
Now to my problem. I use to send data to COM-port ctb::SerialPort::Write() function.
device->Write( (char*)line.c_str(), line.size() );
However, if I disconnect the connection on the side of wxTerminal (i.e. COM2->NULL) than program hangs in this function.
It's obvious that I should add some function to test if my equipment is still there, but to do it I need to send data-packet to it and expect some answer. So I'm back to the Write().
"Just in case" I've also tried ctb::IOBase::Writev (char ∗ buf, size_t len, unsigned int timeout_in_ms) with timeout set to 100ms and I've still got program hanging in the same line. It's actually expected behavior as in this case timeout means only that the connection line is blocked till whole buffer is transferred or timeout is reached.
Connecting of wxTerminal to COM3 leads to un-freezing of debugger or stand-alone program. The Sun is shining, the birds are singing.
Can somebody give me a hint how to overcome my problem? I'd appreciate if comments would be restrained to wxWidgets-world - I really do not want to re-write whole program with other toolkit.
If you COM port library does not provide effective timeouts on write block, (presumably because of hardware flow-control), you could implement your own by threading off the write. You could use a couple of events/semaphores/condvar/whatever. One to signal to the thread that there is something in a buffer to send and another that you can wait on with a timeout that is signaled by the thread after it has sent the buffer. If the 'ack' wait times out, your COM port is stuck and you can pop up some 'Check cable' messageBox. I don't know what other calls your port lib supports, so I don't know how you could implement flushes/retries.
I'm having a peculiar problem with boost::asio and a boost::asio::serial_port device. The code is finally working pretty well with asynchronous reads and stuff, but I can't figure out how to change the speed of the serial port on the fly.
What I'm trying to do right now is just telling the device connected in my serial port to change the serial port speed to say 38400 baud, then I'm setting my computers serial port to the same speed via:
port_.set_option(boost::asio::serial_port_base::baud_rate(rate));
But what's really happening is that if I do the set_option part, the device never receives the command to change the speed. If I don't do the set_option part the device changes speed correctly. From what I gather what's happening is that the (blocking, synchronous) write puts stuff in the hardware buffer on my computer and returns, then does the set_option which discards the buffer (before it has had time to send data to the device). So I need to think of some way to check if the hardware buffer is empty and the device really has received the command to change the speed, before reconfiguring my computers serial port. I also cannot find any info on if I have to do close() and open() on the port for the speed change to take affect. I'm also wondering if close() discards the stuff in the buffer or not... I'm using a USB->serial port adapter and my platform is Ubuntu 10.10 if it makes any difference.
Have you looked at man 3 termios? It seems tcdrain does what you need
tcdrain() waits until all output
written to the object referred to by
fd has been transmitted.
You can get the native descriptor from the boost::asio::serial_port::native method.
Did you try flushing the buffer or looking for an appropriate flush alternative?
Are the client and server in the same process?
Boost.Asio iostream flush not working?
I have a device that generates messages over a serial port. When I reboot the device, the IO Completion Port stops reading bytes.
The code is calls GetQueuedCompletionStatus():
BOOL bRet = GetQueuedCompletionStatus(
m_hCompletionPort,
&dwBytesTransferred,
&dwCompletionKey,
&pOverlapped,
INFINITE);
PortMon looks like:
...
IRP_MJ_WRITE Serial1 SUCCESS LENGTH: 7 REBOOT.
IRP_MJ_READ Serial1 CANCELLED LENGTH: 1
Logging shows the following result:
bRet=true, dwBytesTransferred=7, pOverlapped=0x0202B028, GetLastError()=997
(sleep forever)
Is there any way to detect this failure and reestablish communications?
I can monitor a heat beat and close/reopen the serial port, but it doesn't seem right that the windows API allows serial communications to silently drop like this.
If you do WaitForSingleObject on the handle for the serial port that you opened to start reading data, does the handle become signalled when the device is rebooted? Maybe this is a way to tell when you need to open the port again?
IO Completion Ports can certainly handle this case without problem. You don't need to close and reopen the device.
The most likely problem in this case is that you have an error on the line (caused by the device reset) that you have not cleared using ClearCommError().
You need to use SetCommState() and SetCommTimeouts() appropriately for your device up front. In the DCB you pass to SetCommState(), you need to set fAbortOnError. If you do dequeue an error you need to call ClearCommError() before you requeue another read.
RE: janm (I can't seem to add a comment to your answer sorry)
I did try setting various flags, including the DCB's fAbortOnError, but GetQueuedCompletionStatus() would still wait infinitely. I also tried periodically timing out the call, and checking the serial port for errors. The serial port always looked fine, yet the disconnection would still permanently break the IO Completion Port. The device rebooting probably creates a transient error state... I say probably, because I've never been able to detect it!
A fellow developer also had a crack at this problem, and they too failed. So we just rewrote the code to use overlapped serial port reads, and now it works fine.
There is probably something, somewhere that we missed... in the end we wasted more time trying to solve the mystery than it took to rewrite the code.