diff options
| author | Keith Packard <keithp@keithp.com> | 2015-03-07 10:18:57 -0800 |
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2015-03-07 10:18:57 -0800 |
| commit | cdd7ad469728fde178c69b9c99d70d6e0ab3f12d (patch) | |
| tree | 71b2ddf53b89ae50c156c2414570f5a2ef17be64 /altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | |
| parent | d446c90dab0aca7e501a0228f24c210758d84a1d (diff) | |
altosdroid: Deal with bluetooth connection failures better
Remember when we've closed the bluetooth connection so that we stop
operations, including reporting connection status messages or even
starting a connection attempt.
Pass the AltosBluetooth object back in connection status messages so
that TelemetryService can tell when messages from closed objects get
delivered. There's a queue between the two, so the above fix catches
most of these instances, but not all of them.
Stick a delay during reconnect -- if the TeleBT device is getting
power-cycled, it will need a few seconds to reconfigure the device at
startup, if AltosDroid manages to connect during that time, the
configuration commands will be ignored.
Unlock the AltosBluetooth device while we connect so that cancel
calls will actually work.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java')
| -rw-r--r-- | altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java | 187 |
1 files changed, 102 insertions, 85 deletions
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 973250a5..da75ffdd 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -45,24 +45,36 @@ public class AltosBluetooth extends AltosLink { private Handler handler; private BluetoothAdapter adapter; - private BluetoothDevice device; private BluetoothSocket socket; private InputStream input; private OutputStream output; // Constructor - public AltosBluetooth(BluetoothDevice in_device, Handler in_handler) { + public AltosBluetooth(BluetoothDevice device, Handler handler) { // set_debug(D); adapter = BluetoothAdapter.getDefaultAdapter(); - device = in_device; - handler = in_handler; + this.handler = handler; - connect_thread = new ConnectThread(device); + create_socket(device); + connect_thread = new ConnectThread(); connect_thread.start(); + } + + private Object closed_lock = new Object(); + private boolean closed = false; + private boolean closed() { + synchronized(closed_lock) { + return closed; + } } private void connected() { + if (closed()) { + if (D) Log.d(TAG, "connected after closed"); + return; + } + try { synchronized(this) { if (socket != null) { @@ -79,7 +91,7 @@ public class AltosBluetooth extends AltosLink { /* Let TelemetryService know we're connected */ - handler.obtainMessage(TelemetryService.MSG_CONNECTED).sendToTarget(); + handler.obtainMessage(TelemetryService.MSG_CONNECTED, this).sendToTarget(); /* Notify other waiting threads that we're connected now */ @@ -92,97 +104,104 @@ public class AltosBluetooth extends AltosLink { } private void connect_failed() { - synchronized (this) { - if (socket != null) { - try { - socket.close(); - } catch (IOException e2) { - if (D) Log.e(TAG, "ConnectThread: Failed to close() socket after failed connection"); - } - socket = null; - } - input = null; - output = null; - handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED).sendToTarget(); - if (D) Log.e(TAG, "ConnectThread: Failed to establish connection"); + if (closed()) { + if (D) Log.d(TAG, "connect_failed after closed"); + return; } - } - private Object closing_lock = new Object(); - private boolean closing = false; + close_socket(); + input = null; + output = null; + handler.obtainMessage(TelemetryService.MSG_CONNECT_FAILED, this).sendToTarget(); + if (D) Log.e(TAG, "ConnectThread: Failed to establish connection"); + } private void disconnected() { - synchronized(closing_lock) { - if (D) Log.e(TAG, String.format("Connection lost during I/O. Closing %b", closing)); - if (!closing) { - if (D) Log.d(TAG, "Sending disconnected message"); - handler.obtainMessage(TelemetryService.MSG_DISCONNECTED).sendToTarget(); - } + if (closed()) { + if (D) Log.d(TAG, "disconnected after closed"); + return; } + + if (D) Log.d(TAG, "Sending disconnected message"); + handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget(); } - private class ConnectThread extends Thread { - private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); + private void close_socket() { + BluetoothSocket tmp_socket; - public ConnectThread(BluetoothDevice device) { - BluetoothSocket tmp_socket = null; + synchronized(this) { + tmp_socket = socket; + socket = null; + } + if (tmp_socket != null) { try { - tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID); + tmp_socket.close(); } catch (IOException e) { - e.printStackTrace(); + if (D) Log.e(TAG, "close_socket failed"); } + } + } + + private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); + + private void create_socket(BluetoothDevice device) { + + BluetoothSocket tmp_socket = null; + + try { + tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID); + } catch (IOException e) { + e.printStackTrace(); + } + if (socket != null) { + if (D) Log.d(TAG, String.format("Socket already allocated %s", socket.toString())); + close_socket(); + } + synchronized (this) { socket = tmp_socket; } + } + + private class ConnectThread extends Thread { public void run() { if (D) Log.d(TAG, "ConnectThread: BEGIN"); setName("ConnectThread"); // Always cancel discovery because it will slow down a connection - adapter.cancelDiscovery(); + try { + adapter.cancelDiscovery(); + } catch (Exception e) { + if (D) Log.d(TAG, String.format("cancelDiscovery exception %s", e.toString())); + } - BluetoothSocket local_socket; + BluetoothSocket local_socket = null; - try { - synchronized (AltosBluetooth.this) { + synchronized (AltosBluetooth.this) { + if (!closed()) local_socket = socket; - } + } - if (local_socket != null) { + if (local_socket != null) { + try { // Make a connection to the BluetoothSocket // This is a blocking call and will only return on a // successful connection or an exception local_socket.connect(); + } catch (IOException e) { + if (D) Log.d(TAG, String.format("Connect exception %s", e.toString())); + local_socket = null; } + } + if (local_socket != null) { connected(); - - } catch (IOException e) { + } else { connect_failed(); } - synchronized (AltosBluetooth.this) { - /* Reset the ConnectThread because we're done - */ - connect_thread = null; - } - if (D) Log.d(TAG, "ConnectThread: Connect completed"); - } - - public void cancel() { - try { - BluetoothSocket local_socket; - synchronized(AltosBluetooth.this) { - local_socket = socket; - socket = null; - } - if (local_socket != null) - local_socket.close(); - - } catch (IOException e) { - if (D) Log.e(TAG, "ConnectThread: close() of connect socket failed", e); - } + if (D) Log.d(TAG, "ConnectThread: completed"); } } @@ -246,6 +265,19 @@ public class AltosBluetooth extends AltosLink { private int buffer_len = 0; private int buffer_off = 0; + private byte[] debug_chars = new byte[buffer_size]; + private int debug_off; + + private void debug_input(byte b) { + if (b == '\n') { + Log.d(TAG, " " + new String(debug_chars, 0, debug_off)); + debug_off = 0; + } else { + if (debug_off < buffer_size) + debug_chars[debug_off++] = b; + } + } + public int getchar() { while (buffer_off == buffer_len) { try { @@ -262,13 +294,15 @@ public class AltosBluetooth extends AltosLink { return AltosLink.ERROR; } } + if (D) + debug_input(buffer[buffer_off]); return buffer[buffer_off++]; } public void closing() { - synchronized(closing_lock) { - if (D) Log.d(TAG, "Marked closing true"); - closing = true; + synchronized(closed_lock) { + if (D) Log.d(TAG, "Marked closed true"); + closed = true; } } @@ -278,19 +312,10 @@ public class AltosBluetooth extends AltosLink { closing(); + close_socket(); + synchronized(this) { - if (D) Log.d(TAG, "close(): synched"); - if (socket != null) { - if (D) Log.d(TAG, "close(): Closing socket"); - try { - socket.close(); - } catch (IOException e) { - if (D) Log.e(TAG, "close(): unable to close() socket"); - } - socket = null; - } - connect_thread = null; if (input_thread != null) { if (D) Log.d(TAG, "close(): stopping input_thread"); try { @@ -307,14 +332,6 @@ public class AltosBluetooth extends AltosLink { } } - - // We override this method so that we can add some debugging. Not 100% elegant, but more useful - // than debugging one char at a time above in getchar()! - public void add_reply(AltosLine line) throws InterruptedException { - if (D) Log.d(TAG, String.format("Got REPLY: %s", line.line)); - super.add_reply(line); - } - //public void flush_output() { super.flush_output(); } // Stubs of required methods when extending AltosLink |
