2016-06-12 1 views
0

Je communique avec un périphérique intégré qui arrête régulièrement son émulation de port série USB, utilise le port USB pour autre chose, puis redémarre son émulation de port série. Pendant cette brève période, le port série disparaît du gestionnaire de périphériques Windows et du registre, puis réapparaît dans les deux emplacements. Mon application .NET 4.5 gère cela très bien tant que je suis déconnecté du port série quand il se produit: après le redémarrage de l'émulation de port série, je peux me reconnecter et communiquer comme d'habitude.Comment mon application peut-elle se rétablir lorsqu'un port série émulé par USB disparaît et réapparaît?

Cependant, si je suis connecté au port série virtuel lorsque l'appareil tombe et redémarre plus tard son émulation de port série, mon programme ne se bloque pas mais je ne peux pas accéder au port redémarré.

Dans cette situation, le gestionnaire de périphériques Windows affiche correctement le port qui disparaît et réapparaît, tandis que le registre affiche le port qui disparaît mais ne réapparaît jamais. Naturellement cela signifie que SerialPort.GetPortNames() ne trouve pas le port par la suite, et bien sûr j'obtiens une exception IOException si je tente de fermer le port qui a disparu.

Edit: Je ne suis pas en utilisant les threads de travail, et je me sers BaseStream.ReadAsync et je suis capable de piéger le IOException et disposer l'objet port d'origine.

Comme je l'ai mentionné, le port émulé redémarré apparaît très bien dans le Gestionnaire de périphériques, mais n'apparaît pas dans le registre de HKLM/Hardware/DeviceMap/SerialComm.

Une fois que j'ai éliminé (ou même essayé de fermer) le port dans .net, si je force par la suite le périphérique embarqué à redémarrer, le port émulé réapparaît dans le registre et je peux me reconnecter. Malheureusement, cela nécessite une interaction physique avec l'appareil, ce qui n'est généralement pas possible.

Je cherche un moyen de récupérer par programme, parce que je n'ai normalement pas accès à l'appareil pour forcer un redémarrage. J'imagine qu'après avoir disposé mon objet port série, il pourrait y avoir un moyen d'obtenir l'actualisation du registre par Windows, mais j'ai été incapable de trouver des indices sur la façon dont cela pourrait être accompli.

J'ai trouvé beaucoup de questions SO qui sont similaires aux miennes, mais aucune qui soit identique et aucune qui a fourni une réponse à mon problème.

Hans Passant a suggéré de placer une étiquette sur le câble USB invitant les gens à le débrancher et à le rebrancher plusieurs fois juste pour voir ce qui se passe. J'aime penser, mais dans mon cas, l'émulation est arrêtée et démarrée par un périphérique embarqué - et ce comportement est nécessaire en raison de la conception du matériel.

J'ai essayé aveuglément d'ajouter <legacyUnhandledExceptionPolicy enabled="1"/> à mon fichier app.exe.config, et il n'a pas semblé faire quoi que ce soit.

En fonction des réponses à des questions similaires, j'ai essayé de déplacer mon appel à Close() vers un thread séparé et j'ai également essayé d'utiliser async pour attendre la fin de l'appel. Cette approche a mis fin à mon application avec une erreur de réflexion du système.

Comment puis-je faire en sorte que mon application dispose de sa connexion (ou s'écarte) lorsqu'un port disparaît et réapparaît, afin que le registre puisse être actualisé correctement pour correspondre au gestionnaire de périphériques?

Ou y a-t-il quelque chose que je puisse faire pour récupérer de la perte momentanée d'un port série émulé sans terminer et redémarrer l'application?

Répondre

1

La classe framework System.IO.Ports.SerialPort ne rend certainement pas cette tâche facile.

Vous aurez besoin de p/invoke ou de C++/CLI pour obtenir les événements de déconnexion et de reconnexion ... la fonction RegisterDeviceNotification est la clé. Après cela, vous devriez éviter d'utiliser des threads de travail, car System.IO.Ports.SerialPort va lancer des exceptions lorsque le périphérique disparaît ou que le port est supprimé, et vous n'aurez pas la possibilité d'installer les gestionnaires d'exceptions appropriés sur le port d'achèvement. fil de travail.

Si vous en finir avec l'événement DataReceived et au lieu d'utiliser port.BaseStream.ReadAsync pour évènementielle chevauché recevoir, vous pouvez mettre un try/catch autour du ReadAsync appel et être en mesure de récupérer en disposant l'ancien objet port. Comme un bonus supplémentaire, les données entrantes sont ensuite livrées via le contexte de synchronisation sur votre thread principal de sorte que vous n'avez pas à vous soucier de la synchronisation des threads vous-même.

+0

J'ai la plupart des aspects de série fonctionnent très bien, principalement en raison de votre blog célèbre [ici] (http://www.sparxeng.com/blog/software/must-use-net-system-io- ports-serialport). Cependant, la solution à ce problème particulier me échappe toujours. Êtes-vous en train de suggérer que si vous vous inscrivez pour recevoir les événements de déconnexion et de reconnexion, je peux faire quelque chose pour m'assurer que Windows enregistrera correctement le port lors de la reconnexion? Ou peut-être juste que si je détecte la déconnexion je peux rapidement disposer mon port avant la reconnexion, et cela peut résoudre le problème? –

+0

@ Craig.Feied: Je ne suis pas sûr à 100% mais oui, je pense que l'élimination lors du traitement des événements de notification de déconnexion peut être la solution. Cette notification est synchrone, de sorte que l'événement de reconnexion ne sera pas traité par la gestion des périphériques Windows, à moins que vous ne fassiez quelque chose qui casse la synchronicité comme une invocation inter-thread. –

+0

Malheureusement, il n'y a pas assez d'informations dans cette réponse pour l'appeler une vraie réponse. Cela suggère seulement une possibilité de quelque chose. Dans mon expérience d'attraper l'événement unplugged, et disposer d'un objet SerialPort pendant la gestion de l'événement soit ne fonctionne pas du tout, fonctionne sporadiquement, ou il y a une façon très spécifique de le faire qui permet de construire un autre port qui peut être opérations de lecture/écriture réussies. La première phrase est certainement une déclaration vraie! – shawn1874