我一直在通過學習使用boost的基本串行終端示例來實現半雙工串行驅動程序: ASIO :: basic_serial_port: http://lists.boost.org/boost-users/att-41140/minicom.cpp回調傳遞給boost :: asio :: async_read_some在boost :: asio :: read_some返回數據時從未調用
我需要異步讀取,但仍然會檢測時,處理程序在主線程中完成,所以我使用boost通過async_read_some與幾個額外的參考參數回調的lambda函數:綁定。處理程序永遠不會被調用,但如果我用read_some函數替換async_read_some函數,它將返回沒有問題的數據。
我相信我全部滿足此功能的必然要求調用處理程序,因爲它們對ASIO同一::看了一些函數返回:
- 緩衝區保持在範圍
- 一個或多個字節是由串行設備
- 在IO服務正在運行
- 端口是開放的,在運行正確的波特率
有沒有人知道我是否錯過了異步讀取的另一個獨特假設,或者如果我沒有正確設置io_service?
下面是我如何使用與async_read_some(http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio/reference/basic_serial_port/async_read_some.html)的代碼示例:
void readCallback(const boost::system::error_code& error, size_t bytes_transfered, bool & finished_reading, boost::system::error_code& error_report, size_t & bytes_read)
{
std::cout << "READ CALLBACK\n";
std::cout.flush();
error_report = error;
bytes_read = bytes_transfered;
finished_reading = true;
return;
}
int main()
{
int baud_rate = 115200;
std::string port_name = "/dev/ttyUSB0";
boost::asio::io_service io_service_;
boost::asio::serial_port serial_port_(io_service_,port_name);
serial_port_.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
boost::thread service_thread_;
service_thread = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
std::cout << "Starting byte read\n";
boost::system::error_code ec;
bool finished_reading = false;
size_t bytes_read;
int max_response_size = 8;
uint8_t read_buffer[max_response_size];
serial_port_.async_read_some(boost::asio::buffer(read_buffer, max_response_size),
boost::bind(readCallback,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
finished_reading, ec, bytes_read));
std::cout << "Waiting for read to finish\n";
while (!finished_reading)
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
std::cout << "Finished byte read: " << bytes_read << "\n";
for (int i = 0; i < bytes_read; ++i)
{
printf("0x%x ",read_buffer[i]);
}
}
結果是回調不打印出任何東西和同時完成循環永遠不會結束!
這裏是我如何使用阻塞read_some功能(boost.org/doc/libs/1_56_0/doc/html/boost_asio/reference/basic_serial_port/read_some.html):從
int main()
{
int baud_rate = 115200;
std::string port_name = "/dev/ttyUSB0";
boost::asio::io_service io_service_;
boost::asio::serial_port serial_port_(io_service_,port_name);
serial_port_.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
boost::thread service_thread_;
service_thread = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
std::cout << "Starting byte read\n";
boost::system::error_code ec;
int max_response_size = 8;
uint8_t read_buffer[max_response_size];
int bytes_read = serial_port_.read_some(boost::asio::buffer(read_buffer, max_response_size),ec);
std::cout << "Finished byte read: " << bytes_read << "\n";
for (int i = 0; i < bytes_read; ++i)
{
printf("0x%x ",read_buffer[i]);
}
}
這個版本打印1發送最多8個字符,阻止發送至少一個字符。
感謝您的回答,它解決了我的示例中的所有問題。關於io_service :: run行爲的答案的鏈接非常具有說明性。這僅僅是一個測試代碼,我的實際代碼基於紡紗循環中主線程作用域中的數據包解析細節實現了一個超時。如果數據進入半雙工總線並且本質上是同步的(只要沒有出現任何問題),使用異步讀取的同步結構是合理的,因此我可以確保超時並清除混亂讀取失敗? – st3am 2014-09-29 02:51:33
我想我明白你在重新檢查同步和異步行爲的用法。看來我應該鏈接異步調用來填充一個緩衝區,然後在發送請求後在同步線程中讀取它。 – st3am 2014-09-29 21:37:38
@ st3am如果您需要超時,則需要異步操作。但是,使用其他線程可能會使解決方案複雜化。考慮檢查官方Boost.Asio [超時示例]中使用的超時方法(http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio/examples/cpp03_examples.html#boost_asio.examples.cpp03_examples .timeouts)。對於半雙工系統,通常可以使用單個線程等待讀取完成或超時,然後響應並重復。 – 2014-09-30 02:06:40