boost :: asio :: serial_port чтение после повторного подключения устройства - PullRequest
2 голосов
/ 12 февраля 2009

У меня проблема с чтением класса boost :: asio :: serial_port с устройства GPS (USB-Serial). Подключение устройства и чтение с него работает нормально, но когда я отключаю и снова подключаю устройство, read_some не считывает байты из порта.

Поскольку boost не показывает, что последовательный порт пропал (is_open () возвращает true), я периодически отменяю (), закрываю () и открываю (GPS_PORT) устройство, когда не получаю данные, сбрасываю варианты портов в пути. Но это тоже не помогает, входной буфер остается пустым.

Я что-то упускаю, или делаю что-то не так, или это ошибка в asio? Есть ли стандартный способ определить, что порт исчез?

Ответы [ 3 ]

3 голосов
/ 12 февраля 2009

Трудно сказать, какова точная причина в вашем случае, но практика показывает, что вам часто нужно отключить 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;
  }

, т.е. е. если по какой-либо причине CloseHandle() не удается (или зависает), внутреннему значению дескриптора не присваивается значение INVALID_HANDLE_VALUE и is_open() всегда будет возвращать true.

Чтобы обойти это, отметьте is_open() сразу после close() 'ing, и если он вернет true, уничтожьте весь экземпляр boost::asio::serial_port и создайте его снова.

1 голос
/ 26 мая 2016

Несмотря на простоту управления asio boost::ip:tcp, я думаю, что обработка boost serial_port требует особой осторожности в Windows 7.
У меня похожая проблема, и преодолел ее, сбросив экземпляр boost::asio::io_service, io_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.
1 голос
/ 12 февраля 2009

Обычно вы должны получить исключение типа boost::system::system_error, когда read_some больше не может быть готов. Попробуйте вместо этого использовать read, возможно, он возвращает ошибку, а не просто возвращает. Вы также можете попробовать асинхронные методы; в этом случае обработчик должен получить объект ошибки при отключении устройства.

В качестве альтернативы вы можете получить дескриптор порта с помощью функции native() и вызвать ClearCommError () для этого. Может вернуть ошибку.

...