boost :: :: lettura asio da porta seriale dopo aver ricollegato dispositivo
-
22-08-2019 - |
Domanda
Ho un problema con il boost :: classe lettura asio :: porta seriale da un dispositivo GPS (USB-Seriale). Collegare il dispositivo e la lettura da esso funziona bene, ma quando scollegare e ricollegare il dispositivo, read_some non legge byte dalla porta.
Come spinta non cucitura a rilevare che la porta seriale è andato (is_open () restituisce true), ho periodicamente annullare (), close () e aperto (GPS_PORT) il dispositivo quando non ho ricevuto i dati, il ripristino le opzioni di porta sulla strada. Ma questo non aiuta, il buffer di ingresso rimane vuoto.
Mi manca qualcosa, o fare qualcosa di sbagliato, o si tratta di un bug in ASIO? C'è un modo standard per rilevare che la porta è andato?
Soluzione
E 'difficile dire quale sia la ragione esatta nel tuo caso, ma la pratica dimostra che spesso è necessario disattivare la sensibilità RTS
sulla vostra porta seriale.
RTS
è un perno sull'interfaccia reale RS-232
che è acceso quando un dispositivo sull'altro lato è acceso.
serial_port::read_some
invoca la funzione Windows API
di fondo che appare su questo segnale.
Per quanto non si dispone il dispositivo RS-323
vero e proprio, è necessario fare affidamento su l'emulazione del driver di questo segnale, che potrebbe essere difettosa (e purtroppo spesso è).
Per disabilitarlo, invocano serial_port::set_option(DCB)
con RTSControl
impostato RTS_CONTROL_DISABLE
.
Se il vostro close()
'ing maniglia non aiuta, può essere un problema con boost
. Il codice sorgente per close()
assomiglia a questo:
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()
riesce per qualche motivo (o si blocca), il valore di handle interno non è assegnato a beign INVALID_HANDLE_VALUE
e is_open()
restituirà sempre true
.
Per risolvere questo, controllare is_open()
subito dopo close()
'ing, e se restituisce true
, distruggere tutta istanza di boost::asio::serial_port
e creare di nuovo.
Altri suggerimenti
Normalmente si dovrebbe ottenere un'eccezione di tipo boost::system::system_error
quando read_some
non può pronta più. Provate ad usare read
invece, forse restituisce un errore e non si limita a tornare. Si potrebbe anche provare i metodi asincroni; in questo caso il gestore dovrebbe ottenere un oggetto errore quando il dispositivo è stato disconnesso.
Alterantively si potrebbe ottenere la maniglia alla porta usando la funzione native()
e chiamare ClearCommError () su questo. Potrebbe restituire l'errore.
Nonostante la maneggevolezza di boost::ip:tcp
ASIO, penso che la manipolazione spinta serial_port
richiede particolare cautela su Windows 7.
Ho avuto problemi simili e ha ottenuto su di esso reimpostando un'istanza di boost::asio::io_service
, io_service_.reset()
.
Posso leggere i dati in modo asincrono ma non riesce a fare stessa cosa dal secondo tentativo.
In realtà, non era un problema di funzione di lettura per sé, registrando lettura asincrono fallito, che ha portato ritorno immediato da boost::asio::io_service::run()
nel secondo tentativo.
Non sono sicuro che questo è lo stesso problema come poster originale aveva perché sto usando più recente libreria Boost di questi giorni.
Comunque qui è la mia soluzione:
// 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.