boost :: asio :: serial_port Lesung nach Gerät wieder anschließen
-
22-08-2019 - |
Frage
Ich habe ein Problem mit der boost :: asio :: serial_port Klasse das Lesen von einem GPS-Gerät (USB-Seriell). Gerät anschließen und das Lesen von es funktioniert gut, aber wenn ich das Gerät trennen und erneut, read_some liest kein Bytes vom Hafen entfernt.
Wie Boost nicht zu erkennen ist Naht dass die serielle Schnittstelle ist weg (istAuf () gibt true), kündige ich in regelmäßigen Abständen (), close () und offen (GPS_PORT), um das Gerät, wenn ich Daten nicht bekommen, Zurücksetzen die Port-Optionen auf dem Weg. Aber auch das nicht helfen, der Eingangspuffer bleibt leer.
Bin ich etwas fehlt oder etwas falsch zu machen, oder ist das ein Fehler in Asio? Gibt es eine standardisierte Möglichkeit zu erkennen, dass die Port weg ist?
Lösung
Es ist schwer zu sagen, was der genaue Grund, in Ihrem Fall ist, aber die Praxis zeigt, dass Sie oft RTS
Empfindlichkeit auf Ihrem seriell Port deaktivieren müssen.
RTS
ist ein Stift auf reale RS-232
Schnittstelle, die auf, wenn ein Gerät auf der anderen Seite ist, auf.
serial_port::read_some
ruft zugrunde liegende Windows API
-Funktion, die auf dieses Signal aussieht.
Wie Sie nicht das reale RS-323
Gerät haben, müssen Sie auf der Treiber-Emulation dieses Signals verlassen, die fehlerhaft sein können (und leider oft).
Um sie zu deaktivieren, rufen Sie serial_port::set_option(DCB)
mit RTSControl
auf RTS_CONTROL_DISABLE
.
Ihren Griff Wenn close()
'ing nicht hilft, kann es ein Problem mit boost
sein. Der Quellcode für close()
sieht wie folgt aus:
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. wenn CloseHandle()
aus irgendeinem Grund (oder hängt) ausfällt, der innere Griff Wert beign nicht zugeordnet INVALID_HANDLE_VALUE
und is_open()
immer true
zurück.
Um dies zu umgehen, überprüfen is_open()
direkt nach close()
'ing, und wenn es true
zurückkehrt, zerstören ganze Instanz boost::asio::serial_port
und erstellen Sie es erneut.
Andere Tipps
Normalerweise sollten Sie eine Ausnahme vom Typ boost::system::system_error
erhalten, wenn read_some
kann nicht mehr bereit. Versuchen Sie es mit read
statt, vielleicht ist es einen Fehler zurück und kehrt nicht nur. Sie könnten auch die Asynchron-Methoden versuchen; in diesem Fall sollte der Handler einen Fehler Objekt erhalten, wenn das Gerät abgeschaltet wurde.
Alterantively könnten Sie den Griff zum Hafen erhalten die native()
Funktion und rufen ClearCommError mit () auf, dass. Es könnte den Fehler zurück.
Trotz der einfachen Handhabung von Asio boost::ip:tcp
, denke ich boost serial_port
erfordert auf Windows 7.
besondere Vorsicht bei der Handhabung
Ich habe ähnliches Problem und überwand er durch eine Instanz von boost::asio::io_service
Zurücksetzen , io_service_.reset()
.
Ich kann Daten asynchron lesen, aber es scheitert elbe aus dem zweiten Versuch zu tun.
In der Tat war es kein Problem mit der Lesefunktion selbst, Registrierung asynchrone Lese gescheitert, die sofortige Rückgabe von boost::asio::io_service::run()
in zweitem Versuch führte.
Ich bin nicht sicher, dass dies das gleiche Problem wie ursprüngliches Plakat hatte, weil ich neuere boost Bibliothek dieser Tage verwenden.
Wie auch immer, hier ist meine Lösung:
// 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.