1f0946799d71549c35e19ffb2a78b24752d385a6
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / AltosBluetooth.java
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  * Copyright © 2012 Mike Beattie <mike@ethernal.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package org.altusmetrum.AltosDroid;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.util.UUID;
25
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothDevice;
28 import android.bluetooth.BluetoothSocket;
29 import android.util.Log;
30
31 import org.altusmetrum.AltosLib.*;
32
33 public class AltosBluetooth extends AltosLink {
34
35         // Debugging
36         private static final String TAG = "AltosBluetooth";
37         private static final boolean D = true;
38
39         /**
40          * This thread runs while attempting to make an outgoing connection
41          * with a device. It runs straight through; the connection either
42          * succeeds or fails.
43          */
44
45         private BluetoothAdapter        adapter;
46         private ConnectThread           connect_thread;
47         private BluetoothSocket         socket;
48         private InputStream             input;
49         private OutputStream            output;
50
51         private class ConnectThread extends Thread {
52                 private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
53
54                 public ConnectThread(BluetoothDevice device) {
55                         BluetoothSocket tmp_socket = null;
56
57                         try {
58                                 tmp_socket = device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
59                         } catch (IOException e) {
60                                 e.printStackTrace();
61                         }
62                         socket = tmp_socket;
63                 }
64
65                 public void run() {
66                         if (D) Log.i(TAG, "BEGIN ConnectThread");
67                         setName("ConnectThread");
68
69                         // Always cancel discovery because it will slow down a connection
70                         adapter.cancelDiscovery();
71
72                         // Make a connection to the BluetoothSocket
73                         try {
74                                 // This is a blocking call and will only return on a
75                                 // successful connection or an exception
76                                 socket.connect();
77                         } catch (IOException e) {
78                                 // Close the socket
79                                 try {
80                                         socket.close();
81                                 } catch (IOException e2) {
82                                         if (D) Log.e(TAG, "unable to close() socket during connection failure", e2);
83                                 }
84                                 connection_failed();
85                                 return;
86                         }
87
88                         try {
89                                 synchronized (AltosBluetooth.this) {
90                                         input = socket.getInputStream();
91                                         output = socket.getOutputStream();
92
93                                         // Reset the ConnectThread because we're done
94                                         AltosBluetooth.this.notify();
95                                         connect_thread = null;
96                                         if (D) Log.i(TAG, "Completed connect");
97                                 }
98                         } catch (Exception e) {
99                                 if (D) Log.e(TAG, "Failed to finish connection", e);
100                                 e.printStackTrace();
101                         }
102                 }
103
104                 public void cancel() {
105                         try {
106                                 if (socket != null)
107                                         socket.close();
108                         } catch (IOException e) {
109                                 if (D) Log.e(TAG, "close() of connect socket failed", e);
110                         }
111                 }
112         }
113
114         private synchronized void wait_connected() throws InterruptedException {
115                 if (input == null) {
116                         wait();
117                 }
118         }
119
120         private void connection_failed() {
121         }
122         
123         public void print(String data) {
124                 byte[] bytes = data.getBytes();
125                 try {
126                         wait_connected();
127                         output.write(bytes);
128                 } catch (IOException e) {
129                         connection_failed();
130                 } catch (InterruptedException e) {
131                         connection_failed();
132                 }
133         }
134
135         public int getchar() {
136                 try {
137                         wait_connected();
138                         return input.read();
139                 } catch (IOException e) {
140                         connection_failed();
141                 } catch (java.lang.InterruptedException e) {
142                         connection_failed();
143                 }
144                 return AltosLink.ERROR;
145         }
146                         
147         public void close() {
148                 synchronized(this) {
149                         if (connect_thread != null) {
150                                 connect_thread.cancel();
151                                 connect_thread = null;
152                         }
153                 }
154         }
155
156         public void flush_output() {
157                 super.flush_output();
158                 /* any local work needed to flush bluetooth? */
159         }
160
161         public boolean can_cancel_reply() {
162                 return false;
163         }
164         public boolean show_reply_timeout() {
165                 return true;
166         }
167                 
168         public void hide_reply_timeout() {
169         }
170
171         public AltosBluetooth(BluetoothDevice device) {
172                 adapter = BluetoothAdapter.getDefaultAdapter();
173                 connect_thread = new ConnectThread(device, true);
174                 connect_thread.start();
175         }
176 }