Pergunta

Eu estou tentando usar boost :: asio a ler e escrever a partir de um dispositivo em uma porta serial. Ambos boost :: asio: read () e boost :: asio :: serial_port :: read_some () bloco quando não há nada para ler. Em vez disso eu gostaria de detectar essa condição e escrever um comando para a porta para o arranque do dispositivo.

Como posso quer detectar que não há dados disponíveis?

Se necessário, posso fazer tudo de forma assíncrona, gostaria apenas em vez evitar a complexidade extra, se eu puder.

Foi útil?

Solução

Você tem um par de opções, na verdade. Você pode usar a porta serial é construído em função async_read_some, ou você pode usar o boost::asio::async_read função stand-alone (ou async_read_some).

Você ainda vai correr em uma situação em que você está efetivamente "bloqueado", uma vez que nenhum destes irá chamar o callback a menos que (1) os dados foram lidos ou (2) ocorre um erro. Para contornar este problema, você vai querer usar um objeto deadline_timer para definir um tempo limite. Se o tempo limite dispara em primeiro lugar, não há dados disponíveis. Caso contrário, você vai ter lido dados.

A complexidade não é realmente tão ruim assim. Você vai acabar com dois retornos de chamada com comportamento similar. Se quer a "ler" ou as "timeout" fogos de retorno de chamada com um erro, você sabe que é o perdedor corrida. Caso um dos dois incêndios sem um erro, então você sabe que é o vencedor da corrida (e você deve cancelar a outra chamada). No lugar onde você teria a sua chamada de bloqueio para read_some, agora você vai ter uma chamada para io_svc.run(). Sua função ainda irá bloquear como antes quando ele chama run, mas desta vez você controlar a duração.

Aqui está um exemplo:

void foo()
{
  io_service     io_svc;
  serial_port    ser_port(io_svc, "your string here");
  deadline_timer timeout(io_svc);
  unsigned char  my_buffer[1];
  bool           data_available = false;

  ser_port.async_read_some(boost::asio::buffer(my_buffer),
      boost::bind(&read_callback, boost::ref(data_available), boost::ref(timeout),
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));
  timeout.expires_from_now(boost::posix_time::milliseconds(<<your_timeout_here>>));
  timeout.async_wait(boost::bind(&wait_callback, boost::ref(ser_port),
                  boost::asio::placeholders::error));

  io_svc.run();  // will block until async callbacks are finished

  if (!data_available)
  {
    kick_start_the_device();
  }
}

void read_callback(bool& data_available, deadline_timer& timeout, const boost::system::error_code& error, std::size_t bytes_transferred)
{
  if (error || !bytes_transferred)
  {
    // No data was read!
    data_available = false;
    return;
  }

  timeout.cancel();  // will cause wait_callback to fire with an error
  data_available = true;
}

void wait_callback(serial_port& ser_port, const boost::system::error_code& error)
{
  if (error)
  {
    // Data was read and this timeout was canceled
    return;
  }

  ser_port.cancel();  // will cause read_callback to fire with an error
}

Isso deve começar com apenas alguns ajustes aqui e ali para atender às suas necessidades específicas. Espero que isso ajude!

Outra nota: Não há tópicos extras eram necessárias para lidar com as chamadas de retorno. Tudo é tratado dentro da chamada para run(). Não tenho certeza se já estivesse ciente disso ...

Outras dicas

É realmente muito mais simples do que as respostas aqui têm implícita, e você pode fazê-lo de forma síncrona:

Suponha que a sua leitura bloqueio foi algo como isto:

size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);

Em seguida, você substituí-lo com

socket.non_blocking(true);
size_t len = 0;
error = boost::asio::error::would_block;
while (error == boost::asio::error::would_block)
    //do other things here like go and make coffee
    len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint, 0, error);
std::cout.write(recv_buf.data(), len);

Você utiliza o formulário sobrecarregado alternativa de receive_from que quase toda a enviar / receber métodos têm. Eles infelizmente tomar um argumento flags, mas 0 parece funcionar bem.

Você tem que usar a função-livre asio :: async_read.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top