Timing out when writing to serial port while still receiving data
I've created a wrapper class around boost asio's serial_port class: class SerialPort { public: void open(); void send(const std::vector<uint8> &data); void close(); private: void _startReceiving(); boost::asio::serial_port m_serialPort; boost::asio::io_service m_ioService; std::vector<uint8> m_recvBuf; }; The SerialPort class has an 'open' member function that opens the port and begins waiting for data to be received on the serial port. There's also a 'send' member function that writes the specified data to the serial port. Below is the code (running on a separate thread) that waits for data to be received on the serial port: Receive Thread -------------- while (m_recvData) { m_serialPort.async_read_some(boost::asio::buffer(m_recvBuf), boost::bind(&SerialPort::_recvHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); m_ioService.run(); m_ioService.reset(); } The problem I'm experiencing is that when the flow control of the serial port is set to RTS/CTS, and I try and write to the serial port with the cable unplugged or the CTS serial line otherwise low, the call is a blocking call. I realize this is the way it's supposed to work, but I need to make writing to the serial port timeout after a few hundred milliseconds instead of blocking until CTS goes high. So I found code on the boost user's mailing list to do just that (m_writeDoneEvent is a manual reset event): Write Thread ------------ boost::optionalboost::system::error_code timerResult; boost::asio::deadline_timer writeTimer(m_ioService); writeTimer.expires_from_now(milliseconds(100)); writeTimer.async_wait(boost::bind(&SerialPort::_writeDone, this, &timerResult, (std::size_t*)NULLPTR, _1, 0)); boost::optionalboost::system::error_code writeResult; std::size_t bytesWritten; boost::asio::async_write(m_serialPort, boost::asio::buffer(data, length), boost::bind(&SerialPort::_writeDone, this, &writeResult, &bytesWritten, _1, _2)); // Wait for the write to finish, either due to success or timing out. m_writeDoneEvent.wait(); m_writeDoneEvent.unset(); if (writeResult) { // Write completed successfully. writeTimer.cancel(); if (writeResult->value()) { std::ostringstream oss; oss << "Failed to send some or all of the data to " << m_portName << ". Successfully sent " << bytesWritten << " of a possible " << length << " bytes."; throw SerialException(oss.str(), writeResult->value()); } } else if (timerResult) { // Write timed out. Cancel all asynchronous operations (including the // asynchronous call to read). m_serialPort.cancel(); // <==== ***Throws exception*** std::ostringstream oss; oss << "Sending to " << m_portName << " timed out."; throw SerialException(oss.str()); } void SerialPort::_writeDone(boost::optionalboost::system::error_code *errorToSet, std::size_t *bytesWrittenToSet, const boost::system::error_code &error, std::size_t bytesWritten) const { if (error != boost::asio::error::operation_aborted) { // Set the error code so the caller knows why the asynchronous write //operation finished. errorToSet->reset(error); if (bytesWrittenToSet != NULLPTR) { *bytesWrittenToSet = bytesWritten; } // Signal to the caller that the write operation is complete. m_writeDoneEvent.set(); } } However, when the write operation on the serial port times out, the call to m_serialPort.cancel() above throws an exception, saying 'The attempted operation is not supported for the type of object referenced'. Looking at the source code, the comment where the exception is thrown says that it's an unsafe operation to call cancel on the IO service from a thread when work has been given to the IO service from a different thread. This obviously fits my case - I've submitted an async_read on the Receive thread and I'm trying to cancel all asynchronous work on the Write thread. Is it possible to have a thread always running that's waiting for data to be received on the serial port as well as have a write thread that timeouts? If so, where did I go wrong above? Thanks, Russ
participants (1)
-
Goetz, Russ