【问题标题】:boost::asio::serial_port reading after reconnecting Deviceboost::asio::serial_port 重新连接设备后读取
【发布时间】:2010-10-07 03:57:04
【问题描述】:

我在从 GPS 设备(USB 串行)读取 boost::asio::serial_port 类时遇到问题。连接设备并从中读取工作正常,但是当我断开并重新连接设备时,read_some 不会从端口读取任何字节。

由于 boost 无法检测到串行端口已消失( is_open() 返回 true ),因此当我没有获取数据时,我会定期取消()、关闭()和打开( GPS_PORT )设备,重置途中的港口选项。但这也无济于事,输入缓冲区保持为空。

我是否遗漏了什么,或者做错了什么,或者这是 asio 中的错误?是否有检测端口消失的标准方法?

【问题讨论】:

    标签: c++ boost serial-port boost-asio


    【解决方案1】:

    尽管 asio boost::ip:tcp 很容易处理,但我认为在 Windows 7 上处理 boost serial_port 需要特别小心。
    我遇到了类似的问题,通过重置 boost::asio::io_serviceio_service_.reset() 的实例解决了这个问题。
    我可以异步读取数据,但在第二次尝试时它无法执行相同的操作。
    其实是read函数本身没有问题,注册异步读取失败,导致第二次尝试立即从boost::asio::io_service::run()返回。

    我不确定这与原始海报的问题是否相同,因为我正在使用这些天更新的 boost 库。
    无论如何,这是我的解决方案:

    // 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.
    

    【讨论】:

      【解决方案2】:

      很难说你的具体原因是什么,但实践表明你经常需要在你的串口上禁用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;
        }
      

      ,我。 e.如果CloseHandle() 由于某种原因失败(或挂起),则内部句柄值不会分配给INVALID_HANDLE_VALUEis_open() 将始终返回true

      要解决此问题,请在 close()'ing 之后检查 is_open(),如果它返回 true,则销毁 boost::asio::serial_port 的整个实例并重新创建它。

      【讨论】:

      • 谢谢,我会试试看 - 但是第一次打开设备时读取不应该也会失败吗?
      • 当驱动程序说 RTS 关闭时读取将失败。何时发生取决于驱动程序的实现。顺便说一句,当读取开始成功时:重启后,设备重新连接后,超时后?
      • 好的,我只是尝试设置 RTS_CONTROL_DISABLE - 它不会改变行为。 boost::serial_port::is_open 返回 true,但不会开始读取。行为是:连接 GPS,启动工具 - 读取,断开 GPS,读取停止,再次连接,仍然不读取。重启工具:再次工作。
      • 谢谢,在 close() 之后检查 is_open() 然后创建一个新实例解决了这个问题!
      【解决方案3】:

      通常,当read_some 无法再准备好时,您应该得到boost::system::system_error 类型的异常。尝试改用read,它可能会返回错误,而不仅仅是返回。你也可以试试异步方法;在这种情况下,当设备断开连接时,处理程序应该得到一个错误对象。

      或者,您可以使用native() 函数获取端口句柄并在其上调用 ClearCommError()。它可能会返回错误。

      【讨论】:

      • 看起来不错 - 我正在检查错误代码,但我还没有注意到 native() 方法......这样我应该能够以某种方式说服串行端口读取: )
      • 也许您只是没有注意到设备被拔出,因为 USB 驱动程序没有向操作系统报告这一点。在这种情况下:运气不好:/
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多