Question

J'ai un problème avec le boost :: asio :: serial_port lecture de classe à partir d'un appareil GPS (USB-série). Connexion de l'appareil et la lecture de celui-ci fonctionne très bien, mais quand je débranche et rebranche l'appareil, read_some ne lit aucun octet du port.

Comme coup de pouce ne seam pas de détecter que le port série est allé (is_open () retourne vrai), je cancel périodiquement (), close () et ouvert (GPS_PORT) l'appareil lorsque je ne reçois pas de données, remise à zéro les options de port sur le chemin. Mais cela ne suffit pas non plus, le tampon d'entrée reste vide.

Suis-je manque quelque chose, ou faire quelque chose de mal, ou est-ce un bogue dans asio? Est-il un moyen standard pour détecter que le port est disparu?

Était-ce utile?

La solution

Il est difficile de dire quelle est la raison exacte dans votre cas, mais la pratique montre que vous avez souvent besoin de désactiver la sensibilité de RTS sur votre port série.

RTS est une broche sur l'interface RS-232 réelle qui est sur le moment où un dispositif sur l'autre côté est en marche.

serial_port::read_some invoque la fonction sous-jacente Windows API qui regarde ce signal.

Comme vous n'avez pas le vrai dispositif de RS-323, vous devez compter sur l'émulation du pilote de ce signal qui peut être défectueux (et, malheureusement, est souvent).

Pour la désactiver, invoquez serial_port::set_option(DCB) avec RTSControl réglé sur RTS_CONTROL_DISABLE.

Si close()'ing votre poignée ne fonctionne pas, il peut être un problème avec boost. Le code source 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 la poignée interne n'est pas beign affecté à INVALID_HANDLE_VALUE et is_open() retournera 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.

Autres conseils

Normalement, vous devriez obtenir une exception de type boost::system::system_error quand read_some ne peut plus prêt. Essayez d'utiliser read à la place, peut-être renvoie une erreur et ne se contente pas revenir. Vous pouvez également essayer les méthodes async; dans ce cas, le gestionnaire doit obtenir un objet d'erreur lorsque le dispositif a été déconnecté.

Alterantively vous pouvez obtenir la poignée au port en utilisant la fonction native() et appelez ClearCommError () sur ce point. Il peut renvoyer l'erreur.

En dépit de la manipulation facile de boost::ip:tcp asio, je pense que la manipulation serial_port boost requiert une attention particulière sur Windows 7.
Je suis le même problème et got dessus en réinitialisant une instance de boost::asio::io_service , io_service_.reset().
Je peux lire des données, mais il de manière asynchrone ne parvient pas à le faire même chose à partir du deuxième essai.
En fait, il avait pas de problème de la fonction de lecture lui-même, l'enregistrement de lecture asynchrone a échoué, ce qui a conduit le retour immédiat de boost::asio::io_service::run() deuxième essai.

Je ne suis pas sûr que ce soit le même problème que l'affiche originale avait parce que je suis en utilisant la bibliothèque Boost plus récente de ces jours-ci.
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.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top