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