none
HID USB Stream auslesen RRS feed

  • Frage

  • Hallo MSDN Nutzer,

    Ich nutze VB.Net und WPF und habe folgende Aufgabenstellung:

    Ich habe ein USB Gerät das mit dauerhaft einen Wert aus 32 Bit liefert der so aussieht:

    00  A1  05  35  FF  B4  05  AF  01  0F  05  A5  01  AD  04  D1  01  EF  03  52  00  15  01  92  01  4B  FF  DE  00  16  A0  02

    Aus diesem Wert kann ich jeweils 7 Werte für X, 7 Werte für Y und 1 Wert für Z entnehmen.
    Ein Wert X sowie ein Wert Y entsprechen 0,001024 Sekunden.

    Wie kann ich das Gerät so ansprechen, das ich sekündlich alle geforderten Werte abspeichern kann ohne das sich das komplette Projekt aufhängt?

    Nach aufgerundeter Rechnung benötige ich diesen 32 Bit Wert ungefähr 500 Mal die Sekunde.

    Wenn ich das hinbekämen würde wär ich schon sehr weit. Denn danach geht es daran diese Werte in einem Line-Chart darzustellen.

    Ich hoffe jemand von euch kann mir helfen.


    MfG ASkuN

    Montag, 13. Mai 2013 12:43

Antworten

  • Ich denke du musst einen API-Recall initialisieren. Ich habe das Gefühl das du die Daten selbst lesen willst, und damit ist Deine Methode zu langsam.

    Ich denke du müsstest das Gerät initialisieren und dann per API einen Ereignishandler in Deinem Programm mitteilen, somit wird deine Prozedur jedes mal aufgerufen wenn Daten eintreffen, die Du dann abarbeiten musst. Im Moment rufst du die Funktion auf (erstellst einen Puffer und legst Zeiger fest) wodurch dir Daten zwischen 2 Aufrufen durch die Lappen gehen.

    Solche Nachrichtenschleifen in Dein eigenes Programm zu implementieren sind an sich möglich, aber bedarf einer genauen Planung und Wissen wie der Ablauf in dem Gerät von statten geht.

    Vielleicht kann Dir Elmar Boye da helfen, einer der Forum Gurus hier [Anerkennend gemeint :-)]

    Gruß Thomas


    • Bearbeitet tommytom73 Dienstag, 14. Mai 2013 15:08 Namen falsch geschieben
    • Als Antwort markiert ASkuN Dienstag, 14. Mai 2013 15:19
    Dienstag, 14. Mai 2013 15:07

