Merge branch 'master' of git://git.gag.com/fw/altos
[fw/altos] / ao-tools / altosui / AltosSerial.java
1 /*
2  * Copyright © 2010 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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 /*
19  * Deal with TeleDongle on a serial port
20  */
21
22 package altosui;
23
24 import java.lang.*;
25 import java.io.*;
26 import java.util.concurrent.LinkedBlockingQueue;
27 import java.util.LinkedList;
28 import java.util.Iterator;
29 import altosui.AltosSerialMonitor;
30 import altosui.AltosLine;
31 import libaltosJNI.libaltos;
32 import libaltosJNI.altos_device;
33 import libaltosJNI.SWIGTYPE_p_altos_file;
34 import libaltosJNI.SWIGTYPE_p_altos_list;
35 import libaltosJNI.libaltosConstants;
36
37 /*
38  * This class reads from the serial port and places each received
39  * line in a queue. Dealing with that queue is left up to other
40  * threads.
41  */
42
43 public class AltosSerial implements Runnable {
44
45         SWIGTYPE_p_altos_file altos;
46         LinkedList<LinkedBlockingQueue<AltosLine>> monitors;
47         LinkedBlockingQueue<AltosLine> reply_queue;
48         Thread input_thread;
49         String line;
50         byte[] line_bytes;
51         int line_count;
52         boolean monitor_mode;
53
54         public void run () {
55                 int c;
56
57                 try {
58                         for (;;) {
59                                 c = libaltos.altos_getchar(altos, 0);
60                                 if (Thread.interrupted())
61                                         break;
62                                 if (c == libaltosConstants.LIBALTOS_ERROR) {
63                                         for (int e = 0; e < monitors.size(); e++) {
64                                                 LinkedBlockingQueue<AltosLine> q = monitors.get(e);
65                                                 q.put(new AltosLine());
66                                         }
67                                         reply_queue.put (new AltosLine());
68                                         break;
69                                 }
70                                 if (c == libaltosConstants.LIBALTOS_TIMEOUT)
71                                         continue;
72                                 if (c == '\r')
73                                         continue;
74                                 synchronized(this) {
75                                         if (c == '\n') {
76                                                 if (line_count != 0) {
77                                                         try {
78                                                                 line = new String(line_bytes, 0, line_count, "UTF-8");
79                                                         } catch (UnsupportedEncodingException ue) {
80                                                                 line = "";
81                                                                 for (int i = 0; i < line_count; i++)
82                                                                         line = line + line_bytes[i];
83                                                         }
84                                                         if (line.startsWith("VERSION") || line.startsWith("CRC")) {
85                                                                 for (int e = 0; e < monitors.size(); e++) {
86                                                                         LinkedBlockingQueue<AltosLine> q = monitors.get(e);
87                                                                         q.put(new AltosLine (line));
88                                                                 }
89                                                         } else {
90 //                                                              System.out.printf("GOT: %s\n", line);
91                                                                 reply_queue.put(new AltosLine (line));
92                                                         }
93                                                         line_count = 0;
94                                                         line = "";
95                                                 }
96                                         } else {
97                                                 if (line_bytes == null) {
98                                                         line_bytes = new byte[256];
99                                                 } else if (line_count == line_bytes.length) {
100                                                         byte[] new_line_bytes = new byte[line_count * 2];
101                                                         System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count);
102                                                         line_bytes = new_line_bytes;
103                                                 }
104                                                 line_bytes[line_count] = (byte) c;
105                                                 line_count++;
106                                         }
107                                 }
108                         }
109                 } catch (InterruptedException e) {
110                 }
111         }
112
113         public void flush_output() {
114                 if (altos != null)
115                         libaltos.altos_flush(altos);
116         }
117
118         public void flush_input() {
119                 flush_output();
120                 try {
121                         Thread.sleep(200);
122                 } catch (InterruptedException ie) {
123                 }
124                 synchronized(this) {
125                         if (!"VERSION".startsWith(line) &&
126                             !line.startsWith("VERSION"))
127                                 line = "";
128                         reply_queue.clear();
129                 }
130         }
131
132         public String get_reply() throws InterruptedException {
133                 flush_output();
134                 AltosLine line = reply_queue.take();
135                 return line.line;
136         }
137
138         public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
139                 set_monitor(true);
140                 monitors.add(q);
141         }
142
143         public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
144                 monitors.remove(q);
145                 if (monitors.isEmpty())
146                         set_monitor(false);
147         }
148
149         public boolean opened() {
150                 return altos != null;
151         }
152
153         public void close() {
154                 if (altos != null) {
155                         libaltos.altos_close(altos);
156                 }
157                 if (input_thread != null) {
158                         try {
159                                 input_thread.interrupt();
160                                 input_thread.join();
161                         } catch (InterruptedException e) {
162                         }
163                         input_thread = null;
164                 }
165                 if (altos != null) {
166                         libaltos.altos_free(altos);
167                         altos = null;
168                 }
169         }
170
171         public void putc(char c) {
172                 if (altos != null)
173                         libaltos.altos_putchar(altos, c);
174         }
175
176         public void print(String data) {
177 //              System.out.printf("\"%s\" ", data);
178                 for (int i = 0; i < data.length(); i++)
179                         putc(data.charAt(i));
180         }
181
182         public void printf(String format, Object ... arguments) {
183                 print(String.format(format, arguments));
184         }
185
186         public void open(altos_device device) throws FileNotFoundException {
187                 close();
188                 altos = libaltos.altos_open(device);
189                 if (altos == null)
190                         throw new FileNotFoundException(device.getPath());
191                 input_thread = new Thread(this);
192                 input_thread.start();
193                 print("~\nE 0\n");
194                 flush_output();
195                 set_monitor(monitor_mode);
196         }
197
198         public void set_channel(int channel) {
199                 if (altos != null) {
200                         if (monitor_mode)
201                                 printf("m 0\nc r %d\nm 1\n", channel);
202                         else
203                                 printf("c r %d\n", channel);
204                         flush_output();
205                 }
206         }
207
208         void set_monitor(boolean monitor) {
209                 monitor_mode = monitor;
210                 if (altos != null) {
211                         if (monitor)
212                                 printf("m 1\n");
213                         else
214                                 printf("m 0\n");
215                         flush_output();
216                 }
217         }
218
219         public void set_callsign(String callsign) {
220                 if (altos != null) {
221                         printf ("c c %s\n", callsign);
222                         flush_output();
223                 }
224         }
225
226         public AltosSerial() {
227                 altos = null;
228                 input_thread = null;
229                 line = "";
230                 monitor_mode = false;
231                 monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();
232                 reply_queue = new LinkedBlockingQueue<AltosLine> ();
233         }
234 }