RFCOMM Verbindung Programmieren

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • RFCOMM Verbindung Programmieren

    Hallo zusammen,
    anlässlich eines Studium Projektes befasse ich mich neuerdings mit Java.
    Das geplante Projekt ist ein per Android App (Bluetooth) gesteuertes Modellauto mittels Raspberry Pi.

    Das Layout/Design und einige kleine Funktionen der App funktionieren bereits.
    Allerdings hänge ich seit Tagen an der Steuerung bzw. Verbindung des Raspberry Pis.
    Gedacht sei es eine RFCOMM Verbindung herzustellen (Raspberry = Server , Smartphone = Client) um Python Skripte am Pi über das Smartphone zu starten (Lenkung, Gas, Bremse).

    Nun nach etlicher Recherche im Internet bin ich auf ein Java Skript gestoßen welches eine Verbindung mit dem Pi herstellt und eine LED ein und ausschalten soll (mit jeweiligen Buttons)

    Java-Quellcode

    1. import java.io.IOException;
    2. import java.io.InputStream;
    3. import java.io.OutputStream;
    4. import java.util.Set;
    5. import java.util.UUID;
    6. import android.app.Activity;
    7. import android.bluetooth.BluetoothAdapter;
    8. import android.bluetooth.BluetoothDevice;
    9. import android.bluetooth.BluetoothSocket;
    10. import android.content.Intent;
    11. import android.os.Bundle;
    12. import android.os.Handler;
    13. import android.util.Log;
    14. import android.view.Menu;
    15. import android.view.View;
    16. import android.widget.Button;
    17. import android.widget.TextView;
    18. public class MainActivity extends Activity {
    19. BluetoothSocket mmSocket;
    20. BluetoothDevice mmDevice = null;
    21. final byte delimiter = 33;
    22. int readBufferPosition = 0;
    23. public void sendBtMsg(String msg2send)
    24. {
    25. //UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard SerialPortService ID
    26. UUID uuid = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee"); //Standard SerialPortService ID
    27. try
    28. {
    29. mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
    30. if (!mmSocket.isConnected()){
    31. mmSocket.connect();
    32. }
    33. String msg = msg2send;
    34. //msg += "\n";
    35. OutputStream mmOutputStream = mmSocket.getOutputStream();
    36. mmOutputStream.write(msg.getBytes());
    37. }
    38. catch (IOException e)
    39. {
    40. // TODO Auto-generated catch block
    41. e.printStackTrace();
    42. }
    43. }
    44. @Override
    45. protected void onCreate(Bundle savedInstanceState)
    46. {
    47. super.onCreate(savedInstanceState);
    48. setContentView(R.layout.activity_main);
    49. final Handler handler = new Handler();
    50. final TextView myLabel = (TextView) findViewById(R.id.btResult);
    51. final Button tempButton = (Button) findViewById(R.id.tempButton);
    52. final Button lightOnButton = (Button) findViewById(R.id.lightOn);
    53. final Button lightOffButton = (Button) findViewById(R.id.lightOff);
    54. BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    55. final class workerThread implements Runnable
    56. {
    57. private String btMsg;
    58. public workerThread(String msg)
    59. {
    60. btMsg = msg;
    61. }
    62. public void run()
    63. {
    64. sendBtMsg(btMsg);
    65. while(!Thread.currentThread().isInterrupted())
    66. {
    67. int bytesAvailable;
    68. boolean workDone = false;
    69. try
    70. {
    71. final InputStream mmInputStream;
    72. mmInputStream = mmSocket.getInputStream();
    73. bytesAvailable = mmInputStream.available();
    74. if(bytesAvailable > 0)
    75. {
    76. byte[] packetBytes = new byte[bytesAvailable];
    77. Log.e("Aquarium recv bt","bytes available");
    78. byte[] readBuffer = new byte[1024];
    79. mmInputStream.read(packetBytes);
    80. for(int i=0;i<bytesAvailable;i++)
    81. {
    82. byte b = packetBytes[i];
    83. if(b == delimiter)
    84. {
    85. byte[] encodedBytes = new byte[readBufferPosition];
    86. System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
    87. final String data = new String(encodedBytes, "US-ASCII");
    88. readBufferPosition = 0;
    89. //The variable data now contains our full command
    90. handler.post(new Runnable()
    91. {
    92. public void run()
    93. {
    94. myLabel.setText(data);
    95. }
    96. });
    97. workDone = true;
    98. break;
    99. }
    100. else
    101. {
    102. readBuffer[readBufferPosition++] = b;
    103. }
    104. }
    105. if (workDone == true)
    106. {
    107. mmSocket.close();
    108. break;
    109. }
    110. }
    111. } catch (IOException e) {
    112. // TODO Auto-generated catch block
    113. e.printStackTrace();
    114. }
    115. }
    116. }
    117. };
    118. // start temp button handler
    119. tempButton.setOnClickListener
    120. (new View.OnClickListener()
    121. {
    122. public void onClick(View v)
    123. {
    124. // Perform action on temp button click
    125. (new Thread(new workerThread("temp"))).start();
    126. }
    127. }
    128. );
    129. //end temp button handler
    130. //start light on button handler
    131. lightOnButton.setOnClickListener(new View.OnClickListener() {
    132. public void onClick(View v) {
    133. // Perform action on temp button click
    134. (new Thread(new workerThread("lightOn"))).start();
    135. }
    136. });
    137. //end light on button handler
    138. //start light off button handler
    139. lightOffButton.setOnClickListener(new View.OnClickListener()
    140. {
    141. public void onClick(View v) {
    142. // Perform action on temp button click
    143. (new Thread(new workerThread("lightOff"))).start();
    144. }
    145. });
    146. // end light off button handler
    147. if(!mBluetoothAdapter.isEnabled())
    148. {
    149. Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    150. startActivityForResult(enableBluetooth, 0);
    151. }
    152. Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    153. if(pairedDevices.size() > 0)
    154. {
    155. for(BluetoothDevice device : pairedDevices)
    156. {
    157. if(device.getName().equals("PiBluetooth")) {
    158. Log.e("Aquarium",device.getName());
    159. mmDevice = device;
    160. break;
    161. }
    162. }
    163. }
    164. }
    Alles anzeigen


    Das dazugehörige Python Skript auf dem Pi sieht folgendermaßen aus:

    Python-Quellcode

    1. import os
    2. import glob
    3. import time
    4. import RPi.GPIO as GPIO
    5. from bluetooth import *
    6. os.system('modprobe w1-gpio')
    7. os.system('modprobe w1-therm')
    8. GPIO.setwarnings(False)
    9. GPIO.setmode(GPIO.BCM)
    10. GPIO.setup(17, GPIO.OUT)
    11. server_sock=BluetoothSocket( RFCOMM )
    12. server_sock.bind(("",PORT_ANY))
    13. server_sock.listen(1)
    14. port = server_sock.getsockname()[1]
    15. uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
    16. advertise_service( server_sock, "AquaPiServer",
    17. service_id = uuid,
    18. service_classes = [ uuid, SERIAL_PORT_CLASS ],
    19. profiles = [ SERIAL_PORT_PROFILE ],
    20. # protocols = [ OBEX_UUID ]
    21. )
    22. while True:
    23. print "Waiting for connection on RFCOMM channel %d" % port
    24. client_sock, client_info = server_sock.accept()
    25. print "Accepted connection from ", client_info
    26. try:
    27. data = client_sock.recv(1024)
    28. if len(data) == 0: break
    29. print "received [%s]" % data
    30. if data == 'temp':
    31. data = str(read_temp())+'!'
    32. elif data == 'lightOn':
    33. GPIO.output(17,False)
    34. data = 'light on!'
    35. elif data == 'lightOff':
    36. GPIO.output(17,True)
    37. data = 'light off!'
    38. else:
    39. data = 'WTF!'
    40. client_sock.send(data)
    41. print "sending [%s]" % data
    42. except IOError:
    43. pass
    44. except KeyboardInterrupt:
    45. print "disconnected"
    46. client_sock.close()
    47. server_sock.close()
    48. print "all done"
    49. break
    Alles anzeigen

    Nun das ganze funktioniert soweit auch nur bedingt.
    Die Verbindung wird bei jedem einzelnen "Knopfdruck" getrennt und anschließend wartet er auf eine neue Verbindung.
    [Blockierte Grafik: https://1drv.ms/u/s!AtpcnnBEDRKmkxOBARjXY0rVEE2e]
    Meine zunächst erst Frage ist nun:
    Wie muss der Java Code geändert werden um nur eine einmalige RFCOMM Verbindung aufzubauen?
    Ich bitte um Hilfe ich kämpfe hier schon den ganzen Tag ohne eine Lösung.

    Mit freundlichen Grüßen
  • Hallo, erstmal Willkommen im Forum.


    Mit jedem Tasten klick startest du deinen „workerThread“ der Startet und beendet auch wieder die Verbindung.
    in der „sendBtMsg“ Methode erstellst du jedes Mal wieder ein neues Socket und auch einen neuen OutputStream und baust somit wieder eine Verbindung auf.


    In deinem WorkerThread baust du mit sendBTMsg eine Verbindung auf, sendest deine Daten. Wartest auf eine Antwort, in der while Schleife (Inputstream), nach erhalt einer Antwort wird die Verbindung in Zeile 136 beendet.
    Als Antwort reicht auch ein automatischer Respond vom Bluetooth-Stack denke das Python da was sendet auch wenn du selber nichst in deinen Python Programm sendest.
    Das wird wohl der Stack selber machen. OBEX ist doch Verbindung orientiert, wenn ich mich jetzt nicht täusche.


    Halte das Socket und die Streams solange wie du auch die Verbindung haben willst.


    Nun nach etlicher Recherche im Internet bin ich auf ein Java Skript gestoßen
    Bbringe bitte Java Skript und Java nicht durcheinander. Android ist Java, das sind zwei paar Schuhe.
    Ein Feedback auf Tipps ist auch schön. :P

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von jogimuc ()

  • Danke für die schnelle Antwort.

    Das klingt plausibel. Soweit hatte ich den Code auch verstanden. Kommentiere ich aber Zeile 136 aus ändert es nichts und die Verbindung wird trotzdem getrennt.

    jogimuc schrieb:



    Bbringe bitte Java Skript und Java nicht durcheinander. Android ist Java, das sind zwei paar Schuhe.
    Sorry da hatte ich mich falsch ausgerückt. Ich meinte nicht die Sprache javaskript sondern das Java Skript (Java Code).
  • Hi es reicht nicht nur die Zeile auszukommentieren.

    Du darfst nicht immer wieder eine neues Socket erstellen.
    das machst du auch mit auskommentierter zeile immer noch.

    Erstelle es in onCreate oder besser in der onResume und beim verlassen der App in onPause beendest du es wieder. Dazu musst du einiges in deinem Code ändern.
    In der onResume immer Prüfen ob es schon existiert.
    Ein Feedback auf Tipps ist auch schön. :P
  • Du hast doch für dein socket schon eine globale Klassen variable erstellt. Also reicht es doch wenn du beim App Start ein socket host und somit die Verbindung aufbaut. Beenden tust du sie beim verlassen der app oder activity.
    Somit bleibt die Verbindung über die gesamte Laufzeit erhalten. Du bachst somit nur noch in deinen outputstream schreiben.
    Dazu sind einige Änderungen. Notwendig die du bestimmt Schaft denn den Code scheinst du ja nun verstanden zu haben. Mache dir klar was passiert wen du auf einen Button klickst da rufst du jedes mal deine worker Methode auf und auch da wird jedesmal eine neue Verbindung aufgebaut. Das ist unnötig.

    Wozu hast du sonst globale Variablen.

    PS auch startest du jedesmal mit jeden Klick einen neuen thread ob der alte beendet wurde weißt du auch nicht. Denn du startest einen neuen thread und auch eine neue Verbindung socket.

    Bin im Moment nur am Handy und da ist mir coden echt zu mühsam. Aber du willst es doch sowieso selber schaffen.
    Ein Feedback auf Tipps ist auch schön. :P

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von jogimuc ()

  • Vielen Dank für die Tipps.

    Habe den Code nun einmal komplett bearbeitet:

    Java-Quellcode

    1. public class RCCar extends AppCompatActivity {
    2. BluetoothDevice mmDevice = null;
    3. BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    4. Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    5. final Handler connectionsuccess = new Handler();
    6. private Button btn_connect;
    7. @Override
    8. protected void onCreate(Bundle savedInstanceState)
    9. {
    10. super.onCreate(savedInstanceState);
    11. setContentView(R.layout.activity_main);
    12. //ToolBar Transparent
    13. getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    14. btn_connect = (Button) findViewById(R.id.connect);
    15. btn_connect.setOnClickListener(new View.OnClickListener() {
    16. @Override
    17. public void onClick(View v)
    18. {
    19. for (BluetoothDevice device : pairedDevices)
    20. {
    21. if (device.getName().equals("PiBluetooth"))
    22. {
    23. Log.e("PiBluetooth", device.getName());
    24. mmDevice = device;
    25. break;
    26. }
    27. }
    28. ConnectThread thread1 = new ConnectThread(mmDevice);
    29. thread1.start();
    30. }
    31. });
    32. }
    33. private class ConnectThread extends Thread {
    34. private final BluetoothSocket mmSocket;
    35. private static final String TAG = "ConnectThread";
    36. UUID MY_UUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee");
    37. public ConnectThread(BluetoothDevice device) {
    38. BluetoothSocket tmp = null;
    39. try {
    40. tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
    41. } catch (IOException e) {
    42. Log.e(TAG, "Socket's create() method failed", e);
    43. }
    44. mmSocket = tmp;
    45. }
    46. public void run() {
    47. mBluetoothAdapter.cancelDiscovery();
    48. try {
    49. mmSocket.connect();
    50. if (mmSocket.isConnected()) {
    51. connectionsuccess.post(new Runnable() {
    52. @Override
    53. public void run() {
    54. Toast.makeText(RCCar.this, "Erfolgreich Verbunden", Toast.LENGTH_SHORT).show();
    55. }
    56. });
    57. }
    58. } catch (IOException connectException) {
    59. try {
    60. mmSocket.close();
    61. } catch (IOException closeException) {
    62. Log.e(TAG, "Could not close the client socket", closeException);
    63. }
    64. return;
    65. }
    66. }
    67. public void cancel() {
    68. try {
    69. mmSocket.close();
    70. } catch (IOException e) {
    71. Log.e(TAG, "Could not close the client socket", e);
    72. }
    73. }
    74. }
    75. }
    Alles anzeigen

    Hiermit habe ich einen Button "Connect" welcher mich mit meinem Pi verbindet und diese auch hält.

    Als nächstes werde ich mich etwas in InputStream und OutputStream einlesen müssen. Da ich momentan noch nicht weis was da genau passiert.
    Ich denke das beantwortet zunächst deine Fragen.
  • Hallo
    Leider nein das beantwort nicht meine Frage.
    Ich wollte wissen ob der Thread den du mit einem Tasten Klick startest auch beendet wird. Denn wenn dein Pi nichts sendet läuft der ewig den die While Schleife bekommt nur wenn etwas gesendet wird oder eine Exeption stattfindet eine Abbruch Bedingung . und wenn der Pi nichts sendet wird nie eines deiner „break“ aufgerufen und die Schleife und somit der Thread wird nie beendet . Deshalb habe ich nach dem Log gefragt was du drin hast in Zeile 103 hast. Wenn das durchlaufen wird und somit eine Meldung in der LogCat ausgibt wüstetest du das der Pi was gesendet und du ach etwas empfangen hast und somit die Möglichkeit für ein beenden der Thread gegeben ist.
    Da du in deinem Fall, gar keine Antwort auf einen einer deiner Befehle an dem PI, erwartest und auch nicht notwendig sind kannst du das Warten auf Antwort auch weglassen.

    Zu deinem Neuen Code.
    Die Verbindung bleibt zwar bestehen . Wie willst du darauf zugreifen oder sie beenden?
    Bendet wird sie nur wenn beim aufbau beim "Connect" etwas schief geht und eine Exeption geworfen wird . Da willst du sie beebden obwohl sie warschienlich garnicht erst zustande gekommen ist.


    Ich denke das du das Prinzip eines Thread noch nicht verstanden hast.
    Du kannst nicht auf dein Socket zugreifen. Da du es lokal in der Klasse Thread erstellt hast. Ein Thread wird erstellt und läuft einfach durch, ist er beendet kannst du nicht mehr auf variablen zugreifen die im Thread erstellt wurden, beim erneuten Aufruf des Threads wird eine neue Instanz erstellt und alles beginnt von vorne. Der Konstruktor wird wieder durchlaufen die Run wird gestartet… Auch dein Stocket wird neu erstellt.
    Das alte Stocket kannst du somit nicht mehr beenden.

    Benutze dafür eine globale Variable so wie dein BluetoothDevice in Zeile 3.
    Dies geht arber nur weil du eine Innerer Klasse hast und somit auf die Globalen variablen der Main zu greifen kannst.
    wenn du eine eigene Klasse in eigner Datei machst geht das nicht . dann must du das Soket dem Kostruktor mit übergeben.



    Um zu sehen Was wo wie wann passiert schaue dir mal Log und LogCat an .
    Füge dazu an dein entsprechenden stellen ein Log ein, und kannst verfolgen weher Code wann durchlaufen wird. Ist am anfing sehr hilfreich für das Verständnis.


    Habe mal deinen Ersten Code etwas geändert so sollte die Verbindung erhalten bleiben.

    Quellcode

    1. public class MainActivity extends Activity {
    2. BluetoothSocket mmSocket;
    3. BluetoothDevice mmDevice = null;
    4. OutputStream mmOutputStream = null;
    5. /*final byte delimiter = 33;
    6. int readBufferPosition = 0;*/
    7. public void sendBtMsg(String msg2send)
    8. {
    9. //UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard SerialPortService ID
    10. UUID uuid = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee"); //Standard SerialPortService ID
    11. try
    12. {
    13. if (!mmSocket.isConnected()){
    14. mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
    15. mmSocket.connect();
    16. }
    17. String msg = msg2send;
    18. //msg += "\n";
    19. if ( ! mmOutmmOutputStream) mmOutputStream = mmSocket.getOutputStream();
    20. mmOutputStream.write(msg.getBytes());
    21. }
    22. catch (IOException e)
    23. {
    24. // TODO Auto-generated catch block
    25. e.printStackTrace();
    26. }
    27. }
    28. @Override
    29. protected void onCreate(Bundle savedInstanceState)
    30. {
    31. super.onCreate(savedInstanceState);
    32. setContentView(R.layout.activity_main);
    33. final Handler handler = new Handler();
    34. final TextView myLabel = (TextView) findViewById(R.id.btResult);
    35. final Button tempButton = (Button) findViewById(R.id.tempButton);
    36. final Button lightOnButton = (Button) findViewById(R.id.lightOn);
    37. final Button lightOffButton = (Button) findViewById(R.id.lightOff);
    38. BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    39. final class workerThread implements Runnable
    40. {
    41. private String btMsg;
    42. public workerThread(String msg)
    43. {
    44. btMsg = msg;
    45. }
    46. public void run()
    47. {
    48. sendBtMsg(btMsg);
    49. /* while(!Thread.currentThread().isInterrupted())
    50. {
    51. int bytesAvailable;
    52. boolean workDone = false;
    53. try
    54. {
    55. final InputStream mmInputStream;
    56. mmInputStream = mmSocket.getInputStream();
    57. bytesAvailable = mmInputStream.available();
    58. if(bytesAvailable > 0)
    59. {
    60. byte[] packetBytes = new byte[bytesAvailable];
    61. Log.e("Aquarium recv bt","bytes available");
    62. byte[] readBuffer = new byte[1024];
    63. mmInputStream.read(packetBytes);
    64. for(int i=0;i<bytesAvailable;i++)
    65. {
    66. byte b = packetBytes[i];
    67. if(b == delimiter)
    68. {
    69. byte[] encodedBytes = new byte[readBufferPosition];
    70. System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
    71. final String data = new String(encodedBytes, "US-ASCII");
    72. readBufferPosition = 0;
    73. //The variable data now contains our full command
    74. handler.post(new Runnable()
    75. {
    76. public void run()
    77. {
    78. myLabel.setText(data);
    79. }
    80. });
    81. workDone = true;
    82. break;
    83. }
    84. else
    85. {
    86. readBuffer[readBufferPosition++] = b;
    87. }
    88. }
    89. if (workDone == true)
    90. {
    91. mmSocket.close();
    92. break;
    93. }
    94. }
    95. } catch (IOException e) {
    96. // TODO Auto-generated catch block
    97. e.printStackTrace();
    98. }
    99. }*/
    100. }
    101. };
    102. // start temp button handler
    103. tempButton.setOnClickListener
    104. (new View.OnClickListener()
    105. {
    106. public void onClick(View v)
    107. {
    108. // Perform action on temp button click
    109. (new Thread(new workerThread("temp"))).start();
    110. }
    111. }
    112. );
    113. //end temp button handler
    114. //start light on button handler
    115. lightOnButton.setOnClickListener(new View.OnClickListener() {
    116. public void onClick(View v) {
    117. // Perform action on temp button click
    118. (new Thread(new workerThread("lightOn"))).start();
    119. }
    120. });
    121. //end light on button handler
    122. //start light off button handler
    123. lightOffButton.setOnClickListener(new View.OnClickListener()
    124. {
    125. public void onClick(View v) {
    126. // Perform action on temp button click
    127. (new Thread(new workerThread("lightOff"))).start();
    128. }
    129. });
    130. // end light off button handler
    131. if(!mBluetoothAdapter.isEnabled())
    132. {
    133. Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    134. startActivityForResult(enableBluetooth, 0);
    135. }
    136. Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    137. if(pairedDevices.size() > 0)
    138. {
    139. for(BluetoothDevice device : pairedDevices)
    140. {
    141. if(device.getName().equals("PiBluetooth")) {
    142. Log.e("Aquarium",device.getName());
    143. mmDevice = device;
    144. break;
    145. }
    146. }
    147. }
    148. }
    149. @Override // wird ausgefürt wenn Activity im Hindergound, Verbindung Beenden
    150. public void onPause() {
    151. super.onPause();
    152. if (mmSocket.isConnected()){
    153. mmSocket.close();
    154. }
    155. }
    156. }
    Alles anzeigen
    Ein Feedback auf Tipps ist auch schön. :P

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von jogimuc ()

  • jogimuc schrieb:

    Du kannst nicht auf dein Socket zugreifen. Da du es lokal in der Klasse Thread erstellt hast.
    ….
    Benutze dafür eine globale Variable so wie dein BluetoothDevice in Zeile 3.
    Erledigt.

    Ich werde mich ausschlieslich nurnoch um den 2.ten Code kümmern da ich hier schritt für schritt verstehen möchte was geschieht.

    Die Verbindung wird getrennt sobald ich erneut auf den Connect Button klicke, ansich nicht falsch allerdings weis ich nicht woher dies geschieht. Die cancel Methode wird nie aufgerufen.

    ich habe folgende Methode in meinen onClickListener eingefügt um zu überprüfen ob verbunden ist (dann soll die Verbindung getrennt werden) oder ob getrennt ist (dann soll die Verbindung aufgebaut werden)

    Hier erstmal mein OnClickListener:

    Quellcode

    1. btn_connect.setOnClickListener(new View.OnClickListener() {
    2. @Override
    3. public void onClick(View v)
    4. {
    5. if(mBluetoothAdapter.isEnabled())
    6. {
    7. for (BluetoothDevice device : pairedDevices)
    8. {
    9. if (device.getName().equals("PiBluetooth"))
    10. {
    11. Log.e("Aquarium", device.getName());
    12. mmDevice = device;
    13. break;
    14. }
    15. }
    16. enableDisableconnection();
    17. }
    18. else
    19. {
    20. Toast.makeText(RCCar.this, "Bluetooth ist Deaktiviert", Toast.LENGTH_SHORT).show();
    21. }
    22. }
    23. });
    Alles anzeigen

    Und hier die Methode enableDisableconnection():

    Java-Quellcode

    1. public void enableDisableconnection(){
    2. try {
    3. mmSocket = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
    4. ConnectThread ConnectThread = new ConnectThread(mmDevice);
    5. if (!mmSocket.isConnected()) {
    6. Log.d(TAG, "enableDisableconnection: Connecting.");
    7. ConnectThread.run();
    8. }
    9. else //(mmSocket.isConnected())
    10. {
    11. Log.d(TAG, "enableDisableconnection: Disconnect.");
    12. ConnectThread.cancel();
    13. }
    14. }
    15. catch(IOException e)
    16. {
    17. Log.e(TAG, "Fehler", e);
    18. }
    19. }
    Alles anzeigen

    Hier habe ich mich nach den Log Meldungen orientiert.

    Beim ersten "klicken" wird die Log Meldung "Connecting" angezeigt.
    Beim zweiten "klicken" wird wieder die Log Meldung "Connecting" angezeigt allerdings wird die Verbindung dadurch unterbrochen. Das Versteh ich nicht eigentlich sollte er ConnectThread.cancel() starten und "Disconnect" in die Log schreiben.


    jogimuc schrieb:

    Ich wollte wissen ob der Thread den du mit einem Tasten Klick startest auch beendet wird.
    Soweit ich das richtig gelesen habe wird nach durchlauf der run() der Thread beendet solange es keine Endlosschleife beinhaltet. Somit muss ich den Thread nicht explizit beenden oder? Korrigier mich bitte wenn ich falsch liege.
  • Soweit ich das richtig gelesen habe wird nach durchlauf der run() der Thread beendet solange es keine Endlosschleife beinhaltet. Somit muss ich den Thread nicht explizit beenden oder? Korrigier mich bitte wenn ich falsch liege.

    Dies bezog sich auf dein ersten Code. Habe ja auch dann geschrieben zu deinem neuen Code.

    sollte eigentlich klar gewesen sein wie das gemeint war.

    Und In deinem alten erste Code hattest du eine Endlosschleife ob du es glaubst oder nicht. Da du dies nochmal aufgreifst, zeigt mir das du deinen ersten Cod nicht verstanden hast.

    Und ja wenn keine schleife vorhanden brauchst du ihn nicht extra beenden.
    Deshalb ist das auch mit der cancel() Methode etwas sinnlos. Bim neuen Code.



    So nun zu deinem aktuellen Problem:



    Erstmal hoffe ich das du in deiner ThreadKlasse nicht noch diese Zeile drin hast .
    private final BluetoothSocket mmSocket; wenn ja hast du zwei Variablen eine Lokale und eine Globale mit gleichen Namen.
    Auch solltest du im Kostruktor nicht wieder ein Socket erstellen.


    Zu deiner enableDisableconnection Methode:


    Es ist nicht verwunderlich das der else zweig nie durchlaufen wird.

    Mit jedem Tastenklick und somit Aufruf der Methode host du dir ein neues Socket.
    Danach erstellst du eine neue Instanz deiner Klasse und rufst somit den Kostruktor auf.

    Jetzst prüfst du ob das neue Socket verbunden ist. Ist es logischerweise nicht du hast es ja gerade eben erst erstellt.
    Was passiert? Dein if verzweigt in den true Block und connect wird ausgeführt. Dabei wird wohl die alte Verbindung beendet.
    So wie du das machst wirst du nie in den else Zweig kommen.
    Dein If ist immer True.



    Auch wird das beenden in dem Else Block so nicht gehen. Denn die Instanz vom vorhergehenden Thread ist beim zweiten Tasten klick nicht mehr gültig.

    Du brauchst eigentlich die cancel Methode in der Thread Klasse nicht. da dies sowie so im Main- Ui-Thread ausgeführt wird, kannst das auch gleich hier in der Methode machen. „mmSocket.close();“

    Eigentlich verstehe ich nicht den aufwand mit einer extra Klasse du willst doch nur das dein „connect in einem eigenen Thread gemacht wird . benutze doch dafür ein Runnable.

    Hier eine Variante one diese Klasse hat die gleiche Funktion und ist extrem Übersichtlicher.

    Quellcode

    1. public class RCCar extends AppCompatActivity {
    2. BluetoothDevice mmDevice = null;
    3. BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    4. Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    5. BluetoothSocket mmSocket=null;
    6. UUID MY_UUID;
    7. private Button btn_connect;
    8. @Override
    9. protected void onCreate(Bundle savedInstanceState) {
    10. super.onCreate(savedInstanceState);
    11. setContentView(R.layout.activity_main);
    12. MY_UUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee");
    13. btn_connect = (Button) findViewById(R.id.connect);
    14. btn_connect.setOnClickListener(new View.OnClickListener() {
    15. @Override
    16. public void onClick(View v) {
    17. if (mBluetoothAdapter.isEnabled()) {
    18. for (BluetoothDevice device : pairedDevices) {
    19. if (device.getName().equals("PiBluetooth")) {
    20. Log.e("Aquarium", device.getName());
    21. mmDevice = device;
    22. break;
    23. }
    24. }
    25. enableDisableconnection();
    26. } else {
    27. Toast.makeText(RCCar.this, "Bluetooth ist Deaktiviert", Toast.LENGTH_SHORT).show();
    28. }
    29. }
    30. });
    31. }
    32. public void enableDisableconnection() {
    33. try {
    34. if (mmSocket == null) {
    35. mmSocket = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
    36. Toast.makeText(getApplicationContext(), " Socket wurde erstellt",Toast.LENGTH_SHORT).show();
    37. }
    38. } catch (IOException e) {
    39. e.printStackTrace();
    40. Toast.makeText(getApplicationContext(), " Fehler Socket wurde nicht erstellt",Toast.LENGTH_SHORT).show();
    41. }
    42. if (!mmSocket.isConnected()) {
    43. Log.d(TAG, "enableDisableconnection: Connecting.");
    44. Thread thread = new Thread(new Runnable() {
    45. public void run() {
    46. try {
    47. mmSocket.connect();
    48. Toast.makeText(getApplicationContext(), "Erfolgreich Verbunden", Toast.LENGTH_SHORT).show();
    49. } catch (IOException e) {
    50. e.printStackTrace();
    51. Toast.makeText(getApplicationContext(), " Fehler Verbindung ist fehlgeschlagen", Toast.LENGTH_SHORT).show();
    52. }
    53. }
    54. });
    55. thread.start();
    56. }
    57. else //(mmSocket.isConnected())
    58. {
    59. Log.d(TAG, "enableDisableconnection: Disconnect.");
    60. try {
    61. mmSocket.close();
    62. Toast.makeText(getApplicationContext(), "Verbindung wurde beendet", Toast.LENGTH_SHORT).show();
    63. } catch (IOException e) {
    64. e.printStackTrace();
    65. Toast.makeText(getApplicationContext(), " Fehler Verbindung konte nicht beendet werden", Toast.LENGTH_SHORT).show();
    66. }
    67. }
    68. }
    69. }
    70. }
    Alles anzeigen
    Ein Feedback auf Tipps ist auch schön. :P

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von jogimuc ()

  • C++ allerdings auch erst seit September.

    Danke für deine Code. Dieser Funktioniert aber auch nicht. OnClick = Verbunden. OnClick = Getrennt, OnClick = Log sagt "Connect" er verbindet aber nichtmehr.

    Wie gesagt bin Anfänger darum auch im Thread "Anfängerfragen". Ich hoffe es gibt keine "zu dummen Fragen". Bis hierhin hast du mir ja schon sehr viel geholfen dafür bin ich dir dankbar.
  • Sorry
    Die App stürzt ab weil es nicht so einfach geht aus dem Thread auf die UI zuzugreifen und einen Toast zu senden.
    Habe es eben bei mir selber getestet vorher nicht . Hatte den Code nur in einem Editor geschrieben ohne Test.
    Bei mir läuft er. Musst natürlich auch wieder die UUID und den Geräte Namen ändern.

    wenn die Verbindung beendet ist brauchst du ein neues Socket.
    Deshald setze ich mmSocket wieder auf null.



    Quellcode

    1. public class MainActivity extends AppCompatActivity {
    2. BluetoothDevice mmDevice = null;
    3. BluetoothAdapter mBluetoothAdapter ;
    4. Set<BluetoothDevice> pairedDevices ;
    5. BluetoothSocket mmSocket=null;
    6. UUID MY_UUID;
    7. private Button btn_connect;
    8. @Override
    9. protected void onCreate(Bundle savedInstanceState) {
    10. super.onCreate(savedInstanceState);
    11. setContentView(R.layout.activity_main);
    12. // MY_UUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee");
    13. MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    14. mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    15. pairedDevices = mBluetoothAdapter.getBondedDevices();
    16. btn_connect = (Button) findViewById(R.id.button);
    17. btn_connect.setOnClickListener(new View.OnClickListener() {
    18. @Override
    19. public void onClick(View v) {
    20. if (mBluetoothAdapter.isEnabled()) {
    21. for (BluetoothDevice device : pairedDevices) {
    22. if (device.getName().equals("K01H")) {
    23. mmDevice = device;
    24. break;
    25. }
    26. }
    27. enableDisableconnection();
    28. } else {
    29. Toast.makeText(getApplicationContext(), "Bluetooth ist Deaktiviert", Toast.LENGTH_SHORT).show();
    30. }
    31. }
    32. });
    33. }
    34. public void enableDisableconnection() {
    35. try {
    36. if (mmSocket == null) {
    37. mmSocket = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
    38. }
    39. } catch (IOException e) {
    40. e.printStackTrace();
    41. }
    42. if (!mmSocket.isConnected()) {
    43. Thread thread = new Thread(new Runnable() {
    44. public void run() {
    45. try {
    46. mmSocket.connect();
    47. runOnUiThread(new Runnable(){ public void run(){
    48. Toast.makeText(MainActivity.this, "Erfolgreich Verbunden", Toast.LENGTH_SHORT).show();
    49. }});
    50. } catch (IOException e) {
    51. e.printStackTrace();
    52. runOnUiThread(new Runnable(){ public void run(){
    53. Toast.makeText(MainActivity.this, "Fehler Verbindung ist fehlgeschlagen", Toast.LENGTH_SHORT).show();
    54. }});
    55. }
    56. }
    57. });
    58. thread.start();
    59. }
    60. else //(mmSocket.isConnected())
    61. {
    62. try {
    63. mmSocket.close();
    64. mmSocket=null;
    65. Toast.makeText(getApplicationContext(), "Verbindung wurde beendet", Toast.LENGTH_SHORT).show();
    66. } catch (IOException e) {
    67. e.printStackTrace();
    68. Toast.makeText(getApplicationContext(), " Fehler Verbindung konte nicht beendet werden", Toast.LENGTH_SHORT).show();
    69. }
    70. }
    71. }
    72. }
    Alles anzeigen
    Ein Feedback auf Tipps ist auch schön. :P

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von jogimuc ()

  • Vielen Dank. Funktioniert einwandfrei.

    Deutlich übersichtlicher. Auf anhieb den Code verstanden :D

    als nächstes würde ich Input und Output stream includieren.

    Vermute mal das es sich hierbei um senden und empfangen der daten handelt. Prinzipiell brauch ich nur einen outputstream da ich ja nur daten an den pi sende aber keine empfange. Ist das Richtig?

    Kann ich dies dann auch über eine andere Datei bzw. andere activity machen? Mein Connect button ist in meiner MainActivity.java. Die Steuerung erfolgt über eine andere activity.
    Oder wäre es vorerst einfacher beides in einer activity zu behalten?

    Gruß
  • Also vorerst würde ich sagen das alles in einer Activity zu machen.

    Schaue dir mal an was eine Activity eigentlich ist und was passiert, wenn du die Activity verlässt also eine neue Startest. Du kannst somit nicht mehr auf Daten (Socket) deiner ersten zugreifen, weil sie beendet wird und der GC bereinigt den Speicher.


    Wenn dann würde ich sagen du erstellst dir eine BT Klasse in der du alles macht Verbindung aufbauen, Daten senden …
    Am besten als Singleton Class dann kannst du dir in jeder Activity die gleiche Instanz der Klasse holen.


    Richtig ein Output stream ist zum Senden auf ein Gerät gedacht. Das gibt es in C++ auch.
    In Java benutzt man Streams zum schreiben von Daten auf Geräte oder Dateien. Die Nativen Methoden werden eher selten Benutz.

    Wie etwas sendest hast du in deinem ersten code schon drin oder in meiner korrigierten Version schau da mal nach.

    Wenn du das mit verschieden Activitys Bildschirm Seiten aufbauen willst würde ich aber auf der ersten Conectseite auch Prüfen ob BT eingeschaltet ist.
    Wenn nicht dem User die Möglichkeit geben es zu Avivieren. Und wenn noch nicht gepaart, auch das anbieten.
    Vielleicht auszuwählen welches gepaarte Gerät verwendet werden soll. (ListView der Gepaarten Geräte)

    So wie es jetzt ist wird wohl die App abstürzen, wenn BT ausgeschaltet ist.
    Das wäre nicht gerade User freundlich.
    Ein Feedback auf Tipps ist auch schön. :P