Merge branch 'macos'
authorKeith Packard <keithp@keithp.com>
Wed, 28 Jul 2010 18:20:22 +0000 (11:20 -0700)
committerKeith Packard <keithp@keithp.com>
Wed, 28 Jul 2010 18:20:22 +0000 (11:20 -0700)
20 files changed:
ao-tools/Makefile.am
ao-tools/altosui/AltosDevice.java
ao-tools/altosui/AltosDeviceDialog.java
ao-tools/altosui/AltosDeviceLinux.java [deleted file]
ao-tools/altosui/AltosGPS.java
ao-tools/altosui/AltosSerial.java
ao-tools/altosui/AltosUI.java
ao-tools/altosui/AltosUIIcon.icns [new file with mode: 0644]
ao-tools/altosui/AltosVoice.java
ao-tools/altosui/Makefile
ao-tools/altosui/Manifest.txt
ao-tools/altosui/voices.txt [deleted file]
ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml [new file with mode: 0644]
ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml [new file with mode: 0644]
ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml [new file with mode: 0644]
ao-tools/libaltos/Makefile [new file with mode: 0644]
ao-tools/libaltos/cjnitest.c [new file with mode: 0644]
ao-tools/libaltos/libaltos.c [new file with mode: 0644]
ao-tools/libaltos/libaltos.h [new file with mode: 0644]
ao-tools/libaltos/libaltos.i0 [new file with mode: 0644]

index 2850e909003cbe82e1171c8ff7be8f797a185306..54dc777af134dd8e80c4a3fbf1b5e04c6fe3779a 100644 (file)
@@ -1 +1 @@
-SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view
+SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view libaltos altosui
index 66800c5c66da39e45964f1593ee06a99614ee943..0e7d01da757cf1f7e2729c6a4be038c2133fb873 100644 (file)
 package altosui;
 import java.lang.*;
 import java.util.*;
+import libaltosJNI.*;
 
