Hallo Forum,
ich habe mich bisher mit hardwarenaher Programmierung beschäftigt und
will nun meine erste App umsetzen.
Zu diesem Zweck will ich ein Projekt auf Basis von BluetoothChat
realisieren.
https://developer.android.com/samples/BluetoothChat/index.html
Konkret geht es um eine Mikrocontroller-Platine, die über ein
BTM222-Bluetooth-Modul mit einem Smartphone/Tablet kommunizieren soll.
Über Sensoren auf der Platine werden Messwerte aufgenommen, und sollen
auf dem Tablet dargestellt werden.
Die Anzeige soll allerdings nicht als einfacher Fließtext erfolgen,
sondern die Messwerte sollen immer an einer bestimmten Stelle in der App
angezeigt werden.
Der Datenstrom, der vom Mikrocontroller kommt, ist variabel und kann
flexibel an die Anforerungen der App angepasst werden.
Die App müsste aus diesem Datenstrom nur die einzelnen Messwerte filtern
und an der richtigen Stelle ausgeben.
Ich stelle mir das so vor:
Mikrocontroller sendet per Bluetooth: "T:27,1;RH:35;P:1013..."
Die App soll nun aus diesem Datenstrom erkennen: T ist die Temperatur,
Ausgabe des Werts an der entsprechenden Stelle, RH ist die
Luftfeuchtigkeit und so weiter.
Mit welcher Methode kann ich den ankommenden SPP-Datenstrom auf diese
Art analysieren?
Vielen Dank,
Johnny
danke für das Stichwort, allerdings schreibe ich die App in Java
(Android Studio).
zum Stichwort "Android Parser" findet sich relativ schnell der Begriff
XML-Parser.
Macht es sinn, den Datenstrom kommend vom µC XML-ähnlich zu formatieren?
Bsp: "<t>:27,1</t><rh>35</rh><p>1013</p>..."
ich will die Daten nicht speichern, sondern nur einmalig ausgeben.
Wie baue ich einen solchen simplen Parser am einfachsten auf?
Vielen Dank.
Überleg dir halt wie du das im Kopf machen würdest ...
"T:27,1;RH:35;P:1013".split(;);
teilt den String bei den Strichpunkten. So erhältst du ein Array mit
drei Einträgen:
T:27,1
RH:35
P:1013
Jeden dieser Einträge teilst du jetzt nochmal bei : und schon kannst du
ganz einfach das erste Feld auswerten und entsprechend das zweite
Anzeigen.
zunächst einmal Danke für die Ideen.
Zuvor steht allerdings noch ein grundsätzliches Problem:
Wenn ich zwei Smartphones mit der BluetoothChat-App verbinde, können
unbegrenzt viele Zeichen in einer Nachricht übermittelt werden.
Bei einer Verbindung mit meinem Mikrocontroller-BT-Modul werden die
Nachrichten unterbrochen.
Die Ausgabe sieht dann aus wie folgt:
"BTM222: T:2
BTM222: 7,2;R
BTM222: H:35;P:
BTM222: 1013 usw."
Ich kann nicht nachvollziehen, wie dieser unregelmäßige Umbruch
entsteht.
Jemand einen Ansatz?
Ist doch egal, du entfernst alle "BTM222: ", die Umbrüche entfernst du
auch, da die Umbrüche eh direkt vor dem "BTM222: " stehen machst du das
in einem Schritt. Danach zerlegst du, wie schon geschrieben den string
weiter.
Schau dir mal JSON an. Das wäre genau das, was du suchst Außerdem gibt
es dafür in Android schon einen Parser um die Strings dann zu
dekodieren. Für den µC gibt es sicherlich auch ein Lib.
Dein andere Problem kommt mir bekannt vor. Ich habe selbst mal mit dem
BluetoothChat rumexperimentiert.
Okay das Parsen gucke ich mir direkt an, wenn ich die Grundstruktur
innerhalb des BluetoothChats etwas besser nachvollziehen kann.
Momentan knobel ich noch an den Umbrüchen, die erzeugt werden, wenn ich
Daten des µCs empfange.
Mir ist noch nicht ganz klar, an welcher Stelle genau der Text
zusammengesetzt wird, der letztendlich ausgegeben wird, also das:
"BTM222: ...."
Den Namen des Kommunikationspartners, der eingeblendet wird, wird
automatisch erkannt und voran gestellt.
Wenn ich das richtig sehe, werden die eingehenden Daten hier
verarbeitet:
1
private class ConnectedThread extends Thread {
2
private final BluetoothSocket mmSocket;
3
private final InputStream mmInStream;
4
private final OutputStream mmOutStream;
5
6
public ConnectedThread(BluetoothSocket socket, String socketType) {
// Get the BluetoothSocket input and output streams
13
try {
14
tmpIn = socket.getInputStream();
15
tmpOut = socket.getOutputStream();
16
} catch (IOException e) {
17
Log.e(TAG, "temp sockets not created", e);
18
}
19
20
mmInStream = tmpIn;
21
mmOutStream = tmpOut;
22
}
Es macht wohl einen Unterschied, wenn statt
"private final OutputStream mmOutStream;"
"private final DataOutputStream mmOutStream;"
gesetzt wird.
Dieses Problem wird an anderer Stelle oft besprochen, nur der
Unterschied ist mir noch nicht ganz klar.
Das Lesen aus dem Stream findet aber in der "run()"-Methode hier statt:
// Read from the InputStream
bytes = mmInStream.read(buffer);
Ist der buffer vielleicht zu klein?
Johnny E. schrieb:> Der Buffer ist ein Array aus 1024 "bytes".>> ich hatte das probehalter schon deutlich größer gemacht, ohne> erkennbaren Einfluss auf die Ausgabe.
Das ist ein generelles 'Problem'.
Du kannst bei jeglicher Verbindung an die du dich anklemmst
normalerweise nie davon ausgehen, dass die Daten in genau derselben
Strukturierung aus dem Kanal rauspurzeln, wie sie der Sender auf den Weg
geschickt hat.
Der Sender sendet aus seiner Sicht eine komplette Zeile (die er zb mit
einem \n abschliesst). Aber aus den Empfangsroutinen purzeln die
Character eben nicht wieder als komplette Zeile raus. Allgemeine
Empfangsroutinen wissen nichts von einer Zeilenstruktur in den Daten.
Sie geben das weiter, was zum Zeitpunkt des Aufrufs der Funktion an
Daten bereits empfangen wurde. Das heisst aber nicht, dass das zb eine
komplette Zeile wäre. Du kannst ja die Empfangsfunktion ja auch schon
aufgerufen haben noch ehe der Sender die komplette Zeile überhaupt
weggeschickt hat.
D.h. du selbst bist dafür zuständig, die einzelnen Textfragmente wieder
zu einer komplette Zeile zusammenzusetzen.
und das 'BTM222'. Na ja. Du hast doch den Code für die Routinen. Sieh
halt nach, wer diesen Text in die zurückgegebenen Stringteile einfügt
und wirf das raus.
Vielen Dank für die Anregung.
Ich bin nun schon einen Schritt weiter und habe mich für das
Übertragungsprotokoll für ein JSON-artiges Format entschieden.
Dies soll in Java einfach zu parsen sein.
Die µC-Ausgabe sieht aus wie folgt:
okay, das Problem ist gelöst.
Anderes Thema: ich will, dass sich die App nach dem Start automatisch
mit genau meinem Modul verbindet.
Das Modul ist im System bekannt und bereits gepairt.
Die App muss diese Verbindung also nur aufgreifen.
Wie kann ich das realisieren?
edit:
ich habe zu diesem Thema folgenden Beitrag gefunden:
http://stackoverflow.com/a/17120498/4995080
nur ist mir nicht ganz klar, an welcher Stelle in dem Projekt dieser
Code eingepflegt werden muss.
in die Klasse BluetoothChatService.java oder BluetoothChatFragment.java?
Hier ein paar Auszüge aus meinem Code den ich vor Jahren für einen
Kunden geschrieben habe.
Hier zuerst einmal der Code wie man an ein bestimmtes Device gelangt
So findet man ein paired Device:
Irgenwo im Bluetooth gewurschtel code findest du eine Zeile, die den BT
Socket erzeugt:
tmp = mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID);
Du musst jetzt nur noch mBtdevice im meinem Code durch deinen variablen
Namen ersetzen.
weiter ..
Warum liest du immer den Kompletten Buffer ein und nicht nur soviel
Zeichen wie du gerade zum parsen brauchst ..
InputStream kann das alles, aber da müsste man ja Doku lesen ...
Weil void run() keine "einfache" Methode sondern ein Thread ist, musst
du deine Nachrichten an die GUI (Activity) mit Hilfe eines Handlers
schicken.
Der Handler kann auch viele Formate und nicht nur buffer verschicken.
Aber auch hier muss man die Doku lesen und sich nicht alles vorkauen
lassen.
vielen Dank für deinen Beitrag.
Zunächst, das Problem mit dem BufferedReader und readLine ist, wie ich
bereits geschrieben habe, gelöst.
Der ankommende Datenstrom wird Zeile für Zeile gelesen, gesplittet und
entsprechend weiter verarbeitet.
Nun geht es um die Erweiterung/Automatisierung von Funktionen, deshalb
meine Frage nach dem Autoconnect.
Im ursprünglichen BluetoothChat wird die Auswahl des BT-Partners in der
Klasse DeviceListActivity vorgenommen.
Das Öffnen des BluetoothSockets geschieht in der Klasse
BluetoothChatService.
Meinem Verständnis nach müsste das automatische Verbinden mit meinem
BT-Modul im onCreate des BluetoothChatFragments geschehen, oder?
ich habe die Codezeilen in die Methode onResume der
BluetoothChatFragment eingefügt.
Sie werden erfolgreich abgearbeitet, über Logcat kann ich mir die
gepairten Geräte mit Namen und MAC-Adresse ausgeben lassen.
Die MAC Adresse meines Geräts habe ich folgendermaßen eingegeben:
jetzt muss ich das mBtDevice verwenden, um die Kommunikation aufzubauen.
Mir ist jetzt nicht ganz klar, wie ich das aus der Klasse
BluetoothChatFragment heraus tue.