0eba55fd36f7078d763ef7e7ae9ada1c96686a94
[fw/altos] / altosuilib / 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 org.altusmetrum.altosuilib_3;
23
24 import java.io.*;
25 import java.util.*;
26 import java.awt.*;
27 import javax.swing.*;
28 import org.altusmetrum.altoslib_5.*;
29 import libaltosJNI.*;
30
31 /*
32  * This class reads from the serial port and places each received
33  * line in a queue. Dealing with that queue is left up to other
34  * threads.
35  */
36
37 public class AltosSerial extends AltosLink  {
38
39         static java.util.List<String> devices_opened = Collections.synchronizedList(new LinkedList<String>());
40
41         public AltosDevice device;
42         SWIGTYPE_p_altos_file altos;
43         Thread input_thread;
44         String line;
45         byte[] line_bytes;
46         int line_count;
47         Frame frame;
48
49         public int getchar() {
50                 if (altos == null)
51                         return ERROR;
52                 return libaltos.altos_getchar(altos, 0);
53         }
54
55         public void flush_output() {
56                 super.flush_output();
57                 if (altos != null) {
58                         if (libaltos.altos_flush(altos) != 0)
59                                 close_serial();
60                 }
61         }
62
63         JDialog         timeout_dialog;
64
65         private void start_timeout_dialog_internal() {
66
67                 Object[] options = { "Cancel" };
68
69                 JOptionPane     pane = new JOptionPane();
70                 pane.setMessage(String.format("Connecting to %s, %7.3f MHz as %s", device.toShortString(), frequency, callsign));
71                 pane.setOptions(options);
72                 pane.setInitialValue(null);
73
74                 timeout_dialog = pane.createDialog(frame, "Connecting...");
75
76                 timeout_dialog.setVisible(true);
77
78                 Object o = pane.getValue();
79                 if (o == null)
80                         return;
81                 if (options[0].equals(o))
82                         reply_abort = true;
83                 timeout_dialog.dispose();
84                 timeout_dialog = null;
85         }
86
87         /*
88          * These are required by the AltosLink implementation
89          */
90
91         public boolean can_cancel_reply() {
92                 /*
93                  * Can cancel any replies not called from the dispatch thread
94                  */
95                 return !SwingUtilities.isEventDispatchThread();
96         }
97
98         public boolean show_reply_timeout() {
99                 if (!SwingUtilities.isEventDispatchThread() && frame != null) {
100                         Runnable r = new Runnable() {
101                                         public void run() {
102                                                 start_timeout_dialog_internal();
103                                         }
104                                 };
105                         SwingUtilities.invokeLater(r);
106                         return true;
107                 }
108                 return false;
109         }
110
111         public void hide_reply_timeout() {
112                 Runnable r = new Runnable() {
113                                 public void run() {
114                                         timeout_dialog.setVisible(false);
115                                 }
116                         };
117                 SwingUtilities.invokeLater(r);
118         }
119
120         private synchronized void close_serial() {
121                 synchronized (devices_opened) {
122                         devices_opened.remove(device.getPath());
123                 }
124                 if (altos != null) {
125                         libaltos.altos_free(altos);
126                         altos = null;
127                 }
128                 abort_reply();
129         }
130
131         public void close() {
132                 if (remote) {
133                         try {
134                                 stop_remote();
135                         } catch (InterruptedException ie) {
136                         }
137                 }
138                 if (in_reply != 0)
139                         System.out.printf("Uh-oh. Closing active serial device\n");
140
141                 close_serial();
142
143                 if (input_thread != null) {
144                         try {
145                                 input_thread.interrupt();
146                                 input_thread.join();
147                         } catch (InterruptedException ie) {
148                         }
149                         input_thread = null;
150                 }
151                 if (debug)
152                         System.out.printf("Closing %s\n", device.getPath());
153         }
154
155         private void putc(char c) {
156                 if (altos != null)
157                         if (libaltos.altos_putchar(altos, c) != 0)
158                                 close_serial();
159         }
160
161         public void putchar(byte c) {
162                 if (altos != null) {
163                         if (debug)
164                                 System.out.printf(" %02x", (int) c & 0xff);
165                         if (libaltos.altos_putchar(altos, (char) c) != 0)
166                                 close_serial();
167                 }
168         }
169
170         public void print(String data) {
171                 for (int i = 0; i < data.length(); i++)
172                         putc(data.charAt(i));
173         }
174
175         private void open() throws FileNotFoundException, AltosSerialInUseException {
176                 synchronized (devices_opened) {
177                         if (devices_opened.contains(device.getPath()))
178                                 throw new AltosSerialInUseException(device);
179                         devices_opened.add(device.getPath());
180                 }
181                 altos = device.open();
182                 if (altos == null) {
183                         final String    message = device.getErrorString();
184                         close();
185                         throw new FileNotFoundException(String.format("%s (%s)",
186                                                                       device.toShortString(), message));
187                 }
188                 if (debug)
189                         System.out.printf("Open %s\n", device.getPath());
190                 input_thread = new Thread(this);
191                 input_thread.start();
192                 print("~\nE 0\n");
193                 set_monitor(false);
194                 flush_output();
195         }
196
197         public void set_frame(Frame in_frame) {
198                 frame = in_frame;
199         }
200
201         public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
202                 device = in_device;
203                 frame = null;
204                 serial = device.getSerial();
205                 name = device.toShortString();
206                 open();
207         }
208 }