J'ai un problème avec la lecture de la classe boost :: asio :: serial_port à partir d'un périphérique GPS (USB-Serial). La connexion du périphérique et la lecture de celui-ci fonctionnent correctement, mais lorsque je déconnecte et reconnecte le périphérique, read_some ne lit aucun octet du port. Comme boost ne permet pas de détecter que le port série est parti (is_open() renvoie true), j'annule(), ferme() et ouvre (GPS_PORT) l'appareil périodiquement lorsque je ne reçois pas de données, réinitialiser les options de port en cours de route. Mais cela n'aide pas non plus, le tampon d'entrée reste vide. Est-ce que je manque quelque chose, ou si je fais quelque chose de mal, ou est-ce un bogue dans asio? Existe-t-il un moyen standard de détecter que le port est parti?boost :: asio :: serial_port lecture après la reconnexion du périphérique
Répondre
Il est difficile de dire quelle est la raison exacte dans votre cas, mais la pratique montre que vous devez souvent désactiver la sensibilité RTS
sur votre port série.
RTS
est une broche sur l'interface réelle RS-232
qui est activée lorsqu'un périphérique de l'autre côté est activé.
serial_port::read_some
appelle la fonction sous-jacente Windows API
qui regarde ce signal.
Comme vous n'avez pas le vrai périphérique RS-323
, vous devez vous fier à l'émulation de pilote de ce signal qui peut être défectueuse (et malheureusement souvent). Pour le désactiver, appelez serial_port::set_option(DCB)
avec RTSControl
défini sur RTS_CONTROL_DISABLE
.
Si votre poignée ne vous aide pas, cela peut poser un problème avec boost
. Le code source pour close()
ressemble à ceci:
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. si CloseHandle()
échoue pour une raison quelconque (ou se bloque), la valeur de handle interne n'est pas affectée à INVALID_HANDLE_VALUE
et is_open()
renverra toujours true
.
Pour contourner ce problème, vérifiez is_open()
juste après close()
« ing, et si elle retourne true
, par exemple détruire toute boost::asio::serial_port
et créer à nouveau.
Normalement, vous devriez obtenir une exception de type boost::system::system_error
lorsque read_some
ne peut plus tout faire. Essayez d'utiliser read
à la place, peut-être qu'il renvoie une erreur et ne revient pas seulement. Vous pouvez également essayer les méthodes asynchrones; dans ce cas, le gestionnaire devrait recevoir un objet d'erreur lorsque l'appareil a été déconnecté.
Vous pourriez obtenir le handle du port en utilisant la fonction native()
et appeler ClearCommError(). Cela pourrait renvoyer l'erreur.
Cela semble bon - Je vérifie le code d'erreur, mais je n'ai pas encore remarqué la méthode native() ... avec cela je devrais être en mesure de convier en quelque sorte le port série pour lire :) – VolkA
Peut-être que vous venez de don ' Je remarque que le périphérique a été débranché du fait que le pilote USB ne le signale pas au système d'exploitation. Dans ce cas: la malchance: / – vividos
Malgré la manipulation facile des asio boost::ip:tcp
, je pense que la manipulation poussée serial_port
nécessite des précautions particulières sur Windows 7.
Je suis le même problème et eu sur elle en remettant à zéro une instance de boost::asio::io_service
, io_service_.reset()
.
Je peux lire des données de manière asynchrone, mais il ne parvient pas à faire la même chose à partir du second essai.
En fait, il n'y avait aucun problème de lecture de la fonction elle-même, l'enregistrement de la lecture asynchrone a échoué, ce qui conduit à un retour immédiat de boost::asio::io_service::run()
lors de la deuxième tentative.
Je ne suis pas sûr que ce soit le même problème que l'affiche originale avait parce que j'utilise la nouvelle bibliothèque de boost de ces jours.
Quoi qu'il en soit, voici ma solution:
// 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.
Merci, je vais essayer - mais ne devrait pas la lecture échouera également lorsque l'appareil est d'abord ouvert? – VolkA
Lecture échouera lorsque le conducteur dit que RTS est éteint. Quand cela arrive, cela dépend de l'implémentation du pilote. BTW, lorsque la lecture commence à réussir: après redémarrage, après le rattachement de l'appareil, après le délai? – Quassnoi
Ok, j'ai juste essayé de mettre RTS_CONTROL_DISABLE - ça ne change pas le comportement. Le boost :: serial_port :: is_open renvoie true, mais ne commencera pas à lire. Le comportement est le suivant: connecter le GPS, démarrer l'outil - lire, déconnecter le GPS, arrêter la lecture, se connecter à nouveau, ne pas encore lire. Redémarrer l'outil: fonctionne à nouveau. – VolkA