Daten über Bluetooth senden und empfangen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 68 Antworten in diesem Thema. Der letzte Beitrag () ist von tron25.

    tron25 schrieb:

    Gibt es die Möglichkeit, so etwas auch außerhalb einer Sub oder Funktion abzufangen?


    Das ist garnicht nötig. Wenn du BluetoothClient anstatt im Klassenbereich instanziierst in einer Methode(also das = new...) in eine Function/sub packen.

    Bevor du weiter so arbeitest verpasse ich dir eine Lektion in OOP.(Object Orientiertes Programmieren)
    Anstatt den ganzen BT-Kram in der Form-Klasse zu machen, machen wir eine eigene Klasse dafür, so bleibt der Code in der Formklasse deutlich überschaubarer. Noch dazu kannste dich mit mehreren Devices verbinden indem du die Klasse mehrfach instanziierst. In dem Fall wohl nicht nötig, aber da der Code besser ist, machen wir das nun so, wenn mehrere gleiche devices verwendet werden sollen, muss man die function Connect(siehe meinen Code unten) ein wenig ändern. Das hat noch einen weiteren Vorteil, machste noch so eine App, musste nicht den ganzen Kram wieder schreiben, klasse dem Projekt hinzufügen und feddich. Wiederverwertbarkeit ist IMO ein muss!

    Fangen wir mit einer Klasse an, nennen sie BluetoothUtil. Überlege was muss die Klasse können.

    -Verbinden
    -Verbindung schliessen
    -vom stream lesen
    -in den stream schreiben
    -alles wieder freigeben

    kein muss, mach ich bei sowas immer rein
    -eine function um zu testen ob verbunden

    Also:
    eine Function als Boolean Connect
    ein sub Disconnect
    eine sub Write
    eine funtion Read als byte array oder string
    ein function IsConnected als boolean.
    IDisposeable imlpementieren

    Da haben wir schon das Grundgerüst!

    Ich hab das mal vorbereitet. Die Function read bleibt dir überlassen, die ist noch auskommentiert.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports InTheHand.Net
    2. Imports InTheHand.Net.Sockets
    3. Imports InTheHand.Net.Bluetooth
    4. Public Class BluetoothUtil
    5. Implements IDisposable
    6. Private client As BluetoothClient
    7. Private stream As IO.Stream
    8. Private disposedValue As Boolean
    9. Public Function IsConnected() As Boolean
    10. Return client IsNot Nothing AndAlso client.Connected
    11. End Function
    12. Public Function Connect(deviceName As String) As Boolean
    13. Try
    14. Dim deviceInfo As BluetoothDeviceInfo = Nothing
    15. client = New BluetoothClient()
    16. Dim devices As BluetoothDeviceInfo() = client.DiscoverDevices()
    17. For Each d As BluetoothDeviceInfo In devices
    18. If d.DeviceName.ToLower().Equals(deviceName.ToLower()) Then
    19. deviceInfo = d
    20. End If
    21. Next
    22. If deviceInfo Is Nothing Then
    23. MessageBox.Show("Kein Device mit dem Namen: " & deviceName & " gefunden!")
    24. Return False
    25. End If
    26. Dim endPoint As New BluetoothEndPoint(deviceInfo.DeviceAddress, BluetoothService.SerialPort)
    27. client.Connect(endPoint)
    28. If client.Connected Then
    29. stream = client.GetStream()
    30. Return True
    31. End If
    32. MessageBox.Show("Konnte keine Verbindung zum Device aufbauen!")
    33. Catch ex As PlatformNotSupportedException
    34. MessageBox.Show("Kein Bluetooth verfügbar!")
    35. End Try
    36. Return False
    37. End Function
    38. Public Sub Disconnect()
    39. If Not client Is Nothing Then
    40. If client.Connected Then
    41. client.Close()
    42. End If
    43. End If
    44. End Sub
    45. Public Sub Write(data As String)
    46. If Not IsConnected() Then
    47. MessageBox.Show("Nicht verbunden!")
    48. Return
    49. End If
    50. If stream Is Nothing Then
    51. stream = client.GetStream()
    52. End If
    53. Using streamWriter As New IO.StreamWriter(stream, System.Text.Encoding.Default, 1, True)
    54. streamWriter.Write(data)
    55. End Using
    56. End Sub
    57. Protected Overridable Sub Dispose(disposing As Boolean)
    58. If Not disposedValue Then
    59. If disposing Then
    60. ' TODO: Verwalteten Zustand (verwaltete Objekte) bereinigen
    61. If Not stream Is Nothing Then
    62. stream.Dispose()
    63. End If
    64. If Not client Is Nothing Then
    65. client.Dispose()
    66. End If
    67. End If
    68. ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben
    69. ' TODO: Große Felder auf NULL setzen
    70. disposedValue = True
    71. End If
    72. End Sub
    73. ' ' TODO: Finalizer nur überschreiben, wenn "Dispose(disposing As Boolean)" Code für die Freigabe nicht verwalteter Ressourcen enthält
    74. ' Protected Overrides Sub Finalize()
    75. ' ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(disposing As Boolean)" ein.
    76. ' Dispose(disposing:=False)
    77. ' MyBase.Finalize()
    78. ' End Sub
    79. Public Sub Dispose() Implements IDisposable.Dispose
    80. ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(disposing As Boolean)" ein.
    81. Dispose(disposing:=True)
    82. GC.SuppressFinalize(Me)
    83. End Sub
    84. 'Public Function Read() As String
    85. 'End Function
    86. End Class



    Nun schau mal wie aufgeräumt die Form.Klasse ist, alles ist das wo es hingehöhrt.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private bt As New BluetoothUtil
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. If Not bt.Connect("HyperFlat-76") Then
    5. Close()
    6. End If
    7. End Sub
    8. Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    9. bt.Dispose()
    10. End Sub
    11. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    12. Dim dots As Integer = 255
    13. Dim data As String = Chr(27) & Chr(50) & Chr(0) & Chr(0)
    14. For Zaehler As Integer = 1 To 36
    15. data &= Chr(dots)
    16. Next
    17. bt.Write(data)
    18. End Sub
    19. End Class


    Edit @tron25
    Hab eine Projektmappe angehängt, probiers mal aus
    Dateien
    • WindowsApp1.zip

      (13,7 kB, 61 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Takafusa“ ()

    Vielen Dank für das ausführliche Beispiel. Ich habe den Code bei mir in eine extra Klasse gepackt und "New" bei

    VB.NET-Quellcode

    1. Client = BluetoothClient()

    hinzugefügt. Ich muß zugeben, dass ich bisher nicht so viel mit Funktionen und Klassen programmiert habe. Allerdings sollte ich mich schleunigst damit beschäftigen.

    Jetzt wollte ich das mit Async und Await versehen.

    VB.NET-Quellcode

    1. Public Async Function Connect(Devicename As String) As Task(Of Boolean)
    2. Try
    3. Dim DeviceInfo As BluetoothDeviceInfo = Nothing
    4. Client = New BluetoothClient()
    5. Dim Devices As BluetoothDeviceInfo() = Await Client.DiscoverDevices()
    6. ...

    Jetzt gibt er mir den Fehler
    "Der Not-Operator ist für den Typ "Task(Of Boolean)" nicht definiert."
    Die Zeile

    VB.NET-Quellcode

    1. If Not BluetoothVerbindung.Connect("HyperFlat-76") Then

    Ich hatte das so verstanden, dass die Funktion, die mehr Zeit benötigen könnte, mit dem Schlüsselwort "Async" und "As Task" versehen wird. Vor den Wert der Zuweisung in der entsprechenden Zeile sollte dann "Await" eingefügt werden. Das ist wohl nicht ganz so richtig.


    Ich habe mich nie wirklich mit Async/Await beschäftigt, ich bin altmodisch und nutze Threads, wobei eines Tages sollte ich das mal. Daher kann ich nicht viel dazu sagen. War aber im Stande die Function Connect asyncron auszuführen, da nur das DiscoverDevices lange dauert hab ich das in den Task gepackt, kannst aber theoretisch alles im Task machen. Das Form friert jedensfalls nicht ein, heist es wird wirklich asyncron ausgeführt.

    Meinste nicht auch, das das BT-Zeugs so in einer eigenen Klasse doch besser ist? Schon allein wegen der wiederverwendbarkeit?

    VB.NET-Quellcode

    1. Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. Dim res As Boolean = Await bt.Connect("HyperFlat-76")
    3. If Not res Then
    4. Close()
    5. End If
    6. End Sub


    VB.NET-Quellcode

    1. Public Async Function Connect(deviceName As String) As Task(Of Boolean)
    2. Try
    3. Dim deviceInfo As BluetoothDeviceInfo = Nothing
    4. client = New BluetoothClient()
    5. Dim devices As BluetoothDeviceInfo() = New BluetoothDeviceInfo() {}
    6. Await Task.Run(Sub()
    7. devices = client.DiscoverDevices()
    8. End Sub)
    9. For Each d As BluetoothDeviceInfo In devices
    10. If d.DeviceName.ToLower().Equals(deviceName.ToLower()) Then
    11. deviceInfo = d
    12. End If
    13. Next
    14. If deviceInfo Is Nothing Then
    15. MessageBox.Show("Kein Device mit dem Namen: " & deviceName & " gefunden!")
    16. Return False
    17. End If
    18. Dim endPoint As New BluetoothEndPoint(deviceInfo.DeviceAddress, BluetoothService.SerialPort)
    19. client.Connect(endPoint)
    20. If client.Connected Then
    21. stream = client.GetStream()
    22. Return True
    23. End If
    24. MessageBox.Show("Konnte keine Verbindung zum Device aufbauen!")
    25. Catch ex As PlatformNotSupportedException
    26. MessageBox.Show("Kein Bluetooth verfügbar!")
    27. End Try
    28. Return False
    29. End Function

    Das mit den Klassen ist schon aufgeräumter. Ich überlege, was ich noch in eigene Klassen packen kann.

    Ich habe die Brailleanzeige nun folgendermaßen geändert:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim Pinwert As Integer
    3. Dim Pinbelegung As New List(Of Integer)({1, 2, 4, 8, 16, 32, 64, 128})
    4. AktuelleZeile = ""
    5. X = Braille.ArrayLinks
    6. Y = Braille.ArrayOben
    7. For Block = 0 To 12
    8. AktuelleZeile &= Chr(27) & Chr(50) & Chr(Block) & Chr(0)
    9. For Zeile = 0 To 5
    10. If Block = 12 And Zeile = 4 Then
    11. Exit For
    12. End If
    13. For Abschnitt = 1 To 6
    14. Pinwert = 0
    15. For Pin = 0 To 7
    16. If PunktbildArray(X + Pin, Y + Zeile) > HelligkeitScroll.Value Then
    17. Pinwert += Pinbelegung(Pin)
    18. End If
    19. Next
    20. AktuelleZeile& &= Chr(Pinwert)
    21. X += 8
    22. Next
    23. X = Braille.ArrayLinks
    24. Next
    25. Y += 1
    26. Next
    27. BluetoothVerbindung.Write(AktuelleZeile)
    28. End Sub

    Beim übersetzen eines Bildes werden die Braillepunkte mit ihren Helligkeitswerten in einem Array gespeichert, sodass man durch das Verschieben der Helligkeitsschwelle das Bild heller bzw. dunkeler machen kann. Dabei wird das Braillebild nicht tatsächlich heller oder dunkeler, sondern es werden dann mehr oder weniger Punkte angezeigt. Hier siehst du am Beispiel eines meiner 3D-LKW (das ist mein zweites großes Hobby), wie es im Programm aussieht.
    Bilder
    • Screenshot (14).png

      140,99 kB, 1.600×900, 50 mal angesehen
    • Screenshot (15).png

      68,63 kB, 1.600×900, 49 mal angesehen
    • Screenshot (16).png

      69,11 kB, 1.600×900, 47 mal angesehen

    tron25 schrieb:

    Ich überlege, was ich noch in eigene Klassen packen kann.


    Ich lager nahezu alles was nicht direkt mit dem GUI zusammenhängt in eine Klasse ausserhalb der Form-Klasse aus. 3D Modelierung ist eine tolle Sache, ich arbeite viel mit Blender, deswegen habe ich Python gelernt, obwohl ich die Sprache hasse, in manchen Fällen mach oder ändere ich schneller ein Object via Code als von Hand.

    EIne Idee hätte ich noch, du erstellst die Daten für den Display in der Event-Sub von Button1. Ich täte nun eine Klasse anlegen, welche eine statische function hat(statisch = kannst ohne instanz drauf zugreifen), in VB geht das mit Shared)

    Die Funktion würde entweder ein Pfad zu einem Bild als Argument haben, oder auch ein Bitmap, ausgeben tut die Funktion dann die Daten für den Display. Dann haste in der Sub nur 2 Zeilen Code, könnte man auch in 1 zusammenfassen, könnte dann so aussehen:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. dim daten as String = NochNichtExistierendeKlasse.BildZuBrailleDatenString("pfad zum image")
    3. BluetoothVerbindung.Write(daten)
    4. end sub


    VB.NET-Quellcode

    1. public class NochNichtExistierendeKlasse
    2. public shared function BildZuBrailleDatenString(pfad as string)
    3. dim returnWert as string = .......
    4. return returnWert
    5. end sub
    6. end class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    Bevor ich mich an die neue Klasse mache, würde ich gerne noch das eine oder andere kleinere Problemchen lösen. Mit deinem Vorschlag mit Async und Await, kann ich keine Geschwindigkeitszunahme feststellen.
    Bei der ersten Zeile des nachfolgenden Codes bleibt er trotzdem hängen. Wenn ich sie auskommentiere, da sie, meiner Meinung nach das Gleiche macht, wie die SUB, bekomme ich eine Fehlermeldung.

    VB.NET-Quellcode

    1. Dim Devices As BluetoothDeviceInfo() = Client.DiscoverDevices()
    2. Await Task.Run(Sub()
    3. Devices = Client.DiscoverDevices()
    4. End Sub)

    Fehler:
    Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand
    Fehler BC30112 "Microsoft.VisualBasic.Devices" ist ein Namespace und kann nicht als Ausdruck verwendet werden. PunktBilder D:\Programmierung\PunktBilder\PunktBilder 2021\BluetoothKlasse.vb 24 Aktiv

    Das verstehe ich nicht so ganz, da ja in der SUB im Prinzip das Gleiche, wie darüber steht.

    tron25 schrieb:

    Fehler BC30112 "Microsoft.VisualBasic.Devices" ist ein Namespace und kann nicht als Ausdruck verwendet werden.


    Lösung: benenne die variable um, oder verwende nicht den besagten Namespace.

    tron25 schrieb:

    Mit deinem Vorschlag mit Async und Await, kann ich keine Geschwindigkeitszunahme feststellen.


    Asyncroner Code ist nicht schneller, da hast du was falsch verstanden, es verhindert nur das das Programm nicht reagiert, solange Code ausgeführt wird der länger braucht. Hast du sicher schon mal erlebt, das Programm läuft und du kannst das Fenster nicht verschieben oder schliessen, weil der GUI Thread blockiert ist, durch das asyncrone ausführen wird also die Blockierung des GUI Thread verhindert und nicht mit Magie nicht verhandene HardwareRessourcen herbeigezaubert.


    Nachtrag @tron25

    Takafusa schrieb:

    Dim devices As BluetoothDeviceInfo() = New BluetoothDeviceInfo() {}
    Await Task.Run(Sub()
    devices = client.DiscoverDevices()
    End Sub)


    Schau mal genau hin. Da ist ein grosser Unterschied. Du führst 2 mal client.DiscoverDevices() aus, ich nicht. Ich initialisiere einen leeren Array. Im Task rufe ich client.DiscoverDevices() auf. Den leeren Array initialisiere ich, weil es sonst eine Warnung vom Studio gibt, wegen der nicht initialisierten Variable.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Takafusa“ ()

    Da habe ich wohl die Klammern übersehen. Jetzt funktioniert es besser. Mittlerweile habe ich das Programm so angepaßt, das das Display automatisch angesprochen wird, wenn die Grafik sich ändert. Außerdem habe ich noch einige Menüpunkte für das Display hinzugefügt und ein paar Fehler korrigiert. Ich würde mich jetzt gerne an das Empfangen von Tastenbefehlen machen, bevor ich mit dem exportieren von Funktionen in Klassen beginne. Bei der seriellen Kommunikation gibt es ja das DataRecieve-Ereignis. Könnte man so etwas ähnliches auch hier einbauen oder brauche ich einen Timer, der in Intervallen prüft, ob Bytes angekommen sind? In der Klasse gibt es ja die Funktion "Read". in der Dokumentation von 32feed unter alanjmcf.me.uk/comms/bluetooth/32feet.NET -- User Guide.html gibt es den Punkt "Stream.Read and the number of bytes returned". Ich werde mir nachher mal den Artikel durchlesen müssen. Gibt es auch eine deutsche Übersetzung der Doku?
    Also die Doku scheint nur auf englisch zu sein. Ich habe mal zum schauen ob BluetoothClient Events beinhaltet, BluetoothClient als withevents deklariert und oben im codeditor in den ComboBoxen geschaut, aber keine Events da :( .

    Wirst du wohl mit einem Timer oder Thread versuchen müssen. Möglicherweise geht auch was mit Async.

    Um zu schauen ob Daten zum lesen da sind:

    VB.NET-Quellcode

    1. If client.Available > 0 Then
    2. 'lesen
    3. End If

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Takafusa“ ()

    So, jetzt bin ich wieder da. Mit einem Timer möchte ich nicht arbeiten, da das nicht sehr benutzerfreundlich ist, wenn man schnell hintereinander Knöpfe drückt und das Display sich etwas anders verhält. Mit Threads muß ich mich noch auseinandersetzen. Am liebsten würde ich gerne mit einem Empfangsereignis arbeiten. Meine Idee dazu ist, dass beispielsweise bei der seriellen Kommunikation es ein Data-Recieve-Ereigniss gibt. Da Bluetooth ja auch einen virtuellen COMM-Port erstellt, müßte es auch doch dort eine ähnliche Methode geben. Bis ich da eine Lösung gefunden habe, werde ich mich mit der Fertigstellung meines 1:18 3D VW T3 und mit dem Auslagern von Funktionen in Klassen beschäftigen.

    Falls man nichts mehr von einander liest, wünsche ich allen schöne Feiertage und einen guten Rutsch ins neue Jahr.
    Hallo, ich kanns nicht lassen und sitze schon wieder am Code.

    Ich habe versucht, mich in das Thema Threads und Delegaten einzulesen. Verstehe ich das folgendermaßen richtig?:

    1. Ich erstelle ein Thread, welcher permanent die Rückgabe von Tastendrücken überprüft
    2. Ich erstelle einen Delegaten, welcher den Thread startet und über invoke die Rückgabe überwacht
    3. Im Fall eines Tastendrucks wird der zurückgegebene Wert in eine Textbox oder Variable geschrieben, wo er dann ausgewertet werden kann

    Ist das die richtige Richtung? Leider habe ich im Netz kein sprechendes Beispiel gefunden. Es sind alles abstrakte Beispiele.
    Ich kanns auch nicht lassen. :D

    Also da du auch sendest, könnte es zu Problemen kommen, denn es kann passieren das du schreibst, wobei gerade ein Lesevorgang stattfindet, kann passieren mit mehreren threads, weiss nicht wie sich das mit gleichzeiten Ein-/Aus-gang verhält. Notfalls mit SyncLock arbeiten, so das entweder lesen oder schreiben geht.

    Mach zum testen des Empfangs am besten ein neues Projekt. Ich mach auch oft viele kleine Projekte die dann zu einem großen "verschmelzen". Erstelle einen Thread, starte ihn, in der Sub des Threads eine while scheife, ich bau mir immer einen boolean rein "exitRequested"

    VB.NET-Quellcode

    1. while not exitRequested
    2. .....

    So kann man den Thread sauber beenden(ohne abort). In der Schleife

    VB.NET-Quellcode

    1. If client.Available > 0 Then 'sollte funktionieren
    2. 'streamreader für den stream
    3. 'dim incomingText as string = streamreader.readtoend
    4. 'kurz schlafen legen um CPU zu sparen, sonst wird ein Kern unter vollast laufen. (Thread.Sleep)
    5. end if

    und ausgeben. Tasten drücken und schauen ob und was reinkommt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    Hallo,

    neues Jahr, neues Glück. Dass wünsche ich allen hier im Forum.

    VB.NET-Quellcode

    1. Corona.Dispose()


    Ich habe nun einen Thread eingebaut. Leider aber wohl nicht ganz fehlerfrei. Folgendes habe ich getan:

    In meiner Bluetoothklasse habe ich folgende Funktion:

    VB.NET-Quellcode

    1. Public Function Read(Data As String) As String
    2. Stream = Client.GetStream()
    3. ProcessThread
    4. Using StreamReader As New IO.StreamReader(Stream, System.Text.Encoding.Default, 1, True)
    5. StreamReader.Read(Stream)
    6. End Using
    7. Return Stream
    8. End Function


    In meinem Hauptformular habe ich folgendes eingefügt:

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class PunktbilderFormular
    3. Public HyperFlat76Thread As New Thread(adressof hyperflat76tastenabfrage)
    4. 'Wie man hier sehen kann, wird die Funktion HyperFlat76Tastenabfrage nicht erkannt.
    5. Dim HyperFlat76Ausfuehren As Boolean = False
    6. Public Sub PunktbilderFormular_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    7. Dim Verbunden As Boolean = Await BluetoothVerbindung.Connect("HyperFlat-76")
    8. If Not Verbunden Then
    9. Using InfoFenster As New InfoFormular
    10. InfoFenster.Text = "Hinweis"
    11. InfoFenster.Label1.Text = "Es Wurde kein HyperFlat gefunden. Bitte stellen sie sicher, das das Gerät gekoppelt und eingeschaltet ist."
    12. InfoFenster.ShowDialog(Me)
    13. End Using
    14. Else
    15. HyperFlat76Ausfuehren = True
    16. HyperFlat76Thread.Start()
    17. End If
    18. end sub
    19. Public Sub HyperFlat76Tastenabfrage()
    20. While HyperFlat76Ausfuehren
    21. TextBox1.Text = BluetoothVerbindung.Read
    22. Thread.Sleep(100)
    23. End While
    24. End Sub
    25. end class


    Folgende Fehlermeldung wird angezeigt:
    error BC32017: Komma, ")" oder eine gültige Ausdrucksfortsetzung erwartet.

    Folgende Zeile wird markiert und der Cursor wird in die Klammern zwischen "adressof" und "Hyperflat76tastenabfrage" gesetzt.

    VB.NET-Quellcode

    1. Public HyperFlat76Thread As New Thread(adressof hyperflat76tastenabfrage)


    Habe ich da was übersehen?
    Du hast recht, das "d" hat gefehlt.

    nun gibt es aber ein neues Problem. Da die Funktion "Read" in der Bluetoothklasse nur einen Wert zurückgibt, habe ich im Funktionskopf den Übergabeparameter entfernt.

    VB.NET-Quellcode

    1. Public Function Read() As String
    2. Stream = Client.GetStream()
    3. ' ProcessThread
    4. Using StreamReader As New IO.StreamReader(Stream, System.Text.Encoding.Default, 1, True)
    5. StreamReader.Read(Stream)
    6. End Using
    7. Return Stream.ToString
    8. End Function


    Da die Sub "HyperFlat76Tastenabfrage" von einem Thread aus gesteuert wird, habe ich die Textbox für den Rückgabewert durch eine Variable ersetzt.

    VB.NET-Quellcode

    1. Public Sub HyperFlat76Tastenabfrage()
    2. Dim Rueckgabewert As String
    3. While HyperFlat76Ausfuehren
    4. Rueckgabewert = BluetoothVerbindung.Read()
    5. Thread.Sleep(100)
    6. End While
    7. End Sub


    Nun bekomme ich folgende Fehlermeldung:
    Fehler BC30516 Fehler bei der Überladungsauflösung, da keine zugreifbare "Read" diese Anzahl von Argumenten akzeptiert.

    Ich dachte, das die "Read"-Funktion in der Bluetoothklasse den Stream ausliest und das Ergebnis als Text zurückgibt.
    Also du gehst die Sache nicht ganz richtig an. Denn wenn nichts zu lesen im Stream ist, kann es passieren das du bis es zum timeout für den LeseVorgang kommt, was durchaus auch nie sein kann, in der Zeile in der der StreamReader liest festhängst. Da der StreamReader versucht zu lesen, kann es sein, das wenn du zu der Zeit scheibst eine Exception eintritt, wegen gleichzeitigen ein/ausgang.

    Was hälst du nun davon ein eigenes Event einzubauen? Sobald Daten gelesen werde konnten, feuerst du ein eigenes Event. Auch im Loop im Thread, kannste den Thread deutlich kürzer schlafen legen, 1ms reicht schon, um die CPU Last deutlich zu senken.

    Ich hab jetzt nicht dein Projekt hier, also habe ich einfach mal das lesen in einer Klasse minimal dargestellt. Mit BlueToothClient.Available() bekommts du eine Zahl, der Wert sagt wie viele Bytes im Stream zum lesen da sind, nur wenn dieser Wert ungleich 0 ist, dann wird gelesen.

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Threading
    3. Imports InTheHand.Net
    4. Imports InTheHand.Net.Sockets
    5. Imports InTheHand.Net.Bluetooth
    6. Public Class BT
    7. Private worker As Thread
    8. Private exitRequested As Boolean = False
    9. Private stream As Stream
    10. Private Client As New BluetoothClient
    11. Public Event StringDataReceived(data As String)
    12. Public Sub StartPolling()
    13. If worker.IsAlive() Then
    14. throw new Exception("Ich mach doch schon....")
    15. End if
    16. exitRequested = False
    17. worker = New Thread(AddressOf HyperFlat76Tastenabfrage)
    18. worker.Start()
    19. End Sub
    20. Public Sub StopPolling()
    21. exitRequested = True
    22. End Sub
    23. Private Sub HyperFlat76Tastenabfrage()
    24. While Not exitRequested
    25. If Client.Available() > 0 Then
    26. stream = Client.GetStream()
    27. Using reader As New IO.StreamReader(stream, System.Text.Encoding.Default, 1, True)
    28. Dim txt As String = reader.ReadToEnd()
    29. RaiseEvent StringDataReceived(txt)
    30. End Using
    31. End If
    32. Thread.Sleep(1)
    33. End While
    34. End Sub
    35. End Class


    In der Klasse der Form mit der Instanz der Bluetooth Klasse, kannst nun das Event abbonieren, da das Event aber in einem anderen Thread gefeuert wird, noch Invoken, wenn erforderlich. Ändere die deklaration deiner Bluetooth-Klasse. Direkt als WithEvents.

    VB.NET-Quellcode

    1. Private WithEvents b As New BT
    2. Private Sub b_StringDataReceived(data As String) Handles b.StringDataReceived
    3. If InvokeRequired Then
    4. BeginInvoke(Sub() b_StringDataReceived(data))
    5. Else
    6. Me.Text = data
    7. End If
    8. End Sub

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    Ich habe deine Vorschläge eingearbeitet und an meinen Code angepaßt.

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Threading
    3. Imports InTheHand.Net
    4. Imports InTheHand.Net.Sockets
    5. Imports InTheHand.Net.Bluetooth
    6. Public Class BluetoothKlasse
    7. Implements IDisposable
    8. Private Client As New BluetoothClient
    9. Private Stream As Stream
    10. Private DisposedValue As Boolean
    11. Private Ausfuehren As Boolean
    12. Private Abfrage As Thread
    13. Public Event DatenEmpfangen(Daten As String)
    14. Public Sub EmpfangStarten()
    15. If Abfrage.IsAlive() Then
    16. Throw New Exception("Ich mach doch schon....")
    17. End If
    18. Ausfuehren = True
    19. Abfrage = New Thread(AddressOf HyperFlat76Tastenabfrage)
    20. Abfrage.Start()
    21. End Sub
    22. Public Sub EmpfangStoppen()
    23. Ausfuehren = False
    24. End Sub
    25. Private Sub HyperFlat76Tastenabfrage()
    26. While Ausfuehren
    27. If Client.Available() > 0 Then
    28. Stream = Client.GetStream()
    29. Using Rueckgabe As New IO.StreamReader(Stream, System.Text.Encoding.Default, 1, True)
    30. Dim Rueckgabetext As String = Rueckgabe.ReadToEnd()
    31. RaiseEvent DatenEmpfangen(Rueckgabetext)
    32. End Using
    33. End If
    34. Thread.Sleep(1)
    35. End While
    36. End Sub
    37. end class


    Im Hauptformular habe ich bei erfolgreicher Verbindung folgende Zeile hinzugefügt:

    VB.NET-Quellcode

    1. BluetoothVerbindung.EmpfangStarten()


    Nun bekomme ich die folgende Fehlermeldung:
    System.NullReferenceException: "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."
    "Abfrage" war "Nothing".

    Markiert wird dabei die Zeile:

    VB.NET-Quellcode

    1. If Abfrage.IsAlive() Then


    Wenn ich den Zusatz "New" in die Zeile

    VB.NET-Quellcode

    1. Private Abfrage As Thread

    hinzufüge, erscheint folgende Meldung:
    error BC30516: Fehler bei der Überladungsauflösung, da keine zugreifbare "New" diese Anzahl von Argumenten akzeptiert.

    Ich dachte, dass man mit "New" eine neue Instanz erstellen kann.

    In der Überwachung steht bei "Abfrage" der Wert "Nothing". Wenn ich nun die entsprechende Zeile in

    VB.NET-Quellcode

    1. If Not Abfrage = Nothing Then

    ändere, bekomme ich die folgende Antwort:
    error BC30452: Der =-Operator ist für die Typen "Thread" und "Thread" nicht definiert.

    Syntaktisch scheint der Code fehlerfrei zu sein, da keine Fehlermeldung erscheint, wenn ich den Thread nicht starte.
    Jetzt bekomme ich die folgende Meldung:
    System.ArgumentOutOfRangeException: "Positive Zahl erforderlich.
    Parametername: bufferSize"

    Ich habe statt "1" den Wert von client.available() eingesetzt. So, wie ich es aus der Überwachung verstanden habe, ist dieser Wert die Rückgabegröße. Leider hat es nicht funktioniert.

    Was mich allerdings noch etwas verunsichert, das eine Variable "Stream" deklariert wird, die genauso heißt, wie das Objekt "Stream". Natürlich habe ich auch getestet, was geschieht, wenn ich den Variablennamen in der ganzen Klasse in "Datenstrom" ändere. - Das Programm wird ohne Kommentar beendet. Also, habe ich die Änderungen rückgängig gemacht und den Ausnahmefehler wieder erhalten.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „tron25“ ()