Remove ant build files
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / AltosDroidLink.java
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
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.os.Handler;
27
28 import org.altusmetrum.altoslib_13.*;
29
30 public abstract class AltosDroidLink extends AltosLink {
31
32         Handler         handler;
33
34         Thread          input_thread   = null;
35
36         public double frequency() {
37                 return frequency;
38         }
39
40         public int telemetry_rate() {
41                 return telemetry_rate;
42         }
43
44         public void save_frequency() {
45                 AltosPreferences.set_frequency(0, frequency);
46         }
47
48         public void save_telemetry_rate() {
49                 AltosPreferences.set_telemetry_rate(0, telemetry_rate);
50         }
51
52         Object closed_lock = new Object();
53         boolean closing = false;
54         boolean closed = false;
55
56         public boolean closed() {
57                 synchronized(closed_lock) {
58                         return closing;
59                 }
60         }
61
62         void connected() throws InterruptedException {
63                 input_thread = new Thread(this);
64                 input_thread.start();
65
66                 // Configure the newly connected device for telemetry
67                 print("~\nE 0\n");
68                 set_monitor(false);
69                 AltosDebug.debug("ConnectThread: connected");
70
71                 /* Let TelemetryService know we're connected
72                  */
73                 handler.obtainMessage(TelemetryService.MSG_CONNECTED, this).sendToTarget();
74
75                 /* Notify other waiting threads that we're connected now
76                  */
77                 notifyAll();
78         }
79
80         public void closing() {
81                 synchronized(closed_lock) {
82                         AltosDebug.debug("Marked closing true");
83                         closing = true;
84                 }
85         }
86
87         private boolean actually_closed() {
88                 synchronized(closed_lock) {
89                         return closed;
90                 }
91         }
92
93         abstract void close_device();
94
95         public void close() {
96                 AltosDebug.debug("close(): begin");
97
98                 closing();
99
100                 flush_output();
101
102                 synchronized (closed_lock) {
103                         AltosDebug.debug("Marked closed true");
104                         closed = true;
105                 }
106
107                 close_device();
108
109                 synchronized(this) {
110
111                         if (input_thread != null) {
112                                 AltosDebug.debug("close(): stopping input_thread");
113                                 try {
114                                         AltosDebug.debug("close(): input_thread.interrupt().....");
115                                         input_thread.interrupt();
116                                         AltosDebug.debug("close(): input_thread.join().....");
117                                         input_thread.join();
118                                 } catch (Exception e) {}
119                                 input_thread = null;
120                         }
121                         notifyAll();
122                 }
123         }
124
125         abstract int write(byte[] buffer, int len);
126
127         abstract int read(byte[] buffer, int len);
128
129         private static final int buffer_size = 64;
130
131         private byte[] in_buffer = new byte[buffer_size];
132         private byte[] out_buffer = new byte[buffer_size];
133         private int buffer_len = 0;
134         private int buffer_off = 0;
135         private int out_buffer_off = 0;
136
137         private byte[] debug_chars = new byte[buffer_size];
138         private int debug_off;
139
140         private void debug_input(byte b) {
141                 if (b == '\n') {
142                         AltosDebug.debug("            " + new String(debug_chars, 0, debug_off));
143                         debug_off = 0;
144                 } else {
145                         if (debug_off < buffer_size)
146                                 debug_chars[debug_off++] = b;
147                 }
148         }
149
150         private void disconnected() {
151                 if (closed()) {
152                         AltosDebug.debug("disconnected after closed");
153                         return;
154                 }
155
156                 AltosDebug.debug("Sending disconnected message");
157                 handler.obtainMessage(TelemetryService.MSG_DISCONNECTED, this).sendToTarget();
158         }
159
160         public int getchar() {
161
162                 if (actually_closed())
163                         return ERROR;
164
165                 while (buffer_off == buffer_len) {
166                         buffer_len = read(in_buffer, buffer_size);
167                         if (buffer_len < 0) {
168                                 AltosDebug.debug("ERROR returned from getchar()");
169                                 disconnected();
170                                 return ERROR;
171                         }
172                         buffer_off = 0;
173                 }
174 //              if (AltosDebug.D)
175 //                      debug_input(in_buffer[buffer_off]);
176                 return in_buffer[buffer_off++];
177         }
178
179         public void flush_output() {
180                 super.flush_output();
181
182                 if (actually_closed()) {
183                         out_buffer_off = 0;
184                         return;
185                 }
186
187                 while (out_buffer_off != 0) {
188                         int     sent = write(out_buffer, out_buffer_off);
189
190                         if (sent <= 0) {
191                                 AltosDebug.debug("flush_output() failed");
192                                 out_buffer_off = 0;
193                                 break;
194                         }
195
196                         if (sent < out_buffer_off)
197                                 System.arraycopy(out_buffer, 0, out_buffer, sent, out_buffer_off - sent);
198
199                         out_buffer_off -= sent;
200                 }
201         }
202
203         public void putchar(byte c) {
204                 out_buffer[out_buffer_off++] = c;
205                 if (out_buffer_off == buffer_size)
206                         flush_output();
207         }
208
209         public void print(String data) {
210                 byte[] bytes = data.getBytes();
211 //              AltosDebug.debug(data.replace('\n', '\\'));
212                 for (byte b : bytes)
213                         putchar(b);
214         }
215
216         public AltosDroidLink(Handler handler) {
217                 this.handler = handler;
218         }
219 }