Domanda

Sto tentando di utilizzare boost :: asio per leggere e scrivere da un dispositivo su una porta seriale. Entrambi i blocchi boost :: asio: read () e boost :: asio :: serial_port :: read_some () quando non c'è nulla da leggere. Vorrei invece rilevare questa condizione e scrivere un comando sulla porta per avviare il dispositivo.

Come posso rilevare che non sono disponibili dati?

Se necessario, posso fare tutto in modo asincrono, preferirei evitare l'eventuale complessità aggiuntiva.

È stato utile?

Soluzione

In realtà hai un paio di opzioni. Puoi utilizzare la funzione async_read_some integrata nella porta seriale, oppure puoi utilizzare la funzione autonoma boost :: asio :: async_read (o async_read_some ).

Incontrerai comunque la situazione in cui sei effettivamente "bloccato", poiché nessuno di questi chiamerà il callback a meno che (1) i dati non siano stati letti o (2) si verifichi un errore. Per ovviare a questo, ti consigliamo di utilizzare un oggetto deadline_timer per impostare un timeout. Se il timeout viene attivato per primo, non sono disponibili dati. Altrimenti, avrai letto i dati.

La complessità aggiunta non è poi così male. Ti ritroverai con due callback con un comportamento simile. Se il "leggi" " o il "timeout" la callback si attiva con un errore, sai che è il perdente della gara. Se uno dei due spara senza errori, allora sai che è il vincitore della gara (e dovresti annullare l'altra chiamata). Nel punto in cui avresti avuto la tua chiamata di blocco a read_some , ora avrai una chiamata a io_svc.run () . La tua funzione continuerà a bloccarsi come prima quando chiama esegui , ma questa volta controlli la durata.

Ecco un esempio:

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
}

Ciò dovrebbe iniziare con solo alcune modifiche qua e là per soddisfare le tue esigenze specifiche. Spero che questo aiuti!

Un'altra nota: non sono stati necessari thread aggiuntivi per gestire i callback. Tutto è gestito all'interno della chiamata a run () . Non sono sicuro che tu fossi già a conoscenza di questo ...

Altri suggerimenti

In realtà è molto più semplice delle implicazioni qui fornite, e puoi farlo in modo sincrono:

Supponiamo che la lettura del tuo blocco sia stata qualcosa del genere:

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

Quindi lo sostituisci con

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);

Usi la forma sovraccaricata alternativa di ricezione_di cui hanno quasi tutti i metodi di invio / ricezione. Sfortunatamente accettano un argomento flag ma 0 sembra funzionare bene.

Devi usare la funzione libera asio :: async_read.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top