Alle Antworten

  • Hallo

    Das sieht mir danach aus, das man mit Threads arbeiten müsste.

    Thread 1:
    - Daten auslesen und aufbereiten
    - Daten in einer Collection z.B.(Queue) ablegen

    Thread 2:
    - Daten aus der Collection auslesen und dann anzeigen Bzw. speichern.

    Ich weiß jetzt nicht was Du mit "ohne das sich das komplette Projekt aufhängt?" meinst. Du scheinst ja schon Code geschrieben zu haben der nicht richtig funktioniert. Müsste man sehen um vielleicht Tipps zu geben.

    Gruß Thomas

    Dienstag, 14. Mai 2013 06:41
  • also das Problem ist einfach, das es sich um eine erhebliche Menge an Daten handelt die ich pro Sekunde brauche. Ich fülle zwei Textboxen und ein ComponentOne Chart und damit ist es schon sehr langsam....ich habe die zwei Textboxen jetzt rausgelassen und es geht schonmal doppelt so schnell aber immer noch zu langsam....

    könntest du mir ein Beispiel für eine Thread Methodik geben wie du es lösen würdest? Ich habe schon diverse Methoden ausprobiert (Vielleicht auch mit Verständnisproblem falsch gecoded!) wie zum Beispiel System.Threading.Thread und System.Componentmodel.Backgroundworker


    MfG ASkuN

    Dienstag, 14. Mai 2013 07:12
  • Ich habe mal schnell ein Bespiel geschrieben welches mit 2 Threads arbeitet. Der Erste Thread überwacht ein Verzeichnis und bei Änderungen speichert er diese in die Auflistung (Queue). Der zweite Thread prüft ständig ob es Einträge in der Auflistung gibt, wenn ja nimmt er dieses Object aus der Auflistung heraus und zeigt es in einer Listbox an.

    Die ist wie gesagt ein ganz einfaches Beispiel, welches nur zeigen soll wie es ungefähr gehen könnte, da ich nicht weiß wie Deine Daten ankommen. Mann sollte es auch noch threadsicher machen siehe Queue

    Gruß Thomas

    Public Class Form1
    	'
    	Private Structure objTest
    		Public strEreignis As String
    		Public strFile As String
    		Public Overrides Function ToString() As String
    			Return strEreignis & ":" & strFile
    		End Function
    	End Structure
    	'
    	Private WithEvents bwReadThread As System.ComponentModel.BackgroundWorker
    	Private WithEvents bwSaveThread As System.ComponentModel.BackgroundWorker
    	Private lstQueue As System.Collections.Generic.Queue(Of objTest)
    
     	Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    		If IsNothing(bwReadThread) = False AndAlso bwReadThread.IsBusy = True Then
    			bwReadThread.CancelAsync
    			bwReadThread.Dispose
    		End If
    		If IsNothing(bwSaveThread) = False AndAlso bwSaveThread.IsBusy = True Then
    			bwSaveThread.CancelAsync
    			bwSaveThread.Dispose
    		End If
    	End Sub
    	'
    	Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    		lstQueue = New System.Collections.Generic.Queue(Of objTest)
    		bwReadThread = New System.ComponentModel.BackgroundWorker
    		bwReadThread.WorkerSupportsCancellation = True
    		bwReadThread.RunWorkerAsync
    		'//
    		bwSaveThread = New System.ComponentModel.BackgroundWorker
    		bwSaveThread.WorkerSupportsCancellation = True
    		bwSaveThread.WorkerReportsProgress = True
    		bwSaveThread.RunWorkerAsync
    		'//
    	End Sub
    	'
    #Region "Thread-1"
    	'
    	Private Sub AusleseThread_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwReadThread.DoWork
    		'//
    		Dim fw As New IO.FileSystemWatcher("C:\Users\[USER]\AppData\Local\Temp")
    		AddHandler fw.Changed, AddressOf ObjectChanged
    		AddHandler fw.Renamed, AddressOf ObjectRenamed
    		fw.EnableRaisingEvents = True
    		'//
    		Do While DirectCast(sender, System.ComponentModel.BackgroundWorker).CancellationPending = False
    
    		Loop
    		'//
    		fw.EnableRaisingEvents = False
    		'//
    	End Sub
    	'
    	Private Sub ObjectChanged(sender As Object, e As System.IO.FileSystemEventArgs)
    		Dim t As New objTest
    		t.strEreignis = "geändert"
    		t.strFile = e.Name
    		Me.lstQueue.Enqueue(t)
    	End Sub
    	'
    	Private Sub ObjectRenamed(sender As Object, e As System.IO.RenamedEventArgs)
    		Dim t As New objTest
    		t.strEreignis = "umbenannt"
    		t.strFile = e.Name
    		Me.lstQueue.Enqueue(t)
    	End Sub
    	'
    #End Region
    	'
    #Region "Thread-2"
    	'
    	Private Sub AnzeigeThread_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwSaveThread.DoWork
    		'//
    		Do While DirectCast(sender, System.ComponentModel.BackgroundWorker).CancellationPending = False
    			'//
    			If Me.lstQueue.Count > 0 Then
    				DirectCast(sender, System.ComponentModel.BackgroundWorker).ReportProgress(0, Me.lstQueue.Dequeue)
    			End If
    			'//
    		Loop
    		'//		
    	End Sub
    	'
    	Private Sub AnzeigeThread_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bwSaveThread.ProgressChanged
    		If IsNothing(e.UserState) = False Then
    			Me.ListBox1.Items.Add(DirectCast(e.UserState, objTest).ToString)
    		End If
    	End Sub
    	'
    #End Region
    	'
    End Class

      
    Dienstag, 14. Mai 2013 10:06
  • Okey erstmal Danke für die ausführliche Antwort. Jetzt geht's einen Schritt weiter...

    Ich habe ein USB HID Device das ich mittels Produkt ID und Vendor ID (PID & VID) ansprechen kann. Ich habe herausgefunden das meine Methodik zu langsam ist (es kommen nicht alle Datenpakete an).

    Beim einstecken dieses Geräts fängt er sofort an Datenflüsse zu senden in Form von diesen 32 Byte Paketen.

    Ich brauche eine Methode, Funktion, DLL was auch immer um sehr sauber mit diesem Gerät zu kommunizieren.

    Danke im Voraus...

    P.S.: Mit der Produkt und Vendor ID habe ich es BIS jetzt gemacht. Natürlich hat das Gerät auch eine eindeutige Seriennummer....Hoffe das hilft vielleicht....


    MfG ASkuN


    • Bearbeitet ASkuN Dienstag, 14. Mai 2013 13:13
    Dienstag, 14. Mai 2013 12:56
  • Was ist das für ein Device? Hat das einen Treiber? Wie liest du diese Pakete aus? Wie sieht Deine Prozedur aus in der Du die Daten empfängst?

    So pauschal können wir hier in dem Forum wenig hilfreich sein.

    Gruß Thomas

    Dienstag, 14. Mai 2013 13:12
  • Das ist ein Gerät zum Auslesen des Puls und EKG Wert einer Person. Das Device sendet beim Einstecken sofort kontinuierlich diese 32 Bytes los.

    Ich handle nach dem Prinzip wie es in diesem Projekt zu sehen ist ("generichid_vb")


    MfG ASkuN

    Dienstag, 14. Mai 2013 13:47
  • Also die "theoretische Lösung" würde so aussehn:

    Thread #1:

    Schreibt den Datenfluss der vom HID kommt in einen Buffer ("Buffer #1") mit ausreichender Größe.

    Thread #2:

    Sammelt und ordnet die Byte Pakete aus dem Buffer ("Buffer #1") in deinem neuen Zwischenbuffer ("Buffer #2") und bildet den grafischen View in einem Chart.

    So viel zum theoretischen jetzt muss ich es nur noch hinbekommen die Kommunikation mit dem HID zu realisieren...


    MfG ASkuN

    Dienstag, 14. Mai 2013 14:07
  • Gibt es einen Treiber? Wie wird das Gerät im Gerätemanager angezeigt?

    Finde ich komisch das das Gerät ungefragt (ohne Initialisierung) Daten sendet. Die meisten Medizin-Produkte die ich kenne werden über virtuelle Com-Ports aktiviert und erst wenn ich den Datenempfang initialisiere geht das senden der Daten los. Die Gräte welche Direkt per USB angeschlossen sind haben meisten einen Device-Treiber den man per API-Funktionen initialisieren und den Datenempfang kontrollieren kann.

    In Deinem Fall ist es schwierig dir Tipps zu geben ohne weitere Kenntnisse über das Gerät.

    Ich würde anhand Deiner Informationen folgende Schritte versuchen.

    1. Den Empfang der Daten in dem ersten Thread
    2. Eine Klasse erstellen welche die empfangenen Daten aufnimmt, verarbeitet, und dann strukturiert bereitstellt.
    3. Das erzeugte Objekt in die Auflistung packen
    4. Der zweite Thread übernimmt dann die Speicherung der Daten oder Anzeige in der GUI
    5. Die meisten Diagramm-Controls kann man meistens per Datenbindung direkt mit einer Datenquelle verbinden. (Außer Du hast vor die EKG-Ableitungskurven in Echtzeit anzuzeigen dann hast Du ganz schön was vor Dir.

    Gruß Thomas    

      

    Dienstag, 14. Mai 2013 14:08
  • Es ist ganz schön schwierig alles so darzustellen das ich keine Probleme mit dem Auftraggeber bekomme :-)

    Das Device wird als eingestecktes USB HID gelistet. In der Beispielanwendung ("HIDTest.exe") aus der ZIP Datei wird das mit HidD_GetAttributes realisiert.

    Das Gerät an sich wird per USB-Dongle nutzbar gemacht und aktiviert.

    Zu Punkt 1:

    Das mache ich ja schon, das Problem ist das die Methode (die auch im Beispielprojekt genutzt wird) nicht schnell genug arbeitet. Es gehen immer zwischen 3 und 20 Pakete verloren.


    MfG ASkuN

    Dienstag, 14. Mai 2013 14:20
  • Ich denke du musst einen API-Recall initialisieren. Ich habe das Gefühl das du die Daten selbst lesen willst, und damit ist Deine Methode zu langsam.

    Ich denke du müsstest das Gerät initialisieren und dann per API einen Ereignishandler in Deinem Programm mitteilen, somit wird deine Prozedur jedes mal aufgerufen wenn Daten eintreffen, die Du dann abarbeiten musst. Im Moment rufst du die Funktion auf (erstellst einen Puffer und legst Zeiger fest) wodurch dir Daten zwischen 2 Aufrufen durch die Lappen gehen.

    Solche Nachrichtenschleifen in Dein eigenes Programm zu implementieren sind an sich möglich, aber bedarf einer genauen Planung und Wissen wie der Ablauf in dem Gerät von statten geht.

    Vielleicht kann Dir Elmar Boye da helfen, einer der Forum Gurus hier [Anerkennend gemeint :-)]

    Gruß Thomas


    • Bearbeitet tommytom73 Dienstag, 14. Mai 2013 15:08 Namen falsch geschieben
    • Als Antwort markiert ASkuN Dienstag, 14. Mai 2013 15:19
    Dienstag, 14. Mai 2013 15:07
  • ich danke dir :) ich bin auf so einen Lösungsweg vor ca. einer halben Stunde gestoßen und habe es endlich realisiert bekommen.

    Zur Lösung:

    Jedes Mal wenn Daten des Sticks kommen wird meine Methode OnDataReceived Aufgerufen und diese Speichert dann über einen Thread die Daten in einen Buffer. Parallel läuft ein zweiter Thread der den Buffer überwacht und neue Daten in den View für die grafische Ansicht umwandeln :)

    Mit viel denken, probieren und nachfragen kommt man am Schluss doch immer auf einen Punkt :)

    Vielen Dank :)


    MfG ASkuN

    Dienstag, 14. Mai 2013 15:19
  •  "ASkuN" schrieb im Newsbeitrag
     
    > Ich brauche eine Methode, Funktion, DLL was auch immer um sehr sauber mit
    > diesem Gerät zu kommunizieren.
     
    und was sagt der Hersteller dazu, die gibt es normalerweise vom Hersteller -
    gibt es eine Beschreibung?
     
    Oder wollt Ihr nur ein Gerät für Eure Zwecke missbrauchen?
     
    Du müsstet ja wenigstens wissen was die Werte bedeuten.
     
     
    Mittwoch, 15. Mai 2013 11:30
  • Der Hersteller ist ein Partner von uns und wir stellen die Software her.

    Ich weiß was die Werte genau bedeutet, doch darf ich keine öffentlichen Angaben (wegen Datenschutzgründen) machen.


    MfG ASkuN

    Mittwoch, 15. Mai 2013 11:43
  •  "ASkuN" schrieb
     
    > Der Hersteller ist ein Partner von uns und wir stellen die Software her.
     
    > Ich weiß was die Werte genau bedeutet, doch darf ich keine öffentlichen
    > Angaben (wegen Datenschutzgründen) machen.
     
    Das Demo das Du hattest ist irgendwo aus dem Internet, das habe ich auch
    schon seit langem auf dem Rechner lieen.
     
    Nun kannst Du das Teil nehmen, die Funktionen herausziehen und Dir Deine
    eigenen Klasse daraus aufbauen, passend zu dem Gerät.
     
    Her gibts auch noch ein paar Beispiele zur Inspiration.
     
     
     
    Mittwoch, 15. Mai 2013 13:39
  • Ich hab das Thema doch schon abgeschlossen und es funktioniert alles! Ich hab das Demo Projekt nicht benutzt, weil die Methodik zu langsam für meinen Nutzen ist.

    MfG ASkuN

    Mittwoch, 15. Mai 2013 13:49