altos/telefireone-v2.0: Remove build of ao_product.h from Makefile
[fw/altos] / altoslib / AltosLink.java
index 415c3c64c466daa80bbe5bd6f233a3aa2e821d8e..44202c0c80eb0b6ebe1a53d4d46cadd78d3b7a2d 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.AltosLib;
+package org.altusmetrum.altoslib_13;
 
-import java.lang.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import java.text.*;
 
 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 abstract int getchar() throws InterruptedException;
+       public abstract void print(String data) throws InterruptedException;
+       public abstract void putchar(byte c);
+       public abstract void close() throws InterruptedException;
 
        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 LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>();
 
-       public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+       private String match_string = null;
+
+       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);
@@ -52,9 +58,16 @@ public abstract class AltosLink implements Runnable {
 
        public void printf(String format, Object ... arguments) {
                String  line = String.format(format, arguments);
-               if (debug)
-                       pending_output.add(line);
-               print(line);
+               if (debug) {
+                       synchronized (pending_output) {
+                               pending_output.add(line);
+                       }
+               }
+               try {
+                       print(line);
+               } catch (InterruptedException ie) {
+
+               }
        }
 
        public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException {
@@ -69,17 +82,24 @@ public abstract class AltosLink implements Runnable {
                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 cancel_enable = true;
+
+       public void set_cancel_enable(boolean e) {
+               cancel_enable = e;
+       }
 
        boolean         reply_timeout_shown = false;
 
        private boolean check_reply_timeout() {
+               if (!cancel_enable)
+                       return false;
                if (!reply_timeout_shown)
                        reply_timeout_shown = show_reply_timeout();
                return reply_abort;
@@ -92,6 +112,16 @@ public abstract class AltosLink implements Runnable {
                }
        }
 
+       private int     len_read = 0;
+
+       private boolean match_bytes(byte[] bytes, int byte_count, String match) {
+               if (byte_count < match.length())
+                       return false;
+               String  line = new String(bytes, 0, byte_count, AltosLib.unicode_set);
+               if (line == null)
+                       return false;
+               return line.indexOf(match) >= 0;
+       }
 
        public void run () {
                int c;
@@ -102,13 +132,12 @@ public abstract class AltosLink implements Runnable {
                        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;
@@ -118,10 +147,10 @@ public abstract class AltosLink implements Runnable {
                                                System.out.printf("TIMEOUT\n");
                                        continue;
                                }
-                               if (c == '\r')
+                               if (c == '\r' && len_read == 0)
                                        continue;
                                synchronized(this) {
-                                       if (c == '\n') {
+                                       if (c == '\n' && len_read == 0) {
                                                if (line_count != 0) {
                                                        add_bytes(line_bytes, line_count);
                                                        line_count = 0;
@@ -136,6 +165,16 @@ public abstract class AltosLink implements Runnable {
                                                }
                                                line_bytes[line_count] = (byte) c;
                                                line_count++;
+                                               if (len_read !=0 && line_count == len_read) {
+                                                       add_binary(line_bytes, line_count);
+                                                       line_count = 0;
+                                                       len_read = 0;
+                                               }
+                                               if (match_string != null && match_bytes(line_bytes, line_count, match_string)) {
+                                                       match_string = null;
+                                                       add_bytes(line_bytes, line_count);
+                                                       line_count = 0;
+                                               }
                                        }
                                }
                        }
@@ -143,15 +182,32 @@ public abstract class AltosLink implements Runnable {
                }
        }
 
+       public void set_match(String match) {
+               match_string = match;
+       }
+
        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 (!can_cancel && remote)
+//                     System.out.printf("Uh-oh, reading remote serial device from swing thread\n");
 
-               if (remote && can_cancel)
+               if (remote && can_cancel) {
                        timeout = 500;
+                       switch (telemetry_rate) {
+                       case AltosLib.ao_telemetry_rate_38400:
+                       default:
+                               timeout = 500;
+                               break;
+                       case AltosLib.ao_telemetry_rate_9600:
+                               timeout = 2000;
+                               break;
+                       case AltosLib.ao_telemetry_rate_2400:
+                               timeout = 8000;
+                               break;
+                       }
+               }
                try {
                        ++in_reply;
 
@@ -177,6 +233,38 @@ public abstract class AltosLink implements Runnable {
                return reply;
        }
 
+       public byte[] get_binary_reply(int timeout, int len) throws InterruptedException {
+               boolean can_cancel = can_cancel_reply();
+               byte[] bytes = null;
+
+               synchronized(this) {
+                       len_read = len;
+               }
+               try {
+                       ++in_reply;
+
+                       flush_output();
+
+                       reply_abort = false;
+                       reply_timeout_shown = false;
+                       for (;;) {
+                               bytes = binary_queue.poll(timeout, TimeUnit.MILLISECONDS);
+                               if (bytes != null) {
+                                       cleanup_reply_timeout();
+                                       break;
+                               }
+                               if (!remote || !can_cancel || check_reply_timeout()) {
+                                       bytes = null;
+                                       break;
+                               }
+                       }
+
+               } finally {
+                       --in_reply;
+               }
+               return bytes;
+       }
+
        public void add_telem(AltosLine line) throws InterruptedException {
                for (int e = 0; e < monitors.size(); e++) {
                        LinkedBlockingQueue<AltosLine> q = monitors.get(e);
@@ -192,7 +280,7 @@ public abstract class AltosLink implements Runnable {
                try {
                        add_telem (new AltosLine());
                        add_reply (new AltosLine());
-               } catch (InterruptedException e) {
+               } catch (InterruptedException ie) {
                }
        }
 
@@ -206,22 +294,36 @@ public abstract class AltosLink implements Runnable {
 
        public void add_bytes(byte[] bytes, int len) throws InterruptedException {
                String  line;
-               try {
-                       line = new String(bytes, 0, len, "UTF-8");
-               } catch (UnsupportedEncodingException ue) {
-                       line = "";
-                       for (int i = 0; i < len; i++)
-                               line = line + bytes[i];
-               }
+               line = new String(bytes, 0, len, AltosLib.unicode_set);
                if (debug)
                        System.out.printf("\t\t\t\t\t%s\n", line);
                add_string(line);
        }
 
-       public void flush_output() {
-               for (String s : pending_output)
-                       System.out.print(s);
-               pending_output.clear();
+       public void add_binary(byte[] bytes, int len) throws InterruptedException {
+               byte[] dup = new byte[len];
+
+               if (debug)
+                       System.out.printf ("\t\t\t\t\t%d:", len);
+               for(int i = 0; i < len; i++) {
+                       dup[i] = bytes[i];
+                       if (debug)
+                               System.out.printf(" %02x", dup[i]);
+               }
+               if (debug)
+                       System.out.printf("\n");
+
+               binary_queue.put(dup);
+       }
+
+       public synchronized void flush_output() {
+               if (pending_output == null)
+                       return;
+               synchronized (pending_output) {
+                       for (String s : pending_output)
+                               System.out.print(s);
+                       pending_output.clear();
+               }
        }
 
        public void flush_input(int timeout) throws InterruptedException {
@@ -237,9 +339,22 @@ public abstract class AltosLink implements Runnable {
 
 
        public void flush_input() throws InterruptedException {
-               if (remote)
-                       flush_input(500);
-               else
+               if (remote) {
+                       int timeout = 500;
+                       switch (telemetry_rate) {
+                       case AltosLib.ao_telemetry_rate_38400:
+                       default:
+                               timeout = 500;
+                               break;
+                       case AltosLib.ao_telemetry_rate_9600:
+                               timeout = 1000;
+                               break;
+                       case AltosLib.ao_telemetry_rate_2400:
+                               timeout = 2000;
+                               break;
+                       }
+                       flush_input(timeout);
+               } else
                        flush_input(100);
        }
 
@@ -250,8 +365,13 @@ public abstract class AltosLink implements Runnable {
         */
        public boolean monitor_mode = false;
        public int telemetry = AltosLib.ao_telemetry_standard;
+       public int telemetry_rate = -1;
        public double frequency;
-       AltosConfigData config_data;
+       public String callsign;
+       private AltosConfigData config_data_local;
+       private AltosConfigData config_data_remote;
+
+       private Object config_data_lock = new Object();
 
        private int telemetry_len() {
                return AltosLib.telemetry_len(telemetry);
@@ -275,7 +395,7 @@ public abstract class AltosLink implements Runnable {
                if (frequency == 0)
                        return;
                if (has_frequency)
-                       set_radio_freq((int) Math.floor (frequency * 1000));
+                       set_radio_freq((int) Math.floor (frequency * 1000 + 0.5));
                else if (has_setting)
                        set_radio_setting(AltosConvert.radio_frequency_to_setting(frequency, cal));
                else
@@ -284,10 +404,10 @@ public abstract class AltosLink implements Runnable {
 
        public void set_radio_frequency(double in_frequency) throws InterruptedException, TimeoutException {
                frequency = in_frequency;
-               config_data();
+               AltosConfigData config_data = 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);
        }
 
@@ -298,7 +418,16 @@ public abstract class AltosLink implements Runnable {
                flush_output();
        }
 
-       public void set_monitor(boolean monitor) {
+       public void set_telemetry_rate(int in_telemetry_rate) {
+               telemetry_rate = in_telemetry_rate;
+               if (monitor_mode)
+                       printf("m 0\nc T %d\nm %x\n", telemetry_rate, telemetry_len());
+               else
+                       printf("c T %d\n", telemetry_rate);
+               flush_output();
+       }
+
+       public synchronized void set_monitor(boolean monitor) {
                monitor_mode = monitor;
                if (monitor)
                        printf("m %x\n", telemetry_len());
@@ -307,6 +436,10 @@ public abstract class AltosLink implements Runnable {
                flush_output();
        }
 
+       public synchronized boolean get_monitor() {
+               return monitor_mode;
+       }
+
        private void set_channel(int channel) {
                if (monitor_mode)
                        printf("m 0\nc r %d\nm %x\n",
@@ -325,15 +458,60 @@ public abstract class AltosLink implements Runnable {
                flush_output();
        }
 
-       public AltosConfigData config_data() throws InterruptedException, TimeoutException {
-               if (config_data == null)
-                       config_data = new AltosConfigData(this);
-               return config_data;
+       public AltosConfigData config_data() throws InterruptedException, TimeoutException {
+               synchronized(config_data_lock) {
+                       AltosConfigData config_data;
+
+                       if (remote) {
+                               if (config_data_remote == null) {
+                                       printf("m 0\n");
+                                       config_data_remote = new AltosConfigData(this);
+                                       if (monitor_mode)
+                                               set_monitor(true);
+                               }
+                               config_data = config_data_remote;
+                       } else {
+                               if (config_data_local == null) {
+                                       printf("m 0\n");
+                                       config_data_local = new AltosConfigData(this);
+                                       if (monitor_mode)
+                                               set_monitor(true);
+                               }
+                               config_data = config_data_local;
+                       }
+                       return config_data;
+               }
        }
 
        public void set_callsign(String callsign) {
-               printf ("c c %s\n", callsign);
+               this.callsign = callsign;
+               if (callsign != null) {
+                       printf ("c c %s\n", callsign);
+                       flush_output();
+               }
+       }
+
+       public boolean is_loader() throws InterruptedException {
+               boolean ret = false;
+               printf("v\n");
+               for (;;) {
+                       String line = get_reply();
+
+                       if (line == null)
+                               return false;
+                       if (line.startsWith("software-version"))
+                               break;
+                       if (line.startsWith("altos-loader"))
+                               ret = true;
+               }
+               return ret;
+       }
+
+       public void to_loader() throws InterruptedException {
+               printf("X\n");
                flush_output();
+               close();
+               Thread.sleep(1000);
        }
 
        public boolean remote;
@@ -341,12 +519,17 @@ public abstract class AltosLink implements Runnable {
        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());
+               if (telemetry_rate < 0)
+                       telemetry_rate = AltosPreferences.telemetry_rate(serial);
+               set_telemetry_rate(telemetry_rate);
+               if (callsign == null || callsign.equals(""))
+                       callsign = AltosPreferences.callsign();
+               set_callsign(callsign);
                printf("p\nE 0\n");
                flush_input();
                remote = true;
@@ -364,6 +547,79 @@ public abstract class AltosLink implements Runnable {
                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() {
+               try {
+                       return config_data().has_monitor_battery();
+               } catch (InterruptedException ie) {
+                       return false;
+               } catch (TimeoutException te) {
+                       return false;
+               }
+       }
+
+       public double monitor_battery() throws InterruptedException {
+               double  volts = AltosLib.MISSING;
+
+               try {
+                       AltosConfigData config_data = config_data();
+                       int monitor_batt = AltosLib.MISSING;
+
+                       if (config_data.has_monitor_battery()) {
+                               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++;
+                               }
+                       }
+                       if (monitor_batt != AltosLib.MISSING) {
+                               if (config_data.product.startsWith("TeleBT-v3") || config_data.product.startsWith("TeleBT-v4")) {
+                                       volts = AltosConvert.tele_bt_3_battery(monitor_batt);
+                               } else {
+                                       volts = AltosConvert.cc_battery_to_voltage(monitor_batt);
+                               }
+                       }
+
+               } catch (TimeoutException te) {
+               }
+               return volts;
+       }
+
        public AltosLink() {
+               callsign = "";
+               has_error = false;
        }
 }