altoslib: Lock access to AltosLink config_data
[fw/altos] / altoslib / AltosLink.java
index a39204ac3ba26e8892f6c79658625ca7f036067a..4823a986011c1ec80f443bfc16c6cc0e24458ce3 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.AltosLib;
+package org.altusmetrum.altoslib_2;
 
-import java.lang.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import java.text.*;
 
-public abstract class AltosLink {
+public abstract class AltosLink implements Runnable {
+
+       public final static int ERROR = -1;
+       public final static int TIMEOUT = -2;
+
+       public abstract int getchar();
        public abstract void print(String data);
        public abstract void close();
 
        public static boolean debug = false;
        public static void set_debug(boolean in_debug) { debug = in_debug; }
+
+       public boolean has_error;
+
        LinkedList<String> pending_output = new LinkedList<String>();
 
        public LinkedList<LinkedBlockingQueue<AltosLine>> monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();;
        public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();
 
-       public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+       public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {
                set_monitor(true);
                monitors.add(q);
        }
 
-       public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
+       public synchronized void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
                monitors.remove(q);
                if (monitors.isEmpty())
                        set_monitor(false);
@@ -60,16 +66,117 @@ public abstract class AltosLink {
                return null;
        }
 
-       public String get_reply(int timeout) throws InterruptedException {
+       public String get_reply() throws InterruptedException {
+               return get_reply(5000);
+       }
+
+               
+       public abstract boolean can_cancel_reply();
+       public abstract boolean show_reply_timeout();
+       public abstract void hide_reply_timeout();
+
+       public boolean  reply_abort;
+       public int      in_reply;
+
+       boolean         reply_timeout_shown = false;
+
+       private boolean check_reply_timeout() {
+               if (!reply_timeout_shown)
+                       reply_timeout_shown = show_reply_timeout();
+               return reply_abort;
+       }
+
+       private void cleanup_reply_timeout() {
+               if (reply_timeout_shown) {
+                       reply_timeout_shown = false;
+                       hide_reply_timeout();
+               }
+       }
+
+
+       public void run () {
+               int c;
+               byte[] line_bytes = null;
+               int line_count = 0;
+
                try {
-                       return get_reply_no_dialog(timeout);
-               } catch (TimeoutException te) {
-                       return null;
+                       for (;;) {
+                               c = getchar();
+                               if (Thread.interrupted()) {
+                                       if (debug)
+                                               System.out.printf("INTERRUPTED\n");
+                                       break;
+                               }
+                               if (c == ERROR) {
+                                       if (debug)
+                                               System.out.printf("ERROR\n");
+                                       has_error = true;
+                                       add_telem (new AltosLine());
+                                       add_reply (new AltosLine());
+                                       break;
+                               }
+                               if (c == TIMEOUT) {
+                                       if (debug)
+                                               System.out.printf("TIMEOUT\n");
+                                       continue;
+                               }
+                               if (c == '\r')
+                                       continue;
+                               synchronized(this) {
+                                       if (c == '\n') {
+                                               if (line_count != 0) {
+                                                       add_bytes(line_bytes, line_count);
+                                                       line_count = 0;
+                                               }
+                                       } else {
+                                               if (line_bytes == null) {
+                                                       line_bytes = new byte[256];
+                                               } else if (line_count == line_bytes.length) {
+                                                       byte[] new_line_bytes = new byte[line_count * 2];
+                                                       System.arraycopy(line_bytes, 0, new_line_bytes, 0, line_count);
+                                                       line_bytes = new_line_bytes;
+                                               }
+                                               line_bytes[line_count] = (byte) c;
+                                               line_count++;
+                                       }
+                               }
+                       }
+               } catch (InterruptedException e) {
                }
        }
 
-       public String get_reply() throws InterruptedException {
-               return get_reply(5000);
+       public String get_reply(int timeout) throws InterruptedException {
+               boolean can_cancel = can_cancel_reply();
+               String  reply = null;
+
+               if (!can_cancel && remote)
+                       System.out.printf("Uh-oh, reading remote serial device from swing thread\n");
+
+               if (remote && can_cancel)
+                       timeout = 500;
+               try {
+                       ++in_reply;
+
+                       flush_output();
+
+                       reply_abort = false;
+                       reply_timeout_shown = false;
+                       for (;;) {
+                               AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS);
+                               if (line != null) {
+                                       cleanup_reply_timeout();
+                                       reply = line.line;
+                                       break;
+                               }
+                               if (!remote || !can_cancel || check_reply_timeout()) {
+                                       reply = null;
+                                       break;
+                               }
+                       }
+               } finally {
+                       --in_reply;
+               }
+               return reply;
        }
 
        public void add_telem(AltosLine line) throws InterruptedException {
@@ -83,6 +190,14 @@ public abstract class AltosLink {
                reply_queue.put (line);
        }
 
+       public void abort_reply() {
+               try {
+                       add_telem (new AltosLine());
+                       add_reply (new AltosLine());
+               } catch (InterruptedException e) {
+               }
+       }
+
        public void add_string(String line) throws InterruptedException {
                if (line.startsWith("TELEM") || line.startsWith("VERSION") || line.startsWith("CRC")) {
                        add_telem(new AltosLine(line));
@@ -124,7 +239,10 @@ public abstract class AltosLink {
 
 
        public void flush_input() throws InterruptedException {
-               flush_input(100);
+               if (remote)
+                       flush_input(500);
+               else
+                       flush_input(100);
        }
 
 
@@ -135,8 +253,11 @@ public abstract class AltosLink {
        public boolean monitor_mode = false;
        public int telemetry = AltosLib.ao_telemetry_standard;
        public double frequency;
+       public String callsign;
        AltosConfigData config_data;
 
+       private Object config_data_lock = new Object();
+
        private int telemetry_len() {
                return AltosLib.telemetry_len(telemetry);
        }
@@ -170,8 +291,8 @@ public abstract class AltosLink {
                frequency = in_frequency;
                config_data();
                set_radio_frequency(frequency,
-                                   config_data.radio_frequency != 0,
-                                   config_data.radio_setting != 0,
+                                   config_data.radio_frequency > 0,
+                                   config_data.radio_setting > 0,
                                    config_data.radio_calibration);
        }
 
@@ -210,12 +331,15 @@ public abstract class AltosLink {
        }
 
        public AltosConfigData config_data() throws InterruptedException, TimeoutException {
-               if (config_data == null)
-                       config_data = new AltosConfigData(this);
-               return config_data;
+               synchronized(config_data_lock) {
+                       if (config_data == null)
+                               config_data = new AltosConfigData(this);
+                       return config_data;
+               }
        }
 
        public void set_callsign(String callsign) {
+               this.callsign = callsign;
                printf ("c c %s\n", callsign);
                flush_output();
        }
@@ -225,10 +349,10 @@ public abstract class AltosLink {
        public String name;
 
        public void start_remote() throws TimeoutException, InterruptedException {
-               if (debug)
-                       System.out.printf("start remote %7.3f\n", frequency);
                if (frequency == 0.0)
                        frequency = AltosPreferences.frequency(serial);
+               if (debug)
+                       System.out.printf("start remote %7.3f\n", frequency);
                set_radio_frequency(frequency);
                set_callsign(AltosPreferences.callsign());
                printf("p\nE 0\n");
@@ -248,6 +372,65 @@ public abstract class AltosLink {
                remote = false;
        }
 
+       public int rssi() throws TimeoutException, InterruptedException {
+               if (remote)
+                       return 0;
+               printf("s\n");
+               String line = get_reply_no_dialog(5000);
+               if (line == null)
+                       throw new TimeoutException();
+               String[] items = line.split("\\s+");
+               if (items.length < 2)
+                       return 0;
+               if (!items[0].equals("RSSI:"))
+                       return 0;
+               int rssi = Integer.parseInt(items[1]);
+               return rssi;
+       }
+
+       public String[] adc() throws TimeoutException, InterruptedException {
+               printf("a\n");
+               for (;;) {
+                       String line = get_reply_no_dialog(5000);
+                       if (line == null) {
+                               throw new TimeoutException();
+                       }
+                       if (!line.startsWith("tick:"))
+                               continue;
+                       String[] items = line.split("\\s+");
+                       return items;
+               }
+       }
+
+       public boolean has_monitor_battery() {
+               return config_data.has_monitor_battery();
+       }
+
+       public double monitor_battery() {
+               int monitor_batt = AltosLib.MISSING;
+
+               if (config_data.has_monitor_battery()) {
+                       try {
+                       String[] items = adc();
+                       for (int i = 0; i < items.length;) {
+                               if (items[i].equals("batt")) {
+                                       monitor_batt = Integer.parseInt(items[i+1]);
+                                       i += 2;
+                                       continue;
+                               }
+                               i++;
+                       }
+                       } catch (InterruptedException ie) {
+                       } catch (TimeoutException te) {
+                       }
+               }
+               if (monitor_batt == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               return AltosConvert.cc_battery_to_voltage(monitor_batt);
+       }
+
        public AltosLink() {
+               callsign = "";
+               has_error = false;
        }
 }