-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
flush() does not wait on Windows #118
Comments
Hi,
wbr Kusti |
Many thanks for your quick response. About point 5), I do not want my application to block the serial port under Windows for a long time. Normally, the user spends some time filling in the data and clicking on various options, and then presses the "Send" button once. Therefore, I think that opening and closing the port is justified in this scenario. Sometimes you need to change the cable to another device and use another one of the small applications. You may end up with 2 them open on your PC. Having to press some "connect" and "disconnect" button every time, so that each application locks and releases the serial port, would probably inconvenience my users. About point 6), I did try searching the Internet, but I could not find anybody complaining that FlushFileBuffers does not work. I do not know much about the Windows API, but I have some concerns about a possible interaction of FlushFileBuffers() with the overlapped I/O mode. After all, overlapping tends to mean "do no block". I found the following comment in the following page: http://forums.codeguru.com/showthread.php?147771-Serial-port-question in this case, you might need to setup an event and WaitForSingle/MultipleObject() until output is done. If FlushFileBuffers() always blocks, then there is no easy wait to asynchronously wait for it to finish. If it does start the flush in an "overlapped" manner, then the code should wait for it to finish before returning, shouldn't it? About point 3), I can play a little with OUTPUT_BUFFER_EMPTY. Sun's original documentation states that this is an optional event that may not always be available. Can you make a statement about it in PureJavaComm? I mean, is it always available, and if not, on which platforms? I'll post again when I have done some more testing. Thanks again, |
There is one thing I haven't quite understood yet in src/jtermios/windows/JTermiosImpl.java . Please keep in mind that I am struggling here, because I do not really known that much about the Windows API. Routine write() will start an overlapped write to the serial port, but will not wait for it to complete. Say that the same thread quickly calls flush() afterwards, which goes down to tcdrain() and then to FlushFileBuffers(). Will the data written in an overlapped manner be considered to be in the serial port buffer already? Or is there a race condition here? I mean, should tcdrain() start in the same way as write(), by checking m_WritePending first, and waiting for any in-flight overlapped operation to finish, before calling FlushFileBuffers()? |
That is a good question! Obviously I expected that any write submitted should eventually complete and thus the as it is should work. But, given the rather complex and cumbersome Windows API (why could they not just copy *nix) I would not be too surprised if what you speculate is actually true. Feel free to test that by adding that check and wait there before FlushFileBuffers()s, that would be a valuable data point re debugging. |
For the record, OUTPUT_BUFFER_EMPTY is not enough. It does improve the situation quite a lot: instead of letting only the first byte through, waiting for this event lets the first data chunks out, and only loses the last chunk. Evidence is piling up that flush() is not waiting correctly. I am using the compiled .jar at the moment. The further testing you suggested will require changes to my NetBeans projects. I think that will have to wait until after the Christmas break. Hopefully you will have uploaded the latest sources then, so that we will be at the same level. |
I have investigated a little further:
This all happens with a single call to write for 1813 bytes, which is below the internal buffer size, so there is no internal data fragmentation at all.
I cannot find a way to avoid losing the bytes at the end, other than just waiting for a while before closing the port, which is not a very elegant solution.
Best regards, |
I just pushed 1.0.2 rebranded as 1.0.3 cause I could not be sure that the 1.0.2 binaries out there were 100% compatible with my local and github source code. But now everything is hopefully in sync. |
First of all, many thanks for PureJavaComm. I have been using it for years without problems.
I am writing a number of small JavaFX applications that send data to rather simple serial port devices. The devices do not normally respond. I normally test the applications on Linux (my main development platform) and on a Windows 7 PC.
I recently started seeing problems on several Windows 7 PCs. The data sent is abruptly cut off. The other side just gets one byte, or a few of them. This happens with as little as 3 bytes of data.
Interestingly enough, this issue does not happen with an FTDI-based USB to RS-232 adapter. But it happens with an FTDI-based USB to RS-485 adapter. And with most other RS-232 adapters too, for example, with one based on a cp210x chip from Silicon Labs, or with Prolific-based adapters.
The Linux PC is fine, even with those same adapters, and with a virtual serial port too (created with socat PTY).
I am using PureJavaComm version 1.0.2 . By the way, I find it somewhat disturbing that the source code version in GitHub is not up to date with the binary release. I noticed because there is no release tag for version 1.0.2. It is also mentioned in the following issue: #116
I am also using JNA version 4.5.2. JNA has been upgraded recently quite a lot for a library described as "mature". I wonder whether I should upgrade it again, and whether that would impact PureJavaComm. I could not find any mention of what JNA versions PureJavaComm has been tested against, or whether the JNA version does not matter much.
This is what my source code looks like:
ByteArrayOutputStream bos = blah blah...
OutputStream outputStream = serialPort.getOutputStream();
outputStream.write( bos.toByteArray() );
outputStream.flush();
serialPort.close();
On Linux, and on Windows with the FTDI adapter, the call to flush() waits until all data has been sent. But on Windows, with the other RS-232 or RS-485 adapters, it does not wait. The call to close() apparently drops most of the outgoing bytes.
I have looked at the source code behind flush(), and it does check for eventual errors coming from tcdrain(). But I am not seeing any exceptions.
Can anyone help me with this issue?
I have been thinking about implementing a workaround with the OUTPUT_BUFFER_EMPTY event. But all I could find were incomplete examples. What is the best way to block a thread until all bytes have been sent? Are such events called on a separate thread, and do I need to worry about synchronisation? Is OUTPUT_BUFFER_EMPTY only for the internal buffer, or it is fired when the last bit has actually been sent over the serial interface?
Or is there any way you can poll the serial port to see if all data has been sent?
Thanks in advance,
rdiez
The text was updated successfully, but these errors were encountered: