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