[ASIO] Problem with reading of serial ports using ASIO
Hi All, I'm having some problems using Boost ASIO on Windows XPSP3, 32 bit. I'm trying to set-up an asynchronous read from a serial port on the computer (actually a USB port masquerading as a serial port). The code is at http://gist.github.com/634618 We regularly call the function PCTimeoutUart::wait( iseSize_t len, uint32 timeoutInMS ) which wraps the calls to the boost asio libraries. This creates a deadline_timer, and binds it to our timeout callback (PCTimeoutUart::finishedTimer) It also calls async_read_some on the boost::asio::serial_port object m_port to read the required length, and binds that to the PCTimeoutUart::finishedRead callback. We call the runone() function on m_io, which is declared in the header as a boost::asio::io_service and has been passed to both the timer and serial port's constructors. We continually call this in a loop until either m_timedOut has been set by the asynchronous call back to PCTimeoutUart::finishedTimer or m_finishedRead has been set via the call back to PCTimeoutUart::finishedRead Normally, this works well. However, there are certain scenarios when it fails to write anything to the buffer, despite the fact that finishedRead() is called with error = 0 and the correct length . I've checked by initializing the buffers with a couple of different values and each time, it's clear that the buffer is being passed back without those values being altered. Strangely, it is always when the string sent by the external device is '\r\nNACK:XX\r\n' where XX is a 2 character ascii number. I've got portmon running on the serial port and it confirms that the data has been correctly received from the external device. We've debugged it as far as putting a break-point on line 71 and at that point can see that the system thinks that a read is complete, n bytes have been returned, but only some of those bytes are in buffer. If anyone could offer any views on why we may be having problems, or places that we could look, then that would be very much appreciated. Thanks in advance, Jim
We regularly call the function PCTimeoutUart::wait( iseSize_t len, uint32 timeoutInMS ) which wraps the calls to the boost asio libraries.
This creates a deadline_timer, and binds it to our timeout callback (PCTimeoutUart::finishedTimer) It also calls async_read_some on the boost::asio::serial_port object m_port to read the required length, and binds that to the PCTimeoutUart::finishedRead callback.
We call the runone() function on m_io, which is declared in the header as a boost::asio::io_service and has been passed to both the timer and serial port's constructors.
We continually call this in a loop until either m_timedOut has been set by the asynchronous call back to PCTimeoutUart::finishedTimer or m_finishedRead has been set via the call back to PCTimeoutUart::finishedRead
Normally, this works well. However, there are certain scenarios when it fails to write anything to the buffer, despite the fact that finishedRead() is called with error = 0 and the correct length .
I don't know whether it's related or not (most likely not), but it seems that the following code is dangerous, as you delete the buffer without waiting for the async read completion. You assume that after you call cancel(), the buffer won't be used anymore by the async operation -- which is not obvious, imho. if( m_timedOut ) { m_port.cancel(); delete[] buffer; return false; }
Igor R
We regularly call the function PCTimeoutUart::wait( iseSize_t len, uint32 timeoutInMS ) which wraps the calls to the boost asio libraries.
This creates a deadline_timer, and binds it to our timeout callback (PCTimeoutUart::finishedTimer) It also calls async_read_some on the boost::asio::serial_port object m_port to read the required length, and binds that to the PCTimeoutUart::finishedRead callback.
We call the runone() function on m_io, which is declared in the header as a boost::asio::io_service and has been passed to both the timer and serial port's constructors.
We continually call this in a loop until either m_timedOut has been set by the asynchronous call back to PCTimeoutUart::finishedTimer or m_finishedRead has been set via the call back to PCTimeoutUart::finishedRead
Normally, this works well. However, there are certain scenarios when it fails to write anything to the buffer, despite the fact that finishedRead() is called with error = 0 and the correct length .
I don't know whether it's related or not (most likely not), but it seems that the following code is dangerous, as you delete the buffer without waiting for the async read completion. You assume that after you call cancel(), the buffer won't be used anymore by the async operation -- which is not obvious, imho.
if( m_timedOut ) { m_port.cancel(); delete[] buffer; return false; } _______________________________________________ Boost-users mailing list Boost-users <at> lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Thanks Igor and you were virtually bang on. For those who are interested, the problems are at line 52 and line 72 - i.e. once we've had a callback from either the timer or the serial port, we immediately return from the function without waiting for the other async process to complete. I believe that what was happening was that we were receiving data at about the same time as the timeout fired and thus it was interrupting the reception of data. Because we immediately returned, we didn't give the in-process read request chance to finish. I've changed this now to only exit the while(m_io.run_one()) loop (line 46) once we've received confirmation that both the timer and port callbacks have fired. (One will have fired normally, and the second will fire as a result of calling cancel() in the relevant callback.) Only at that point do we return with the received data. Thanks again for your help! Jim
participants (2)
-
Igor R
-
Jim Donaldson