[Boost-bugs] [Boost C++ Libraries] #11721: boost::asio::serial_port bug in win10

Subject: [Boost-bugs] [Boost C++ Libraries] #11721: boost::asio::serial_port bug in win10
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2015-10-13 07:57:36


#11721: boost::asio::serial_port bug in win10
--------------------------+----------------------------
 Reporter: admin@… | Owner: chris_kohlhoff
     Type: Bugs | Status: new
Milestone: Boost 1.59.0 | Component: asio
  Version: Boost 1.59.0 | Severity: Problem
 Keywords: serial_port |
--------------------------+----------------------------
 åœ¨æœ€è¿‘写一些串口操作的程序时使用了 boost::asio::serial_port 来操作串口
 ä½†å½“尝试打开串口的时候出现了错误。下面是我的测试代码:
 {{{#!cpp
 boost::asio::io_service _io_service;
 const std::string devname = "COM3";
 try
 {
         boost::asio::serial_port serial(_io_service);
         serial.open(devname);// throw error every times.
         if (serial.is_open()) {
                 std::cout << devname << " serial open successed." <<
 std::endl;
         }
         else {
                 std::cout << devname << " serial open failed!" <<
 std::endl;
         }
 }
 catch (const std::exception& ex)
 {
         std::cout << ex.what() << std::endl;// GetLastError() == 87
 }
 }}}
 æ¯æ¬¡éƒ½ä¼šå‡ºçŽ°é”™è¯¯87。即 GetLastError() 的结果为 87
 äºŽæ˜¯è·Ÿè¿›ä»£ç é‡Œé¢è°ƒè¯•è¿½åˆ°äº† win_iocp_serial_port_service::open 函数里

 win_iocp_serial_port_service::open 函数的实现如下:
 {{{#!cpp
 boost::system::error_code win_iocp_serial_port_service::open(
         win_iocp_serial_port_service::implementation_type& impl,
         const std::string& device, boost::system::error_code& ec)
 {
         if (is_open(impl))
         {
                 ec = boost::asio::error::already_open;
                 return ec;
         }

         std::string name = (device[0] == '\\') ? device : "\\\\.\\" +
 device;

         ::HANDLE handle = ::CreateFileA(name.c_str(),
                 GENERIC_READ | GENERIC_WRITE, 0, 0,
                 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
         if (handle == INVALID_HANDLE_VALUE)
         {
                 DWORD last_error = ::GetLastError();
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         using namespace std;
         ::DCB dcb;
         memset(&dcb, 0, sizeof(DCB));
         dcb.DCBlength = sizeof(DCB);
         if (!::GetCommState(handle, &dcb))
         {
                 DWORD last_error = ::GetLastError();
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         dcb.fBinary = TRUE;
         dcb.fDsrSensitivity = FALSE;
         dcb.fNull = FALSE;
         dcb.fAbortOnError = FALSE;

         if (!::SetCommState(handle, &dcb))
         {
                 DWORD last_error = ::GetLastError();// lee: error is
 here!!!
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         ::COMMTIMEOUTS timeouts;
         timeouts.ReadIntervalTimeout = 1;
         timeouts.ReadTotalTimeoutMultiplier = 0;
         timeouts.ReadTotalTimeoutConstant = 0;
         timeouts.WriteTotalTimeoutMultiplier = 0;
         timeouts.WriteTotalTimeoutConstant = 0;
         if (!::SetCommTimeouts(handle, &timeouts))
         {
                 DWORD last_error = ::GetLastError();
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         if (handle_service_.assign(impl, handle, ec))
                 ::CloseHandle(handle);
         return ec;
 }
 }}}
 å‘现每次在第一次 SetCommState 的时候总是会报错并离开。
 äºŽæ˜¯æŸ¥çœ‹äº†å‰é¢é€šè¿‡ GetCommState 获取到的 dcb 的值。
 å‘现 dcb.BaudRate == 0 时无法 SetCommState 成功
 ä¹Ÿå°±æ˜¯è¯´åœ¨æœ‰äº›è®¾å¤‡ä¸­èŽ·å–不到 dcb.BaudRate 这个值。

 == 下面是我自己的解决办法: ==
 åœ¨ win_iocp_serial_port_service.ipp 文件的88行左右添加
 {{{#!cpp
 if (dcb.BaudRate == 0) dcb.BaudRate = 115200;
 }}}

 ä¿®æ”¹åŽçš„ win_iocp_serial_port_service::open 函数完整代码如下:
 {{{#!cpp
 boost::system::error_code win_iocp_serial_port_service::open(
         win_iocp_serial_port_service::implementation_type& impl,
         const std::string& device, boost::system::error_code& ec)
 {
         if (is_open(impl))
         {
                 ec = boost::asio::error::already_open;
                 return ec;
         }

         std::string name = (device[0] == '\\') ? device : "\\\\.\\" +
 device;

         ::HANDLE handle = ::CreateFileA(name.c_str(),
                 GENERIC_READ | GENERIC_WRITE, 0, 0,
                 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
         if (handle == INVALID_HANDLE_VALUE)
         {
                 DWORD last_error = ::GetLastError();
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         using namespace std;
         ::DCB dcb;
         memset(&dcb, 0, sizeof(DCB));
         dcb.DCBlength = sizeof(DCB);
         if (!::GetCommState(handle, &dcb))
         {
                 DWORD last_error = ::GetLastError();
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         dcb.fBinary = TRUE;
         dcb.fDsrSensitivity = FALSE;
         dcb.fNull = FALSE;
         dcb.fAbortOnError = FALSE;
         if (dcb.BaudRate == 0) dcb.BaudRate = 115200; // add lee
 2015.10.10. 解决dcb.BaudRate为0时无法成功SetCommStateçš„BUG
         if (!::SetCommState(handle, &dcb))
         {
                 DWORD last_error = ::GetLastError();
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         ::COMMTIMEOUTS timeouts;
         timeouts.ReadIntervalTimeout = 1;
         timeouts.ReadTotalTimeoutMultiplier = 0;
         timeouts.ReadTotalTimeoutConstant = 0;
         timeouts.WriteTotalTimeoutMultiplier = 0;
         timeouts.WriteTotalTimeoutConstant = 0;
         if (!::SetCommTimeouts(handle, &timeouts))
         {
                 DWORD last_error = ::GetLastError();
                 ::CloseHandle(handle);
                 ec = boost::system::error_code(last_error,
                         boost::asio::error::get_system_category());
                 return ec;
         }

         if (handle_service_.assign(impl, handle, ec))
                 ::CloseHandle(handle);
         return ec;
 }
 }}}

 == 测试环境 ==
 ||= 说明 =||= 参数 =||
 || 操作系统 || Windows10 专业版 x64 ||
 || 开发环境 || Microsoft Visual Studio Community 2013 Version 12.0.40629.00
 Update 5 ||
 || Boost版本 || boost_1.59.0 ||

 == 结束语 ==
 ä»¥ä¸Šåªæ˜¯è‡ªå·±çš„猜测,并不一定是完全正确的。如有任何错误,请联系并告诉我。我将尽快修改,不胜感激。

 == 我的原文 ==
 http://www.leelib.com/2015/10/10/win10-boost-asio-serial-port-bug.html

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/11721>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC