重新连接设备后 boost::asio::serial_port 读取

发布于 2024-07-13 17:29:18 字数 311 浏览 8 评论 0原文

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

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

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

I have a problem with the boost::asio::serial_port class reading from a GPS device (USB-Serial). Connecting the device and reading from it works fine, but when I disconnect and reconnect the device, read_some doesn't read any bytes from the port.

As boost doesn't seam to detect that the serial port is gone ( is_open() returns true ), I periodically cancel(), close() and open( GPS_PORT ) the device when I don't get data, resetting the port options on the way. But this doesn't help either, the input buffer stays empty.

Am I missing something, or doing something wrong, or is this a bug in asio? Is there a standard way to detect that the port is gone?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

多孤肩上扛 2024-07-20 17:29:18

很难说出您的情况的确切原因是什么,但实践表明您经常需要禁用串行端口上的 RTS 敏感性。

RTS 是真正的 RS-232 接口上的引脚,当另一侧的设备打开时,该引脚就会打开。

serial_port::read_some 调用查看此信号的底层 Windows API 函数。

由于您没有真正的 RS-323 设备,因此您需要依赖该信号的驱动程序模拟,这可能会出现错误(不幸的是经常出现错误)。

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

如果 close()'ing 您的句柄没有帮助,则可能是 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;
  }

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

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

It's hard to say what is the exact reason in your case, but practice shows that you often need to disable RTS sensitivity on your serial port.

RTS is a pin on real RS-232 interface that is on when a device on the other side is on.

serial_port::read_some invokes underlying Windows API function that looks on this signal.

As you don't have the real RS-323 device, you need to rely on the driver emulation of this signal which may be faulty (and unfortunately often is).

To disable it, invoke serial_port::set_option(DCB) with RTSControl set to RTS_CONTROL_DISABLE.

If close()'ing your handle doesn't help, it may be a problem with boost. Source code for close() looks like this:

  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. e. if CloseHandle() fails for some reason (or hangs), the internal handle value is not beign assigned to INVALID_HANDLE_VALUE and is_open() will always return true.

To work around this, check is_open() right after close()'ing, and if it returns true, destroy whole instance of boost::asio::serial_port and create it again.

娇纵 2024-07-20 17:29:18

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

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

Normally you should get an exception of type boost::system::system_error when read_some cannot ready anymore. Try using read instead, maybe it returns an error and doesn't just return. You could also try the async methods; in this case the handler should get an error object when the device was disconnected.

Alterantively you could get the handle to the port using the native() function and call ClearCommError() on that. It might return the error.

原来分手还会想你 2024-07-20 17:29:18

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

Despite of the easy handling of asio boost::ip:tcp, I think handling boost serial_port requires special caution on Windows 7.
I got similar problem and got over it by resetting an instance of boost::asio::io_service, io_service_.reset().
I can read data asynchronously but it fails to do same thing from the second try.
In fact, it was no problem of read function itself, registering asynchronous read failed, which led immediate return from boost::asio::io_service::run() in second try.

I am not sure this is the same problem as original poster had because I am using newer boost library of these days.
Anyway here is my solution:

// 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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文