-public class AltosDevice {
-       String  tty;    /* suitable to be passed to AltosSerial.connect */
-       String  manufacturer;
-       String  product;
-       int     serial;
-       int     idProduct;
-       int     idVendor;
+public class AltosDevice extends altos_device {
 
+       public String toString() {
+               return String.format("%-20.20s %4d %s",
+                                    getProduct(), getSerial(), getPath());
+       }
+
+       static {
+               System.loadLibrary("altos");
+               libaltos.altos_init();
+       }
+       static AltosDevice[] list(String product) {
+               SWIGTYPE_p_altos_list list = libaltos.altos_list_start();
+
+               ArrayList<AltosDevice> device_list = new ArrayList<AltosDevice>();
+               if (list != null) {
+                       SWIGTYPE_p_altos_file file;
+
+                       for (;;) {
+                               AltosDevice device = new AltosDevice();
+                               if (libaltos.altos_list_next(list, device) == 0)
+                                       break;
+                               device_list.add(device);
+                       }
+                       libaltos.altos_list_finish(list);
+               }
+
+               AltosDevice[] devices = new AltosDevice[device_list.size()];
+               for (int i = 0; i < device_list.size(); i++)
+                       devices[i] = device_list.get(i);
+               return devices;
+       }
 }
\ No newline at end of file
index cb1eef8bc8f8204db8ab414a5dbd7563be1ddb80..eb70877c9b99f18559a83e81989e126623251d75 100644 (file)
@@ -20,15 +20,17 @@ package altosui;
 import java.lang.*;
 import java.util.*;
 import javax.swing.*;
+import libaltosJNI.libaltos;
+import libaltosJNI.altos_device;
+import libaltosJNI.SWIGTYPE_p_altos_file;
+import libaltosJNI.SWIGTYPE_p_altos_list;
 import altosui.AltosDevice;
-import altosui.AltosDeviceLinux;
 
 public class AltosDeviceDialog {
 
-       static AltosDevice show (JFrame frame, String product) {
-               AltosDevice[]   devices = null;
-               if (System.getProperty("os.name").startsWith("Linux"))
-                       devices = AltosDeviceLinux.list(product);
+       static altos_device show (JFrame frame, String product) {
+               AltosDevice[]   devices;
+               devices = AltosDevice.list(product);
                if (devices != null & devices.length > 0) {
                        Object o = JOptionPane.showInputDialog(frame,
                                                               "Select a device",
@@ -37,7 +39,7 @@ public class AltosDeviceDialog {
                                                               null,
                                                               devices,
                                                               devices[0]);
-                       return (AltosDevice) o;
+                       return (altos_device) o;
                } else {
                        return null;
                }
diff --git a/ao-tools/altosui/AltosDeviceLinux.java b/ao-tools/altosui/AltosDeviceLinux.java
deleted file mode 100644 (file)
index ffc70af..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-package altosui;
-import java.lang.*;
-import java.io.*;
-import java.util.*;
-import altosui.AltosDevice;
-
-public class AltosDeviceLinux extends AltosDevice {
-
-       String load_string(File file) {
-               try {
-                       FileInputStream in = new FileInputStream(file);
-                       String result = "";
-                       int c;
-                       try {
-                               while ((c = in.read()) != -1) {
-                                       if (c == '\n')
-                                               break;
-                                       result = result + (char) c;
-                               }
-                               return result;
-                       } catch (IOException ee) {
-                               return "";
-                       }
-               } catch (FileNotFoundException ee) {
-                       return "";
-               }
-       }
-       String load_string(File dir, String name) {
-               return load_string(new File(dir, name));
-       }
-
-       int load_hex(File file) {
-               try {
-                       return Integer.parseInt(load_string(file).trim(), 16);
-               } catch (NumberFormatException ee) {
-                       return -1;
-               }
-       }
-
-       int load_hex(File dir, String name) {
-               return load_hex(new File(dir, name));
-       }
-
-       int load_dec(File file) {
-               try {
-                       return Integer.parseInt(load_string(file).trim());
-               } catch (NumberFormatException ee) {
-                       return -1;
-               }
-       }
-
-       int load_dec(File dir, String name) {
-               return load_dec(new File(dir, name));
-       }
-
-       String usb_tty(File sys_dir) {
-               String base = sys_dir.getName();
-               int num_configs = load_hex(sys_dir, "bNumConfigurations");
-               int num_inters = load_hex(sys_dir, "bNumInterfaces");
-               for (int config = 1; config <= num_configs; config++) {
-                       for (int inter = 0; inter < num_inters; inter++) {
-                               String endpoint_base = String.format("%s:%d.%d",
-                                                                    base, config, inter);
-                               File endpoint_full = new File(sys_dir, endpoint_base);
-
-                               File[] namelist;
-
-                               /* Check for tty:ttyACMx style names */
-                               class tty_colon_filter implements FilenameFilter {
-                                       public boolean accept(File dir, String name) {
-                                               return name.startsWith("tty:");
-                                       }
-                               }
-                               namelist = endpoint_full.listFiles(new tty_colon_filter());
-                               if (namelist != null && namelist.length > 0)
-                                       return new File ("/dev", namelist[0].getName().substring(4)).getPath();
-
-                               /* Check for tty/ttyACMx style names */
-                               class tty_filter implements FilenameFilter {
-                                       public boolean accept(File dir, String name) {
-                                               return name.startsWith("tty");
-                                       }
-                               }
-                               File tty_dir = new File(endpoint_full, "tty");
-                               namelist = tty_dir.listFiles(new tty_filter());
-                               if (namelist != null && namelist.length > 0)
-                                       return new File ("/dev", namelist[0].getName()).getPath();
-                       }
-               }
-               return null;
-       }
-
-       public AltosDeviceLinux (File sys) {
-               sys = sys;
-               manufacturer = load_string(sys, "manufacturer");
-               product = load_string(sys, "product");
-               serial = load_dec(sys, "serial");
-               idProduct = load_hex(sys, "idProduct");
-               idVendor = load_hex(sys, "idVendor");
-               tty = usb_tty(sys);
-       }
-
-       public String toString() {
-               return String.format("%-20s %6d %-15s", product, serial, tty == null ? "" : tty);
-       }
-       static public AltosDeviceLinux[] list() {
-               LinkedList<AltosDeviceLinux> devices = new LinkedList<AltosDeviceLinux>();
-
-               class dev_filter implements FilenameFilter{
-                       public boolean accept(File dir, String name) {
-                               for (int i = 0; i < name.length(); i++) {
-                                       char c = name.charAt(i);
-                                       if (Character.isDigit(c))
-                                               continue;
-                                       if (c == '-')
-                                               continue;
-                                       if (c == '.' && i != 1)
-                                               continue;
-                                       return false;
-                               }
-                               return true;
-                       }
-               }
-
-               File usb_devices = new File("/sys/bus/usb/devices");
-               File[] devs = usb_devices.listFiles(new dev_filter());
-               if (devs != null) {
-                       for (int e = 0; e < devs.length; e++) {
-                               AltosDeviceLinux        dev = new AltosDeviceLinux(devs[e]);
-                               if (dev.idVendor == 0xfffe && dev.tty != null) {
-                                       devices.add(dev);
-                               }
-                       }
-               }
-               AltosDeviceLinux[] foo = new AltosDeviceLinux[devices.size()];
-               for (int e = 0; e < devices.size(); e++)
-                       foo[e] = devices.get(e);
-               return foo;
-       }
-
-       static public AltosDeviceLinux[] list(String model) {
-               AltosDeviceLinux[] devices = list();
-               if (model != null) {
-                       LinkedList<AltosDeviceLinux> subset = new LinkedList<AltosDeviceLinux>();
-                       for (int i = 0; i < devices.length; i++) {
-                               if (devices[i].product.startsWith(model))
-                                       subset.add(devices[i]);
-                       }
-                       devices = new AltosDeviceLinux[subset.size()];
-                       for (int e = 0; e < subset.size(); e++)
-                               devices[e] = subset.get(e);
-               }
-               return devices;
-       }
-}
index c3b368e26b47ce022f5e34068bf227e49d3bb7e1..f8eb5f4844150024244f3ef08211db8f75c62d9d 100644 (file)
@@ -90,6 +90,9 @@ public class AltosGPS {
                        gps_connected = true;
                        gps_time = new AltosGPSTime();
                        i++;
+               } else if ((words[i]).equals("not-connected")) {
+                       gps_time = new AltosGPSTime();
+                       i++;
                } else if (words.length >= 40) {
                        gps_locked = true;
                        gps_connected = true;
@@ -106,6 +109,7 @@ public class AltosGPS {
                        v_error = AltosParse.parse_int(AltosParse.strip_suffix(words[i++], "(verr)"));
                } else {
                        gps_time = new AltosGPSTime();
+                       i++;
                }
                AltosParse.word(words[i++], "SAT");
                int tracking_channels = 0;
index 03ab28c55376ff635c4c7b964304f0ab7cd1b269..e84f5b63e4e21c7ca5cdd0cbb0cb90c863383ced 100644 (file)
@@ -26,16 +26,21 @@ import java.io.*;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.LinkedList;
 import java.util.Iterator;
-import gnu.io.*;
 import altosui.AltosSerialMonitor;
+import libaltosJNI.libaltos;
+import libaltosJNI.altos_device;
+import libaltosJNI.SWIGTYPE_p_altos_file;
+import libaltosJNI.SWIGTYPE_p_altos_list;
 
 /*
  * This class reads from the serial port and places each received
  * line in a queue. Dealing with that queue is left up to other
  * threads.
  */
-class AltosSerialReader implements Runnable {
-       InputStream     serial_in;
+
+public class AltosSerial implements Runnable {
+
+       SWIGTYPE_p_altos_file altos;
        LinkedList<LinkedBlockingQueue<String>> monitors;
        LinkedBlockingQueue<String> reply_queue;
        Thread input_thread;
@@ -46,7 +51,7 @@ class AltosSerialReader implements Runnable {
 
                try {
                        for (;;) {
-                               c = serial_in.read();
+                               c = libaltos.altos_getchar(altos, 0);
                                if (Thread.interrupted())
                                        break;
                                if (c == -1)
@@ -70,7 +75,6 @@ class AltosSerialReader implements Runnable {
                                        }
                                }
                        }
-               } catch (IOException e) {
                } catch (InterruptedException e) {
                }
        }
@@ -96,16 +100,13 @@ class AltosSerialReader implements Runnable {
        }
 
        public boolean opened() {
-               return serial_in != null;
+               return altos != null;
        }
 
        public void close() {
-               if (serial_in != null) {
-                       try {
-                               serial_in.close();
-                       } catch (IOException e) {
-                       }
-                       serial_in = null;
+               if (altos != null) {
+                       libaltos.altos_close(altos);
+                       altos = null;
                }
                if (input_thread != null) {
                        try {
@@ -117,87 +118,31 @@ class AltosSerialReader implements Runnable {
                }
        }
 
-       public void open(File name) throws FileNotFoundException {
-               close();
-               serial_in = new FileInputStream(name);
-               input_thread = new Thread(this);
-               input_thread.start();
-       }
-       public void open(CommPort c) throws IOException {
-               close();
-               try {
-               c.enableReceiveTimeout(1000);   /* icky. the read method cannot be interrupted */
-               } catch (UnsupportedCommOperationException ee) {
-               }
-               serial_in = c.getInputStream();
-               input_thread = new Thread(this);
-               input_thread.start();
-       }
-       public AltosSerialReader () {
-               serial_in = null;
-               input_thread = null;
-               line = "";
-               monitors = new LinkedList<LinkedBlockingQueue<String>> ();
-               reply_queue = new LinkedBlockingQueue<String> ();
+       public void putc(char c) {
+               libaltos.altos_putchar(altos, c);
        }
 
-}
-
-public class AltosSerial {
-       OutputStream serial_out = null;
-       AltosSerialReader reader = null;
-
-       CommPort comm_port = null;
-
-       public void close() {
-               try {
-                       serial_out.close();
-               } catch (IOException ee) {
-               }
-               reader.close();
-               if (comm_port != null) {
-                       comm_port.close();
-               }
-       }
-
-       public void open(File serial_name) throws FileNotFoundException {
-               reader.open(serial_name);
-               serial_out = new FileOutputStream(serial_name);
-       }
-
-       public void open(CommPort c) throws IOException {
-               reader.open(c);
-               serial_out = c.getOutputStream();
+       public void print(String data) {
+               for (int i = 0; i < data.length(); i++)
+                       putc(data.charAt(i));
        }
 
-       public void connect(String port_name) throws IOException, NoSuchPortException, PortInUseException {
-               comm_port = new RXTXPort(port_name);
-               open(comm_port);
+       public void printf(String format, Object ... arguments) {
+               print(String.format(format, arguments));
        }
 
-       void init() {
-               reader = new AltosSerialReader();
-       }
-
-       public void add_monitor(LinkedBlockingQueue<String> q) {
-               reader.add_monitor(q);
-       }
-
-       public void remove_monitor(LinkedBlockingQueue<String> q) {
-               reader.remove_monitor(q);
+       public void open(altos_device device) throws FileNotFoundException {
+               close();
+               altos = libaltos.altos_open(device);
+               input_thread = new Thread(this);
+               input_thread.start();
        }
 
        public AltosSerial() {
-               init();
-       }
-
-       public AltosSerial(File serial_name) throws FileNotFoundException {
-               init();
-               open(serial_name);
-       }
-
-       public AltosSerial(CommPort comm_port) throws IOException {
-               init();
-               open(comm_port);
+               altos = null;
+               input_thread = null;
+               line = "";
+               monitors = new LinkedList<LinkedBlockingQueue<String>> ();
+               reply_queue = new LinkedBlockingQueue<String> ();
        }
 }
index 43c40799f193552ba66d2dbbd74b1b52c9d140ad..3dfc89527601d52d6bf685b2174b66ca9e75e883 100644 (file)
@@ -27,7 +27,6 @@ import java.util.*;
 import java.text.*;
 import java.util.prefs.*;
 import java.util.concurrent.LinkedBlockingQueue;
-import gnu.io.*;
 
 import altosui.AltosSerial;
 import altosui.AltosSerialMonitor;
@@ -38,6 +37,8 @@ import altosui.AltosPreferences;
 import altosui.AltosLog;
 import altosui.AltosVoice;
 
+import libaltosJNI.*;
+
 class AltosFlightStatusTableModel extends AbstractTableModel {
        private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
        private Object[] data = { 0, "idle", 0, 0 };
@@ -220,16 +221,8 @@ public class AltosUI extends JFrame {
                flightInfoModel[col].addRow(name, value);
        }
 
-       public void info_add_row(int col, String name, String format, Object value) {
-               flightInfoModel[col].addRow(name, String.format(format, value));
-       }
-
-       public void info_add_row(int col, String name, String format, Object v1, Object v2) {
-               flightInfoModel[col].addRow(name, String.format(format, v1, v2));
-       }
-
-       public void info_add_row(int col, String name, String format, Object v1, Object v2, Object v3) {
-               flightInfoModel[col].addRow(name, String.format(format, v1, v2, v3));
+       public void info_add_row(int col, String name, String format, Object... parameters) {
+               flightInfoModel[col].addRow(name, String.format(format, parameters));
        }
 
        public void info_add_deg(int col, String name, double v, int pos, int neg) {
@@ -345,48 +338,57 @@ public class AltosUI extends JFrame {
        class IdleThread extends Thread {
 
                private AltosState state;
+               int     reported_landing;
+
+               public void report(boolean last) {
+                       if (state == null)
+                               return;
+
+                       /* reset the landing count once we hear about a new flight */
+                       if (state.state < AltosTelemetry.ao_flight_drogue)
+                               reported_landing = 0;
+
+                       /* Shut up once the rocket is on the ground */
+                       if (reported_landing > 2) {
+                               return;
+                       }
+
+                       /* If the rocket isn't on the pad, then report height */
+                       if (state.state > AltosTelemetry.ao_flight_pad) {
+                               voice.speak("%d meters", (int) (state.height + 0.5));
+                       } else {
+                               reported_landing = 0;
+                       }
+
+                       /* If the rocket is coming down, check to see if it has landed;
+                        * either we've got a landed report or we haven't heard from it in
+                        * a long time
+                        */
+                       if (!state.ascent &&
+                           (last ||
+                            System.currentTimeMillis() - state.report_time >= 15000 ||
+                            state.state == AltosTelemetry.ao_flight_landed))
+                       {
+                               if (Math.abs(state.baro_speed) < 20 && state.height < 100)
+                                       voice.speak("rocket landed safely");
+                               else
+                                       voice.speak("rocket may have crashed");
+                               if (state.gps != null)
+                                       voice.speak("bearing %d degrees, range %d meters",
+                                                   (int) (state.from_pad.bearing + 0.5),
+                                                   (int) (state.from_pad.distance + 0.5));
+                               ++reported_landing;
+                       }
+               }
 
                public void run () {
-                       int     reported_landing = 0;
 
+                       reported_landing = 0;
                        state = null;
                        try {
                                for (;;) {
                                        Thread.sleep(10000);
-                                       if (state == null)
-                                               continue;
-
-                                       /* reset the landing count once we hear about a new flight */
-                                       if (state.state < AltosTelemetry.ao_flight_drogue)
-                                               reported_landing = 0;
-
-                                       /* Shut up once the rocket is on the ground */
-                                       if (reported_landing > 2)
-                                               continue;
-
-                                       /* If the rocket isn't on the pad, then report height */
-                                       if (state.state > AltosTelemetry.ao_flight_pad) {
-                                               voice.speak(String.format("%d meters", (int) (state.height + 0.5)));
-                                       }
-
-                                       /* If the rocket is coming down, check to see if it has landed;
-                                        * either we've got a landed report or we haven't heard from it in
-                                        * a long time
-                                        */
-                                       if (!state.ascent &&
-                                           (System.currentTimeMillis() - state.report_time > 10000 ||
-                                            state.state == AltosTelemetry.ao_flight_landed))
-                                       {
-                                               if (Math.abs(state.baro_speed) < 20 && state.height < 100)
-                                                       voice.speak("rocket landed safely");
-                                               else
-                                                       voice.speak("rocket may have crashed");
-                                               if (state.gps != null)
-                                                       voice.speak(String.format("bearing %d degrees, range %d meters",
-                                                                                 (int) (state.from_pad.bearing + 0.5),
-                                                                                 (int) (state.from_pad.distance + 0.5)));
-                                               ++reported_landing;
-                                       }
+                                       report(false);
                                }
                        } catch (InterruptedException ie) {
                        }
@@ -400,21 +402,22 @@ public class AltosUI extends JFrame {
        private void tell(AltosState state, AltosState old_state) {
                if (old_state == null || old_state.state != state.state) {
                        voice.speak(state.data.state);
-                       switch (state.state) {
-                       case AltosTelemetry.ao_flight_fast:
-                               voice.speak(String.format("max speed %d meters per second",
-                                                         (int) (state.max_speed + 0.5)));
-                               break;
-                       case AltosTelemetry.ao_flight_drogue:
-                               voice.speak(String.format("max height %d meters",
-                                                         (int) (state.max_height + 0.5)));
-                               break;
+                       if ((old_state == null || old_state.state <= AltosTelemetry.ao_flight_boost) &&
+                           state.state > AltosTelemetry.ao_flight_boost) {
+                               voice.speak("max speed: %d meters per second.",
+                                           (int) (state.max_speed + 0.5));
+                       } else if ((old_state == null || old_state.state < AltosTelemetry.ao_flight_drogue) &&
+                                  state.state >= AltosTelemetry.ao_flight_drogue) {
+                               voice.speak("max height: %d meters.",
+                                           (int) (state.max_height + 0.5));
                        }
                }
                old_state = state;
        }
 
        class DisplayThread extends Thread {
+               IdleThread      idle_thread;
+
                String read() throws InterruptedException { return null; }
 
                void close() { }
@@ -425,7 +428,8 @@ public class AltosUI extends JFrame {
                        String          line;
                        AltosState      state = null;
                        AltosState      old_state = null;
-                       IdleThread      idle_thread = new IdleThread();
+
+                       idle_thread = new IdleThread();
 
                        info_reset();
                        info_finish();
@@ -451,6 +455,11 @@ public class AltosUI extends JFrame {
                                idle_thread.interrupt();
                        }
                }
+
+               public void report() {
+                       if (idle_thread != null)
+                               idle_thread.report(true);
+               }
        }
 
        class DeviceThread extends DisplayThread {
@@ -475,31 +484,21 @@ public class AltosUI extends JFrame {
        }
 
        private void ConnectToDevice() {
-               AltosDevice     device = AltosDeviceDialog.show(AltosUI.this, "TeleDongle");
+               altos_device    device = AltosDeviceDialog.show(AltosUI.this, "TeleDongle");
 
                if (device != null) {
                        try {
-                               serial_line.connect(device.tty);
+                               serial_line.open(device);
                                DeviceThread thread = new DeviceThread(serial_line);
                                run_display(thread);
                        } catch (FileNotFoundException ee) {
                                JOptionPane.showMessageDialog(AltosUI.this,
-                                                             device.tty,
+                                                             device.getPath(),
                                                              "Cannot open serial port",
                                                              JOptionPane.ERROR_MESSAGE);
-                       } catch (NoSuchPortException ee) {
-                               JOptionPane.showMessageDialog(AltosUI.this,
-                                                             device.tty,
-                                                             "No such serial port",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       } catch (PortInUseException ee) {
-                               JOptionPane.showMessageDialog(AltosUI.this,
-                                                             device.tty,
-                                                             "Port in use",
-                                                             JOptionPane.ERROR_MESSAGE);
                        } catch (IOException ee) {
                                JOptionPane.showMessageDialog(AltosUI.this,
-                                                             device.tty,
+                                                             device.getPath(),
                                                              "Unkonwn I/O error",
                                                              JOptionPane.ERROR_MESSAGE);
                        }
@@ -517,8 +516,9 @@ public class AltosUI extends JFrame {
                while ((c = s.read()) != -1) {
                        if (c == '\r')
                                continue;
-                       if (c == '\n')
+                       if (c == '\n') {
                                return line;
+                       }
                        line = line + (char) c;
                }
                return null;
@@ -554,12 +554,13 @@ public class AltosUI extends JFrame {
                                replay.close();
                        } catch (IOException ee) {
                        }
+                       report();
                }
 
                void update(AltosState state) throws InterruptedException {
                        /* Make it run in realtime after the rocket leaves the pad */
                        if (state.state > AltosTelemetry.ao_flight_pad)
-                               Thread.sleep((int) (state.time_change * 1000));
+                               Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
                }
        }
 
@@ -600,7 +601,7 @@ public class AltosUI extends JFrame {
                        } catch (FileNotFoundException ee) {
                                JOptionPane.showMessageDialog(AltosUI.this,
                                                              filename,
-                                                             "Cannot open serial port",
+                                                             "Cannot open telemetry file",
                                                              JOptionPane.ERROR_MESSAGE);
                        }
                }
diff --git a/ao-tools/altosui/AltosUIIcon.icns b/ao-tools/altosui/AltosUIIcon.icns
new file mode 100644 (file)
index 0000000..fe49f36
Binary files /dev/null and b/ao-tools/altosui/AltosUIIcon.icns differ
index e4ea99a2220d80a8abbe3a83a602486a7a45f236..c39bfb9b4694fb086df9278faad2008393663b26 100644 (file)
@@ -47,6 +47,10 @@ public class AltosVoice implements Runnable {
                }
        }
 
+       public void speak(String format, Object... parameters) {
+               speak(String.format(format, parameters));
+       }
+
        public AltosVoice () {
                voice_manager = VoiceManager.getInstance();
                voice = voice_manager.getVoice(voice_name);
index 57c889b8d37c3d1c335221791289b65178d2bdc5..cd1230238a1cd199fb3e2a5156248cf67ead5e9f 100644 (file)
@@ -1,6 +1,6 @@
 .SUFFIXES: .java .class
 
-CLASSPATH=..:/usr/share/java/*:/home/keithp/src/freetts/freetts-1.2.2
+CLASSPATH=classes:./*
 CLASSFILES=\
        AltosConvert.class \
        AltosFile.class \
@@ -15,24 +15,45 @@ CLASSFILES=\
        AltosTelemetry.class \
        AltosUI.class \
        AltosDevice.class \
-       AltosDeviceLinux.class \
        AltosDeviceDialog.class \
        AltosVoice.class
 
+FREETTSSRC=/home/keithp/src/freetts/freetts-1.2.2
+FREETTSLIB=$(FREETTSSRC)/lib
+FREETTSJAR= \
+       cmudict04.jar \
+       cmulex.jar \
+       cmu_time_awb.jar \
+       cmutimelex.jar \
+       cmu_us_kal.jar \
+       en_us.jar \
+       freetts.jar \
+       freetts-jsapi10.jar \
+       jsapi.jar
+
 JAVAFLAGS=-Xlint:unchecked
 
-all: $(CLASSFILES) altosui altosui.jar
+all: altosui.jar
+
+$(CLASSFILES):
 
 .java.class:
        javac -cp "$(CLASSPATH)" $(JAVAFLAGS) $*.java
 
-altosui: Makefile
-       (echo '#!/bin/sh'; \
-       echo exec java -cp '"$(CLASSPATH)"' altosui/AltosUI) > $@
-       chmod +x $@
+altosui.jar: classes/altosui classes/libaltosJNI $(FREETTSJAR) $(CLASSFILES) Manifest.txt
+       cd ./classes && jar cfm ../$@ altosui/Manifest.txt altosui/*.class libaltosJNI/*.class
+
+classes/altosui:
+       mkdir -p classes
+       ln -s .. classes/altosui
+
+classes/libaltosJNI:
+       mkdir -p classes
+       ln -s ../../libaltos/libaltosJNI classes/libaltosJNI
 
-altosui.jar: $(CLASSFILES) Manifest.txt
-       cd .. && jar cfm altosui/$@ altosui/Manifest.txt altosui/*.class
+$(FREETTSJAR):
+       ln -s $(FREETTSLIB)/$@ .
 
 clean:
-       rm -f *.class
+       rm -f *.class $(FREETTSJAR) altosui.jar
+       rm -rf classes
index 0305fcfbe4ed73b4c2415f25cfeb5e3e8bf833d1..251ce2a014363294990050744e2f61c607b202e8 100644 (file)
@@ -1 +1,2 @@
 Main-Class: altosui.AltosUI
+Class-Path: freetts.jar
diff --git a/ao-tools/altosui/voices.txt b/ao-tools/altosui/voices.txt
deleted file mode 100644 (file)
index e8825fc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory
diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui-contents.xml
new file mode 100644 (file)
index 0000000..e19a1e4
--- /dev/null
@@ -0,0 +1 @@
+<pkg-contents spec="1.12"><f n="AltosUI.app" o="keithp" g="keithp" p="16877" pt="/Users/keithp/AltosUI.app" m="false" t="file"><f n="Contents" o="keithp" g="keithp" p="16877"><f n="Info.plist" o="keithp" g="keithp" p="33188"/><f n="MacOS" o="keithp" g="keithp" p="16877"><f n="JavaApplicationStub" o="keithp" g="keithp" p="33133"/></f><f n="PkgInfo" o="keithp" g="keithp" p="33188"/><f n="Resources" o="keithp" g="keithp" p="16877"><f n="AltosUIIcon.icns" o="keithp" g="keithp" p="33188"/><f n="Java" o="keithp" g="keithp" p="16877"><f n="altosui.jar" o="keithp" g="keithp" p="33188"/><f n="cmu_time_awb.jar" o="keithp" g="keithp" p="33188"/><f n="cmu_us_kal.jar" o="keithp" g="keithp" p="33188"/><f n="cmudict04.jar" o="keithp" g="keithp" p="33188"/><f n="cmulex.jar" o="keithp" g="keithp" p="33188"/><f n="cmutimelex.jar" o="keithp" g="keithp" p="33188"/><f n="en_us.jar" o="keithp" g="keithp" p="33188"/><f n="freetts-jsapi10.jar" o="keithp" g="keithp" p="33188"/><f n="freetts.jar" o="keithp" g="keithp" p="33188"/><f n="libaltos.dylib" o="keithp" g="keithp" p="33188"/></f></f></f></f></pkg-contents>
\ No newline at end of file
diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/01altosui.xml
new file mode 100644 (file)
index 0000000..5d84e5f
--- /dev/null
@@ -0,0 +1 @@
+<pkgref spec="1.12" uuid="C5762664-2F26-4536-94C4-56F0FBC08D1A"><config><identifier>org.altusmetrum.altosUi.AltosUI.pkg</identifier><version>1.0</version><description></description><post-install type="none"/><installFrom>/Users/keithp/AltosUI.app</installFrom><installTo mod="true" relocatable="true">/Applications/AltosUI.app</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>installTo.path</mod><mod>parent</mod><mod>requireAuthorization</mod><mod>installTo</mod></config><contents><file-list>01altosui-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
\ No newline at end of file
diff --git a/ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml b/ao-tools/libaltos/AltOS Package Configuration.pmdoc/index.xml
new file mode 100644 (file)
index 0000000..1277db6
--- /dev/null
@@ -0,0 +1 @@
+<pkmkdoc spec="1.12"><properties><title>AltOS UI</title><build>/Users/keithp/Documents/AltosUI.pkg</build><organization>org.altusmetrum</organization><userSees ui="easy"/><min-target os="3"/><domain anywhere="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><contents><choice title="AltosUI" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="org.altusmetrum.altosUi.AltosUI.pkg"/></choice></contents><resources bg-scale="none" bg-align="topleft"><locale lang="en"/></resources><flags/><item type="file">01altosui.xml</item><mod>properties.title</mod></pkmkdoc>
\ No newline at end of file
diff --git a/ao-tools/libaltos/Makefile b/ao-tools/libaltos/Makefile
new file mode 100644 (file)
index 0000000..0bbd304
--- /dev/null
@@ -0,0 +1,80 @@
+OS:=$(shell uname)
+
+ifeq ($(OS),Linux)
+
+JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include
+
+OS_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS)
+
+LIBEXT=so
+
+endif
+
+ifeq ($(OS),Darwin)
+
+DARWIN_CFLAGS=\
+       --sysroot=/Developer/SDKs/MacOSX10.5.sdk -mmacosx-version-min=10.5 \
+       -iwithsysroot /System/Library/Frameworks/JavaVM.framework/Headers \
+       -iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \
+       -iwithsysroot /System/Library/Frameworks/CoreFoundation.framework/Headers
+DARWIN_LIBS=\
+       -framework IOKit -framework CoreFoundation
+
+OS_CFLAGS = $(DARWIN_CFLAGS) -DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64
+LIBEXT=dylib
+
+endif
+
+.SUFFIXES: .java .class
+
+CLASSPATH=".:jnitest/*:libaltosJNI:/usr/share/java/*"
+
+SWIG_DIR=swig_bindings/java
+SWIG_FILE=$(SWIG_DIR)/libaltos.swig
+SWIG_WRAP=$(SWIG_DIR)/libaltos_wrap.c
+
+JNI_DIR=libaltosJNI
+JNI_FILE=$(JNI_DIR)/libaltosJNI.java 
+JNI_SRCS=$(JNI_FILE) \
+       $(JNI_DIR)/SWIGTYPE_p_altos_file.java \
+       $(JNI_DIR)/SWIGTYPE_p_altos_list.java \
+       $(JNI_DIR)/altos_device.java \
+       $(JNI_DIR)/libaltos.java
+
+JAVAFILES=\
+       $(JNI_SRCS)
+
+CLASSFILES = $(JAVAFILES:%.java=%.class)
+
+JAVAFLAGS=-Xlint:unchecked
+
+all: libaltos.$(LIBEXT) cjnitest $(CLASSFILES)
+
+.java.class:
+       javac -cp "$(CLASSPATH)" $(JAVAFLAGS) $*.java
+
+CFLAGS=$(OS_CFLAGS) -O0 -g -I.
+
+HEADERS=libaltos.h
+SRCS = libaltos.c $(SWIG_WRAP)
+OBJS = $(SRCS:%.c=%.o)
+LIBS = $(DARWIN_LIBS)
+
+cjnitest: cjnitest.o $(OBJS)
+       cc -o $@ $(CFLAGS) cjnitest.o $(OBJS) $(LIBS)
+
+libaltos.$(LIBEXT): $(OBJS)
+       gcc -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+       rm -f $(CLASSFILES) $(OBJS) libaltos.$(LIBEXT) cjnitest cjnitest.o
+       rm -rf swig_bindings libaltosJNI
+
+$(JNI_FILE): libaltos.i0 $(HEADERS)
+       mkdir -p $(SWIG_DIR)
+       mkdir -p libaltosJNI
+       sed 's;//%;%;' libaltos.i0 $(HEADERS) > $(SWIG_FILE)
+       swig -java -package libaltosJNI $(SWIG_FILE)
+       cp swig_bindings/java/*.java libaltosJNI
+
+$(SWIG_WRAP): $(JNI_FILE)
diff --git a/ao-tools/libaltos/cjnitest.c b/ao-tools/libaltos/cjnitest.c
new file mode 100644 (file)
index 0000000..cd3898e
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include "libaltos.h"
+
+main ()
+{
+       struct altos_device     device;
+       struct altos_list       *list;
+
+       altos_init();
+       list = altos_list_start();
+       while (altos_list_next(list, &device)) {
+               struct altos_file       *file;
+               int                     c;
+
+               file = altos_open(&device);
+               altos_putchar(file, '?'); altos_putchar(file, '\n'); altos_flush(file);
+               while ((c = altos_getchar(file, 100)) >= 0) {
+                       putchar (c);
+               }
+               printf ("getchar returns %d\n", c);
+               altos_close(file);
+       }
+       altos_list_finish(list);
+       altos_fini();
+}
diff --git a/ao-tools/libaltos/libaltos.c b/ao-tools/libaltos/libaltos.c
new file mode 100644 (file)
index 0000000..df0d5b2
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "libaltos.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+match_dev(char *product, int serial, struct altos_device *device)
+{
+       struct altos_list       *list;
+       int                     i;
+
+       list = altos_list_start();
+       if (!list)
+               return 0;
+       while ((i = altos_list_next(list, device)) != 0) {
+               if (product && strncmp (product, device->product, strlen(product)) != 0)
+                       continue;
+               if (serial && serial != device->serial)
+                       continue;
+               break;
+       }
+       altos_list_finish(list);
+       return i;
+}
+
+#ifdef DARWIN
+/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
+static char *
+altos_strndup (const char *s, size_t n)
+{
+    size_t len = strlen (s);
+    char *ret;
+
+    if (len <= n)
+       return strdup (s);
+    ret = malloc(n + 1);
+    strncpy(ret, s, n);
+    ret[n] = '\0';
+    return ret;
+}
+
+#else
+#define altos_strndup strndup
+#endif
+
+int
+altos_find_by_arg(char *arg, char *default_product, struct altos_device *device)
+{
+       char    *product;
+       int     serial;
+       char    *end;
+       char    *colon;
+       int     ret;
+
+       if (arg)
+       {
+               /* check for <serial> */
+               serial = strtol(arg, &end, 0);
+               if (end != arg) {
+                       if (*end != '\0')
+                               return 0;
+                       product = NULL;
+               } else {
+                       /* check for <product>:<serial> */
+                       colon = strchr(arg, ':');
+                       if (colon) {
+                               product = altos_strndup(arg, colon - arg);
+                               serial = strtol(colon + 1, &end, 0);
+                               if (*end != '\0')
+                                       return 0;
+                       } else {
+                               product = arg;
+                               serial = 0;
+                       }
+               }
+       } else {
+               product = NULL;
+               serial = 0;
+       }
+       if (!product && default_product)
+               ret = match_dev(default_product, serial, device);
+       if (!ret)
+               ret = match_dev(product, serial, device);
+       if (product && product != arg)
+               free(product);
+       return ret;
+}
+
+#ifdef LINUX
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *
+cc_fullname (char *dir, char *file)
+{
+       char    *new;
+       int     dlen = strlen (dir);
+       int     flen = strlen (file);
+       int     slen = 0;
+
+       if (dir[dlen-1] != '/')
+               slen = 1;
+       new = malloc (dlen + slen + flen + 1);
+       if (!new)
+               return 0;
+       strcpy(new, dir);
+       if (slen)
+               strcat (new, "/");
+       strcat(new, file);
+       return new;
+}
+
+static char *
+cc_basename(char *file)
+{
+       char *b;
+
+       b = strrchr(file, '/');
+       if (!b)
+               return file;
+       return b + 1;
+}
+
+static char *
+load_string(char *dir, char *file)
+{
+       char    *full = cc_fullname(dir, file);
+       char    line[4096];
+       char    *r;
+       FILE    *f;
+       int     rlen;
+
+       f = fopen(full, "r");
+       free(full);
+       if (!f)
+               return NULL;
+       r = fgets(line, sizeof (line), f);
+       fclose(f);
+       if (!r)
+               return NULL;
+       rlen = strlen(r);
+       if (r[rlen-1] == '\n')
+               r[rlen-1] = '\0';
+       return strdup(r);
+}
+
+static int
+load_hex(char *dir, char *file)
+{
+       char    *line;
+       char    *end;
+       long    i;
+
+       line = load_string(dir, file);
+       if (!line)
+               return -1;
+       i = strtol(line, &end, 16);
+       free(line);
+       if (end == line)
+               return -1;
+       return i;
+}
+
+static int
+load_dec(char *dir, char *file)
+{
+       char    *line;
+       char    *end;
+       long    i;
+
+       line = load_string(dir, file);
+       if (!line)
+               return -1;
+       i = strtol(line, &end, 10);
+       free(line);
+       if (end == line)
+               return -1;
+       return i;
+}
+
+static int
+dir_filter_tty_colon(const struct dirent *d)
+{
+       return strncmp(d->d_name, "tty:", 4) == 0;
+}
+
+static int
+dir_filter_tty(const struct dirent *d)
+{
+       return strncmp(d->d_name, "tty", 3) == 0;
+}
+
+struct altos_usbdev {
+       char    *sys;
+       char    *tty;
+       char    *manufacturer;
+       char    *product;
+       int     serial; /* AltOS always uses simple integer serial numbers */
+       int     idProduct;
+       int     idVendor;
+};
+
+static char *
+usb_tty(char *sys)
+{
+       char *base;
+       int num_configs;
+       int config;
+       struct dirent **namelist;
+       int interface;
+       int num_interfaces;
+       char endpoint_base[20];
+       char *endpoint_full;
+       char *tty_dir;
+       int ntty;
+       char *tty;
+
+       base = cc_basename(sys);
+       num_configs = load_hex(sys, "bNumConfigurations");
+       num_interfaces = load_hex(sys, "bNumInterfaces");
+       for (config = 1; config <= num_configs; config++) {
+               for (interface = 0; interface < num_interfaces; interface++) {
+                       sprintf(endpoint_base, "%s:%d.%d",
+                               base, config, interface);
+                       endpoint_full = cc_fullname(sys, endpoint_base);
+
+                       /* Check for tty:ttyACMx style names
+                        */
+                       ntty = scandir(endpoint_full, &namelist,
+                                      dir_filter_tty_colon,
+                                      alphasort);
+                       if (ntty > 0) {
+                               free(endpoint_full);
+                               tty = cc_fullname("/dev", namelist[0]->d_name + 4);
+                               free(namelist);
+                               return tty;
+                       }
+
+                       /* Check for tty/ttyACMx style names
+                        */
+                       tty_dir = cc_fullname(endpoint_full, "tty");
+                       free(endpoint_full);
+                       ntty = scandir(tty_dir, &namelist,
+                                      dir_filter_tty,
+                                      alphasort);
+                       free (tty_dir);
+                       if (ntty > 0) {
+                               tty = cc_fullname("/dev", namelist[0]->d_name);
+                               free(namelist);
+                               return tty;
+                       }
+               }
+       }
+       return NULL;
+}
+
+static struct altos_usbdev *
+usb_scan_device(char *sys)
+{
+       struct altos_usbdev *usbdev;
+
+       usbdev = calloc(1, sizeof (struct altos_usbdev));
+       if (!usbdev)
+               return NULL;
+       usbdev->sys = strdup(sys);
+       usbdev->manufacturer = load_string(sys, "manufacturer");
+       usbdev->product = load_string(sys, "product");
+       usbdev->serial = load_dec(sys, "serial");
+       usbdev->idProduct = load_hex(sys, "idProduct");
+       usbdev->idVendor = load_hex(sys, "idVendor");
+       usbdev->tty = usb_tty(sys);
+       return usbdev;
+}
+
+static void
+usbdev_free(struct altos_usbdev *usbdev)
+{
+       free(usbdev->sys);
+       free(usbdev->manufacturer);
+       free(usbdev->product);
+       /* this can get used as a return value */
+       if (usbdev->tty)
+               free(usbdev->tty);
+       free(usbdev);
+}
+
+#define USB_DEVICES    "/sys/bus/usb/devices"
+
+static int
+dir_filter_dev(const struct dirent *d)
+{
+       const char      *n = d->d_name;
+       char    c;
+
+       while ((c = *n++)) {
+               if (isdigit(c))
+                       continue;
+               if (c == '-')
+                       continue;
+               if (c == '.' && n != d->d_name + 1)
+                       continue;
+               return 0;
+       }
+       return 1;
+}
+
+struct altos_list {
+       struct altos_usbdev     **dev;
+       int                     current;
+       int                     ndev;
+};
+
+int
+altos_init(void)
+{
+       return 1;
+}
+
+void
+altos_fini(void)
+{
+}
+
+struct altos_list *
+altos_list_start(void)
+{
+       int                     e;
+       struct dirent           **ents;
+       char                    *dir;
+       struct altos_usbdev     *dev;
+       struct altos_list       *devs;
+       int                     n;
+
+       devs = calloc(1, sizeof (struct altos_list));
+       if (!devs)
+               return NULL;
+
+       n = scandir (USB_DEVICES, &ents,
+                    dir_filter_dev,
+                    alphasort);
+       if (!n)
+               return 0;
+       for (e = 0; e < n; e++) {
+               dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
+               dev = usb_scan_device(dir);
+               free(dir);
+               if (dev->idVendor == 0xfffe && dev->tty) {
+                       if (devs->dev)
+                               devs->dev = realloc(devs->dev,
+                                                   devs->ndev + 1 * sizeof (struct usbdev *));
+                       else
+                               devs->dev = malloc (sizeof (struct usbdev *));
+                       devs->dev[devs->ndev++] = dev;
+               }
+       }
+       free(ents);
+       devs->current = 0;
+       return devs;
+}
+
+int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+       struct altos_usbdev *dev;
+       if (list->current >= list->ndev)
+               return 0;
+       dev = list->dev[list->current];
+       strcpy(device->product, dev->product);
+       strcpy(device->path, dev->tty);
+       device->serial = dev->serial;
+       list->current++;
+       return 1;
+}
+
+void
+altos_list_finish(struct altos_list *usbdevs)
+{
+       int     i;
+
+       if (!usbdevs)
+               return;
+       for (i = 0; i < usbdevs->ndev; i++)
+               usbdev_free(usbdevs->dev[i]);
+       free(usbdevs);
+}
+
+#endif
+
+#ifdef DARWIN
+
+#include <IOKitLib.h>
+#include <IOKit/usb/USBspec.h>
+#include <sys/param.h>
+#include <paths.h>
+#include <CFNumber.h>
+#include <IOBSD.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct altos_list {
+       io_iterator_t iterator;
+};
+
+static int
+get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
+{
+       CFTypeRef entry_as_string;
+       Boolean got_string;
+
+       entry_as_string = IORegistryEntrySearchCFProperty (object,
+                                                          kIOServicePlane,
+                                                          entry,
+                                                          kCFAllocatorDefault,
+                                                          kIORegistryIterateRecursively);
+       if (entry_as_string) {
+               got_string = CFStringGetCString(entry_as_string,
+                                               result, result_len,
+                                               kCFStringEncodingASCII);
+    
+               CFRelease(entry_as_string);
+               if (got_string)
+                       return 1;
+       }
+       return 0;
+}
+
+int
+altos_init(void)
+{
+       return 1;
+}
+
+void
+altos_fini(void)
+{
+}
+
+struct altos_list *
+altos_list_start(void)
+{
+       struct altos_list *list = calloc (sizeof (struct altos_list), 1);
+       CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
+       UInt32 vendor = 0xfffe, product = 0x000a;
+       CFNumberRef vendor_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor);
+       CFNumberRef product_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product);
+       io_iterator_t tdIterator;
+       io_object_t tdObject;
+  
+       CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBVendorID), vendor_ref);
+       CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBProductID), product_ref);
+
+       IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
+  
+       CFRelease(vendor_ref);
+       CFRelease(product_ref);
+       return list;
+}
+
+int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+       io_object_t object;
+       char serial_string[128];
+
+       for (;;) {
+               object = IOIteratorNext(list->iterator);
+               if (!object)
+                       return 0;
+  
+               if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
+                   get_string (object, CFSTR("USB Product Name"), device->product, sizeof (device->product)) &&
+                   get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
+                       device->serial = atoi(serial_string);
+                       return 1;
+               }
+       }
+}
+
+void
+altos_list_finish(struct altos_list *list)
+{
+       IOObjectRelease (list->iterator);
+       free(list);
+}
+
+#endif
+
+#ifdef POSIX_TTY
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+
+#define USB_BUF_SIZE   64
+
+struct altos_file {
+       int                             fd;
+       unsigned char                   out_data[USB_BUF_SIZE];
+       int                             out_used;
+       unsigned char                   in_data[USB_BUF_SIZE];
+       int                             in_used;
+       int                             in_read;
+};
+
+struct altos_file *
+altos_open(struct altos_device *device)
+{
+       struct altos_file       *file = calloc (sizeof (struct altos_file), 1);
+       int                     ret;
+       struct termios          term;
+
+       if (!file)
+               return NULL;
+
+       file->fd = open(device->path, O_RDWR | O_NOCTTY);
+       if (file->fd < 0) {
+               perror(device->path);
+               free(file);
+               return NULL;
+       }
+       ret = tcgetattr(file->fd, &term);
+       if (ret < 0) {
+               perror("tcgetattr");
+               close(file->fd);
+               free(file);
+               return NULL;
+       }
+       cfmakeraw(&term);
+       term.c_cc[VMIN] = 0;
+       term.c_cc[VTIME] = 1;
+       ret = tcsetattr(file->fd, TCSAFLUSH, &term);
+       if (ret < 0) {
+               perror("tcsetattr");
+               close(file->fd);
+               free(file);
+               return NULL;
+       }
+       return file;
+}
+
+void
+altos_close(struct altos_file *file)
+{
+       close(file->fd);
+       free(file);
+}
+
+int
+altos_putchar(struct altos_file *file, char c)
+{
+       int     ret;
+
+       if (file->out_used == USB_BUF_SIZE) {
+               ret = altos_flush(file);
+               if (ret)
+                       return ret;
+       }
+       file->out_data[file->out_used++] = c;
+       if (file->out_used == USB_BUF_SIZE)
+               return altos_flush(file);
+       return 0;
+}
+
+int
+altos_flush(struct altos_file *file)
+{
+       while (file->out_used) {
+               int     ret;
+
+               ret = write (file->fd, file->out_data, file->out_used);
+               if (ret < 0)
+                       return -errno;
+               if (ret) {
+                       memmove(file->out_data, file->out_data + ret,
+                               file->out_used - ret);
+                       file->out_used -= ret;
+               }
+       }
+}
+
+int
+altos_getchar(struct altos_file *file, int timeout)
+{
+       while (file->in_read == file->in_used) {
+               int     ret;
+
+               altos_flush(file);
+               ret = read(file->fd, file->in_data, USB_BUF_SIZE);
+               if (ret < 0)
+                       return -errno;
+               file->in_read = 0;
+               file->in_used = ret;
+       }
+       return file->in_data[file->in_read++];
+}
+
+#endif /* POSIX_TTY */
+
+#ifdef USE_LIBUSB
+#include <libusb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+libusb_context *usb_context;
+
+int altos_init(void)
+{
+       int     ret;
+       ret = libusb_init(&usb_context);
+       if (ret)
+               return ret;
+       libusb_set_debug(usb_context, 3);
+       return 0;
+}
+
+void altos_fini(void)
+{
+       libusb_exit(usb_context);
+       usb_context = NULL;
+}
+
+static libusb_device **list;
+static ssize_t num, current;
+
+int altos_list_start(void)
+{
+       if (list)
+               altos_list_finish();
+       current = 0;
+       num = libusb_get_device_list(usb_context, &list);
+       if (num == 0) {
+               current = num = 0;
+               list = NULL;
+               return 0;
+       }
+       return 1;
+}
+
+int altos_list_next(struct altos_device *device)
+{
+       while (current < num) {
+               struct libusb_device_descriptor descriptor;
+               libusb_device *usb_device = list[current++];
+
+               if (libusb_get_device_descriptor(usb_device, &descriptor) == 0) {
+                       if (descriptor.idVendor == 0xfffe)
+                       {
+                               libusb_device_handle    *handle;
+                               if (libusb_open(usb_device, &handle) == 0) {
+                                       char    serial_number[256];
+                                       libusb_get_string_descriptor_ascii(handle, descriptor.iProduct,
+                                                                          device->product,
+                                                                          sizeof(device->product));
+                                       libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber,
+                                                                          serial_number,
+                                                                          sizeof (serial_number));
+                                       libusb_close(handle);
+                                       device->serial = atoi(serial_number);
+                                       device->device = usb_device;
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+void altos_list_finish(void)
+{
+       if (list) {
+               libusb_free_device_list(list, 1);
+               list = NULL;
+       }
+}
+
+#define USB_BUF_SIZE   64
+
+struct altos_file {
+       struct libusb_device            *device;
+       struct libusb_device_handle     *handle;
+       int                             out_ep;
+       int                             out_size;
+       int                             in_ep;
+       int                             in_size;
+       unsigned char                   out_data[USB_BUF_SIZE];
+       int                             out_used;
+       unsigned char                   in_data[USB_BUF_SIZE];
+       int                             in_used;
+       int                             in_read;
+};
+
+struct altos_file *
+altos_open(struct altos_device *device)
+{
+       struct altos_file               *file;
+       struct libusb_device_handle     *handle;
+       if (libusb_open(device->device, &handle) == 0) {
+               int     ret;
+
+               ret = libusb_claim_interface(handle, 1);
+#if 0
+               if (ret) {
+                       libusb_close(handle);
+                       return NULL;
+               }
+#endif
+               ret = libusb_detach_kernel_driver(handle, 1);
+#if 0
+               if (ret) {
+                       libusb_close(handle);
+                       return NULL;
+               }
+#endif
+
+               file = calloc(sizeof (struct altos_file), 1);
+               file->device = libusb_ref_device(device->device);
+               file->handle = handle;
+               /* XXX should get these from the endpoint descriptors */
+               file->out_ep = 4 | LIBUSB_ENDPOINT_OUT;
+               file->out_size = 64;
+               file->in_ep = 5 | LIBUSB_ENDPOINT_IN;
+               file->in_size = 64;
+
+               return file;
+       }
+       return NULL;
+}
+
+void
+altos_close(struct altos_file *file)
+{
+       libusb_close(file->handle);
+       libusb_unref_device(file->device);
+       file->handle = NULL;
+       free(file);
+}
+
+int
+altos_putchar(struct altos_file *file, char c)
+{
+       int     ret;
+
+       if (file->out_used == file->out_size) {
+               ret = altos_flush(file);
+               if (ret)
+                       return ret;
+       }
+       file->out_data[file->out_used++] = c;
+       if (file->out_used == file->out_size)
+               return altos_flush(file);
+       return 0;
+}
+
+int
+altos_flush(struct altos_file *file)
+{
+       while (file->out_used) {
+               int     transferred;
+               int     ret;
+
+               ret = libusb_bulk_transfer(file->handle,
+                                          file->out_ep,
+                                          file->out_data,
+                                          file->out_used,
+                                          &transferred,
+                                          0);
+               if (ret)
+                       return ret;
+               if (transferred) {
+                       memmove(file->out_data, file->out_data + transferred,
+                               file->out_used - transferred);
+                       file->out_used -= transferred;
+               }
+       }
+}
+
+int
+altos_getchar(struct altos_file *file, int timeout)
+{
+       while (file->in_read == file->in_used) {
+               int     ret;
+               int     transferred;
+
+               altos_flush(file);
+               ret = libusb_bulk_transfer(file->handle,
+                                          file->in_ep,
+                                          file->in_data,
+                                          file->in_size,
+                                          &transferred,
+                                          (unsigned int) timeout);
+               if (ret)
+                       return ret;
+               file->in_read = 0;
+               file->in_used = transferred;
+       }
+       return file->in_data[file->in_read++];
+}
+
+#endif /* USE_LIBUSB */
diff --git a/ao-tools/libaltos/libaltos.h b/ao-tools/libaltos/libaltos.h
new file mode 100644 (file)
index 0000000..782f244
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _LIBALTOS_H_
+#define _LIBALTOS_H_
+
+struct altos_device {
+       //%immutable;
+       char                            product[256];
+       int                             serial;
+       char                            path[256];
+       //%mutable;
+};
+
+int altos_init(void);
+
+void altos_fini(void);
+
+struct altos_list *
+altos_list_start(void);
+
+int altos_list_next(struct altos_list *list, struct altos_device *device);
+
+void altos_list_finish(struct altos_list *list);
+
+struct altos_file *
+altos_open(struct altos_device *device);
+
+void altos_close(struct altos_file *file);
+
+int
+altos_putchar(struct altos_file *file, char c);
+
+int
+altos_flush(struct altos_file *file);
+
+int
+altos_getchar(struct altos_file *file, int timeout);
+
+#endif /* _LIBALTOS_H_ */
diff --git a/ao-tools/libaltos/libaltos.i0 b/ao-tools/libaltos/libaltos.i0
new file mode 100644 (file)
index 0000000..d06468f
--- /dev/null
@@ -0,0 +1,5 @@
+%module libaltos
+%{
+#include "libaltos.h"
+%}
+