2015-07-21 3 views
1

Une partie d'un programme que je modifie implique la communication via un port série à l'aide d'une bibliothèque propriétaire. Malheureusement, cette bibliothèque n'a pas le même SerialPort.DataReceived event que l'espace de noms System.IO.Ports contient. En fait, il n'a pas d'événement que ce soit, mais il ne dispose de deux fonctions qui peuvent probablement être utilisés de manière similaire:Soulever un événement lorsqu'une fonction renvoie Vrai

  1. Port.WaitForData (heure int)

    Cette fonction attend la quantité de temps donnée pour recevoir certaines chaînes précédemment spécifiées sur le port. Il renvoie 1 pour oui, a reçu la chaîne, ou 0 pour non, n'a pas reçu de chaîne, a expiré.

  2. Port.IsReceiveBufferEmpty()

    Cette fonction retourne une valeur booléenne de oui, le tampon de réception est vide ounon, la mémoire tampon de réception contient des données.

Il me semble que je vais devoir créer un fil pour être en boucle en continu chaque fois que le port est ouvert et faire une de ces deux choses:

  1. Pour chaque boucle, appelez WaitForData (certains grand nombre) avec les chaînes spécifiées, il cherche à mettre "", ou vbCrLf, ou quelque chose d'autre que je peux confirmer, il recevra à chaque fois que les données sont envoyées. S'il trouve quelque chose, lisez-le et écrivez dans une zone de texte. Si WaitForData ne trouve rien, bouclez à nouveau.

  2. Pour chaque boucle, appelez IsReceiveBufferEmpty(), et si ce n'est pas le cas, lisez-le et écrivez dans une zone de texte.

Quelle est la meilleure façon d'y parvenir? Les premières options me semblent potentiellement plus efficaces, bien que je ne sache presque rien de la façon dont ces méthodes fonctionnent sous le capot. Évidemment, je veux que mon formulaire reste réactif quand je fais cela, alors comment dois-je faire pour boucler continuellement sans figer le formulaire, mais être capable de lire toutes les données entrantes?

Merci pour votre aide.

+0

écrire une telle API pour un usage général serait différent de l'optimiser pour l'application que vous écrivez. nous ne savons rien de votre application. une chose est «... écrire dans une zone de texte ...» vous ne pourrez pas faire cela à partir de n'importe quelle solution à base de threads. Je soulèverais un événement et fournirais les données reçues et laisserais le consommateur traiter avec lui. – Plutonix

+0

@Plutonix Je ne sais pas exactement comment simuler un événement DataReceived dans mon code, et j'essaie de trouver la meilleure façon de le faire. L'application prend l'entrée à partir d'une zone de texte, l'envoie au port, puis lit tout ce qui revient du port. Y a-t-il plus d'informations dont vous avez besoin pour pouvoir décrire de manière générale comment procéder? Mes solutions ci-dessus ont-elles un sens? En outre, dans les applications multithread, je peux utiliser Invoke ou quelque chose de similaire pour écrire dans les composants de formulaire, correct? – Django

+0

Pouvez-vous utiliser 'Async/Await' (VS 2012+/.NET 4.5+ - ou 4.0 avec quelques librairies supplémentaires)? – Mark

Répondre

1

Peut-être pas la solution la plus élégante, mais vous pouvez utiliser un BackgroundWorker pour faire l'E/S. par exemple. Quelque chose comme ce pseudo-code:

Public Class MyForm 

    Private _port As ProprietaryIOLibrary 
    Private WithEvents Worker As System.ComponentModel.BackgroundWorker 

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load 
     _port = New ProprietaryIOLibrary() 
     Worker = New System.ComponentModel.BackgroundWorker() 
     Worker.WorkerReportsProgress = True 
     Worker.WorkerSupportsCancellation = True 
     Worker.RunWorkerAsync() 
    End Sub 

    Private Sub ButtonCancel_Click(sender As Object, e As EventArgs) Handles ButtonCancel.Click 
     Worker.CancelAsync() 
    End Sub 

    Private Sub Worker_DoWork(sender As Object, e As DoWorkEventArgs) Handles Worker.DoWork 
     Do 
      If _port.WaitForData(1000) Then ' Adjust timeout depending on cancel responsiveness? 
       Dim data As String = _port.ReadDataAsString() ' ? 
       ' Trigger the ProgressChanged event, passing the data 
       Worker.ReportProgress(0, data) 
      End If 
      If Worker.CancellationPending Then 
       Exit Do 
      End If 
     Loop 
    End Sub 

    Private Sub Worker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles Worker.ProgressChanged 
     ' Update the UI with the data received 
     ' ProgressChanged is called on the UI thread, so no need to Invoke 
     Dim data As String = DirectCast(e.UserState, String) 
     TextBox1.Text &= data & vbCrLf 
    End Sub 

    Private Sub Worker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles Worker.RunWorkerCompleted 
     TextBox1.Text &= "Complete!" 
    End Sub 

End Class