Pergunta

Eu tenho um problema com o boost :: asio :: leitura classe serial_port de um dispositivo GPS (USB-Serial). Ligar o dispositivo e leitura de funciona bem, mas quando eu desligar e voltar a ligar o dispositivo, read_some não lê bytes da porta.

Como impulso não costura para detectar que a porta serial está desaparecido (nome esta_aberta () retorna true), eu periodicamente cancelar (), close () e aberto (GPS_PORT) o dispositivo quando eu não obter dados, redefinindo as opções de porta no caminho. Mas isso não quer ajudar, a entrada tampão estadias esvaziar.

Estou faltando alguma coisa, ou fazendo algo errado, ou este é um bug no asio? Existe uma maneira padrão para detectar que a porta se foi?

Foi útil?

Solução

É difícil dizer o que é a razão exata no seu caso, mas a prática mostra que muitas vezes você precisa desativar sensibilidade RTS em sua porta serial.

RTS é um pino na interface verdadeira RS-232 que é quando um dispositivo do outro lado está ligado.

invoca serial_port::read_some subjacentes função Windows API que olhares sobre esse sinal.

Como você não tem o dispositivo RS-323 real, você precisa contar com a emulação condutor deste sinal que pode estar com defeito (e, infelizmente, muitas vezes é).

Para desativá-lo, invoque serial_port::set_option(DCB) com o conjunto RTSControl para RTS_CONTROL_DISABLE.

Se close()'ing seu punho não ajudar, pode haver um problema com boost. O código-fonte para olhares close() assim:

  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. se CloseHandle() falhar por algum motivo (ou trava), o valor do identificador interno não é beign atribuído a INVALID_HANDLE_VALUE e is_open() sempre retornará true.

Para contornar isso, certo verificação is_open() após close()'ing, e se ele retorna true, destruir toda instância de boost::asio::serial_port e criá-lo novamente.

Outras dicas

Normalmente, você deve obter uma exceção do tipo boost::system::system_error quando read_some não pode preparar mais. Tente usar read em vez disso, talvez ele retorna um erro e não apenas retornar. Você também pode tentar os métodos assíncronos; neste caso, o manipulador deve obter um objeto de erro quando o dispositivo foi desconectado.

Alterantively você poderia obter o identificador para a porta usando a função native() e chamar ClearCommError () sobre isso. Ele pode retornar o erro.

Apesar do fácil manuseio de asio boost::ip:tcp, acho que lidar com impulso serial_port requer um cuidado especial no Windows 7.
Eu tenho problema semelhante e tem sobre ele, redefinindo uma instância de boost::asio::io_service , io_service_.reset().
Sou capaz de ler dados de forma assíncrona, mas não o faça mesma coisa a partir da segunda tentativa.
Na verdade, não foi um problema da própria função de leitura, registrar leitura assíncrona falhou, o que levou o retorno imediato de boost::asio::io_service::run() na segunda tentativa.

Eu não estou certo de que este é o mesmo problema como o cartaz original tinha porque eu estou usando mais recente biblioteca de impulso destes dias.
De qualquer forma aqui está a minha solução:

// 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.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top