2009-02-12 386 views
2

我有一个问题,从GPS设备(USB串行)读取boost :: asio :: serial_port类。连接设备并从中读取可以正常工作,但当断开连接并重新连接设备时,read_some不会从端口读取任何字节。由于boost并没有检测到串口已经消失(is_open()返回true),所以当我没有获取数据时,我定期的取消(),关闭()并打开(GPS_PORT)设备,在途中重置端口选项。但是这也没有帮助,输入缓冲区保持空白。boost :: asio :: serial_port重新连接设备后读取

我错过了什么,或者做错了什么,或者这是asio中的错误?有没有一种标准的方法来检测端口已经不存在了?

回答

3

很难说你的情况是什么原因,但实践表明你经常需要在串口上禁用RTS灵敏度。

RTS是真实的针脚RS-232当另一侧的设备打开时,该接口处于打开状态。

serial_port::read_some调用看起来在这个信号上的基础Windows API函数。因为你没有真正的RS-323设备,所以你需要依赖这个信号的驱动器仿真,这可能是错误的(不幸的是经常是这样)。

要禁用它,请调用serial_port::set_option(DCB)并将RTSControl设置为RTS_CONTROL_DISABLE

如果close()'您的手柄没有帮助,这可能是boost的问题。 close()的源代码如下所示:

boost::system::error_code close(implementation_type& impl, 
     boost::system::error_code& ec) 
    { 
    if (is_open(impl)) 
    { 
     if (!::CloseHandle(impl.handle_)) 
     { 
     DWORD last_error = ::GetLastError(); 
     ec = boost::system::error_code(last_error, 
      boost::asio::error::get_system_category()); 
     return ec; 
     } 

     impl.handle_ = INVALID_HANDLE_VALUE; 
     impl.safe_cancellation_thread_id_ = 0; 
    } 

    ec = boost::system::error_code(); 
    return ec; 
    } 

,i。即如果CloseHandle()由于某种原因(或挂起)失败,则内部句柄值不会被分配给INVALID_HANDLE_VALUE,并且is_open()将始终返回true

要解决这个问题,之后close()“ING检查is_open(),如果返回true,破坏boost::asio::serial_port整个实例,并重新创建它。

+0

谢谢,我想试试 - 但不应在设备第一次打开时的读取也失败了呢? – VolkA 2009-02-12 13:48:55

+0

当驾驶员说RTS关闭时,读取将失败。何时发生取决于驱动程序的实现。顺便说一句,当读取开始成功:重新启动,设备重新连接后,超时后? – Quassnoi 2009-02-12 13:53:00

1

正常情况下,如果read_some无法准备好,则应该得到boost::system::system_error类型的例外。请尝试使用read代替,也许它会返回一个错误并且不会返回。你也可以尝试异步方法;在这种情况下,处理程序应在设备断开连接时收到错误对象。

也可以使用native()函数获取端口的句柄,并调用ClearCommError()。它可能会返回错误。

1

尽管易于操作ASIO boost::ip:tcp,我觉得处理升压serial_port需要特别注意在Windows 7
我有类似的问题,挺过来了通过重置的boost::asio::io_serviceio_service_.reset()一个实例。
我可以异步读取数据,但无法从第二次尝试中做同样的事情。
事实上,读取函数本身没有问题,注册异步读取失败,导致第二次尝试立即从boost::asio::io_service::run()返回。

我不确定这与原来的海报有什么相同的问题,因为我现在使用的是较新的增强库。
反正这里是我的解决方案:

// port open step 
port_ = boost::shared_ptr<boost::asio::serial_port> 
     (new boost::asio::serial_port(io_service_)); 
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service_)); 
port_->async_read_some(....); 
....... 

// port close step 
port_->cancel(); 
port_->close(); 
port_.reset(); 

io_service_.stop(); 
io_service_.reset(); // <-- IMPORTANT: this makes serial_port works in repeat use. 
相关问题