--- /dev/null
+windows/
+linux/
+macosx/
+fat/
+Manifest.txt
+Manifest-fat.txt
+libaltosJNI
+classes
+altosui
+altosui-test
+classaltosui.stamp
+Altos-Linux-*.tar.bz2
+Altos-Mac-*.zip
+Altos-Windows-*.exe
+*.dll
+*.dylib
+*.so
+*.jar
+*.class
--- /dev/null
+<pkg-contents spec="1.12"><f n="AltosUI.app" o="keithp" g="keithp" p="16877" pt="/Users/keithp/altos/ao-tools/altosui/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></f></f></pkg-contents>
\ No newline at end of file
--- /dev/null
+<pkgref spec="1.12" uuid="C5762664-2F26-4536-94C4-56F0FBC08D1A"><config><identifier>org.altusmetrum.altosUi.AltosUI.pkg</identifier><version>0.7</version><description></description><post-install type="none"/><installFrom relative="true" mod="true">AltosUI.app</installFrom><installTo mod="true" relocatable="true">/Applications/AltosUI.app</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>installTo.path</mod><mod>installFrom.isRelativeType</mod><mod>version</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
--- /dev/null
+<pkmkdoc spec="1.12"><properties><title>AltOS UI</title><build>/Users/keithp/altos/ao-tools/altosui/AltosUI.pkg</build><organization>org.altusmetrum</organization><userSees ui="both"/><min-target os="3"/><domain system="true" user="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><description>Install AltOS User Interface</description><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="tofit" bg-align="center"><locale lang="en"><resource relative="true" mod="true" type="background">altusmetrum.jpg</resource></locale></resources><flags/><item type="file">01altosui.xml</item><mod>properties.anywhereDomain</mod><mod>properties.title</mod><mod>properties.customizeOption</mod><mod>description</mod><mod>properties.userDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.util.*;
+import java.text.*;
+
+public class Altos {
+ /* EEProm command letters */
+ static final int AO_LOG_FLIGHT = 'F';
+ static final int AO_LOG_SENSOR = 'A';
+ static final int AO_LOG_TEMP_VOLT = 'T';
+ static final int AO_LOG_DEPLOY = 'D';
+ static final int AO_LOG_STATE = 'S';
+ static final int AO_LOG_GPS_TIME = 'G';
+ static final int AO_LOG_GPS_LAT = 'N';
+ static final int AO_LOG_GPS_LON = 'W';
+ static final int AO_LOG_GPS_ALT = 'H';
+ static final int AO_LOG_GPS_SAT = 'V';
+ static final int AO_LOG_GPS_DATE = 'Y';
+
+ /* Added for header fields in eeprom files */
+ static final int AO_LOG_CONFIG_VERSION = 1000;
+ static final int AO_LOG_MAIN_DEPLOY = 1001;
+ static final int AO_LOG_APOGEE_DELAY = 1002;
+ static final int AO_LOG_RADIO_CHANNEL = 1003;
+ static final int AO_LOG_CALLSIGN = 1004;
+ static final int AO_LOG_ACCEL_CAL = 1005;
+ static final int AO_LOG_RADIO_CAL = 1006;
+ static final int AO_LOG_MANUFACTURER = 1007;
+ static final int AO_LOG_PRODUCT = 1008;
+ static final int AO_LOG_SERIAL_NUMBER = 1009;
+ static final int AO_LOG_SOFTWARE_VERSION = 1010;
+
+ /* Added to flag invalid records */
+ static final int AO_LOG_INVALID = -1;
+
+ /* Flight state numbers and names */
+ static final int ao_flight_startup = 0;
+ static final int ao_flight_idle = 1;
+ static final int ao_flight_pad = 2;
+ static final int ao_flight_boost = 3;
+ static final int ao_flight_fast = 4;
+ static final int ao_flight_coast = 5;
+ static final int ao_flight_drogue = 6;
+ static final int ao_flight_main = 7;
+ static final int ao_flight_landed = 8;
+ static final int ao_flight_invalid = 9;
+
+ static HashMap<String,Integer> string_to_state = new HashMap<String,Integer>();
+
+ static boolean map_initialized = false;
+
+ static final int tab_elt_pad = 5;
+
+ static final Font label_font = new Font("Dialog", Font.PLAIN, 22);
+ static final Font value_font = new Font("Monospaced", Font.PLAIN, 22);
+ static final Font status_font = new Font("SansSerif", Font.BOLD, 24);
+
+ static final int text_width = 16;
+
+ static void initialize_map()
+ {
+ string_to_state.put("startup", ao_flight_startup);
+ string_to_state.put("idle", ao_flight_idle);
+ string_to_state.put("pad", ao_flight_pad);
+ string_to_state.put("boost", ao_flight_boost);
+ string_to_state.put("fast", ao_flight_fast);
+ string_to_state.put("coast", ao_flight_coast);
+ string_to_state.put("drogue", ao_flight_drogue);
+ string_to_state.put("main", ao_flight_main);
+ string_to_state.put("landed", ao_flight_landed);
+ string_to_state.put("invalid", ao_flight_invalid);
+ map_initialized = true;
+ }
+
+ static String[] state_to_string = {
+ "startup",
+ "idle",
+ "pad",
+ "boost",
+ "fast",
+ "coast",
+ "drogue",
+ "main",
+ "landed",
+ "invalid",
+ };
+
+ static public int state(String state) {
+ if (!map_initialized)
+ initialize_map();
+ if (string_to_state.containsKey(state))
+ return string_to_state.get(state);
+ return ao_flight_invalid;
+ }
+
+ static public String state_name(int state) {
+ if (state < 0 || state_to_string.length <= state)
+ return "invalid";
+ return state_to_string[state];
+ }
+
+ static final int AO_GPS_VALID = (1 << 4);
+ static final int AO_GPS_RUNNING = (1 << 5);
+ static final int AO_GPS_DATE_VALID = (1 << 6);
+ static final int AO_GPS_NUM_SAT_SHIFT = 0;
+ static final int AO_GPS_NUM_SAT_MASK = 0xf;
+
+ static boolean isspace(int c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ return true;
+ }
+ return false;
+ }
+
+ static boolean ishex(int c) {
+ if ('0' <= c && c <= '9')
+ return true;
+ if ('a' <= c && c <= 'f')
+ return true;
+ if ('A' <= c && c <= 'F')
+ return true;
+ return false;
+ }
+
+ static boolean ishex(String s) {
+ for (int i = 0; i < s.length(); i++)
+ if (!ishex(s.charAt(i)))
+ return false;
+ return true;
+ }
+
+ static int fromhex(int c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+ }
+
+ static int fromhex(String s) throws NumberFormatException {
+ int c, v = 0;
+ for (int i = 0; i < s.length(); i++) {
+ c = s.charAt(i);
+ if (!ishex(c)) {
+ if (i == 0)
+ throw new NumberFormatException(String.format("invalid hex \"%s\"", s));
+ return v;
+ }
+ v = v * 16 + fromhex(c);
+ }
+ return v;
+ }
+
+ static boolean isdec(int c) {
+ if ('0' <= c && c <= '9')
+ return true;
+ return false;
+ }
+
+ static boolean isdec(String s) {
+ for (int i = 0; i < s.length(); i++)
+ if (!isdec(s.charAt(i)))
+ return false;
+ return true;
+ }
+
+ static int fromdec(int c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ return -1;
+ }
+
+ static int fromdec(String s) throws NumberFormatException {
+ int c, v = 0;
+ int sign = 1;
+ for (int i = 0; i < s.length(); i++) {
+ c = s.charAt(i);
+ if (i == 0 && c == '-') {
+ sign = -1;
+ } else if (!isdec(c)) {
+ if (i == 0)
+ throw new NumberFormatException(String.format("invalid number \"%s\"", s));
+ return v;
+ } else
+ v = v * 10 + fromdec(c);
+ }
+ return v * sign;
+ }
+
+ static String replace_extension(String input, String extension) {
+ int dot = input.lastIndexOf(".");
+ if (dot > 0)
+ input = input.substring(0,dot);
+ return input.concat(extension);
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosAscent extends JComponent implements AltosFlightDisplay {
+ GridBagLayout layout;
+
+ public class AscentStatus {
+ JLabel label;
+ JTextField value;
+ AltosLights lights;
+
+ void show(AltosState state, int crc_errors) {}
+ void reset() {
+ value.setText("");
+ lights.set(false);
+ }
+
+ public AscentStatus (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ lights = new AltosLights();
+ c.gridx = 0; c.gridy = y;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(lights, c);
+ add(lights);
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 2; c.gridy = y;
+ c.gridwidth = 2;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+
+ }
+ }
+
+ public class AscentValue {
+ JLabel label;
+ JTextField value;
+ void show(AltosState state, int crc_errors) {}
+
+ void reset() {
+ value.setText("");
+ }
+ public AscentValue (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 2; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.gridwidth = 2;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+ }
+ }
+
+ public class AscentValueHold {
+ JLabel label;
+ JTextField value;
+ JTextField max_value;
+ double max;
+
+ void show(AltosState state, int crc_errors) {}
+
+ void reset() {
+ value.setText("");
+ max_value.setText("");
+ max = 0;
+ }
+
+ void show(String format, double v) {
+ value.setText(String.format(format, v));
+ if (v > max) {
+ max_value.setText(String.format(format, v));
+ max = v;
+ }
+ }
+ public AscentValueHold (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 2; c.gridy = y;
+ c.anchor = GridBagConstraints.EAST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+
+ max_value = new JTextField(Altos.text_width);
+ max_value.setFont(Altos.value_font);
+ max_value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 3; c.gridy = y;
+ c.anchor = GridBagConstraints.EAST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(max_value, c);
+ add(max_value);
+ }
+ }
+
+
+ class Height extends AscentValueHold {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m", state.height);
+ }
+ public Height (GridBagLayout layout, int y) {
+ super (layout, y, "Height");
+ }
+ }
+
+ Height height;
+
+ class Speed extends AscentValueHold {
+ void show (AltosState state, int crc_errors) {
+ double speed = state.speed;
+ if (!state.ascent)
+ speed = state.baro_speed;
+ show("%6.0f m/s", speed);
+ }
+ public Speed (GridBagLayout layout, int y) {
+ super (layout, y, "Speed");
+ }
+ }
+
+ Speed speed;
+
+ class Accel extends AscentValueHold {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m/s²", state.acceleration);
+ }
+ public Accel (GridBagLayout layout, int y) {
+ super (layout, y, "Acceleration");
+ }
+ }
+
+ Accel accel;
+
+ String pos(double p, String pos, String neg) {
+ String h = pos;
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%s %4d° %9.6f", h, deg, min);
+ }
+
+ class Apogee extends AscentStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.drogue_sense));
+ lights.set(state.drogue_sense > 3.2);
+ }
+ public Apogee (GridBagLayout layout, int y) {
+ super(layout, y, "Apogee Igniter Voltage");
+ }
+ }
+
+ Apogee apogee;
+
+ class Main extends AscentStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.main_sense));
+ lights.set(state.main_sense > 3.2);
+ }
+ public Main (GridBagLayout layout, int y) {
+ super(layout, y, "Main Igniter Voltage");
+ }
+ }
+
+ Main main;
+
+ class Lat extends AscentValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ value.setText(pos(state.gps.lat,"N", "S"));
+ else
+ value.setText("???");
+ }
+ public Lat (GridBagLayout layout, int y) {
+ super (layout, y, "Latitude");
+ }
+ }
+
+ Lat lat;
+
+ class Lon extends AscentValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ value.setText(pos(state.gps.lon,"E", "W"));
+ else
+ value.setText("???");
+ }
+ public Lon (GridBagLayout layout, int y) {
+ super (layout, y, "Longitude");
+ }
+ }
+
+ Lon lon;
+
+ public void reset() {
+ lat.reset();
+ lon.reset();
+ main.reset();
+ apogee.reset();
+ height.reset();
+ speed.reset();
+ accel.reset();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ height.show(state, crc_errors);
+ main.show(state, crc_errors);
+ apogee.show(state, crc_errors);
+ speed.show(state, crc_errors);
+ accel.show(state, crc_errors);
+ }
+
+ public void labels(GridBagLayout layout, int y) {
+ GridBagConstraints c;
+ JLabel cur, max;
+
+ cur = new JLabel("Current");
+ cur.setFont(Altos.label_font);
+ c = new GridBagConstraints();
+ c.gridx = 2; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ layout.setConstraints(cur, c);
+ add(cur);
+
+ max = new JLabel("Maximum");
+ max.setFont(Altos.label_font);
+ c.gridx = 3; c.gridy = y;
+ layout.setConstraints(max, c);
+ add(max);
+ }
+
+ public AltosAscent() {
+ layout = new GridBagLayout();
+
+ setLayout(layout);
+
+ /* Elements in ascent display:
+ *
+ * lat
+ * lon
+ * height
+ */
+ labels(layout, 0);
+ height = new Height(layout, 1);
+ speed = new Speed(layout, 2);
+ accel = new Accel(layout, 3);
+ lat = new Lat(layout, 4);
+ lon = new Lon(layout, 5);
+ apogee = new Apogee(layout, 6);
+ main = new Main(layout, 7);
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public class AltosCRCException extends Exception {
+ public int rssi;
+
+ public AltosCRCException (int in_rssi) {
+ rssi = in_rssi;
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.util.*;
+
+public class AltosCSV implements AltosWriter {
+ File name;
+ PrintStream out;
+ boolean header_written;
+ boolean seen_boost;
+ int boost_tick;
+ LinkedList<AltosRecord> pad_records;
+ AltosState state;
+
+ static final int ALTOS_CSV_VERSION = 2;
+
+ /* Version 2 format:
+ *
+ * General info
+ * version number
+ * serial number
+ * flight number
+ * callsign
+ * time (seconds since boost)
+ * rssi
+ * link quality
+ *
+ * Flight status
+ * state
+ * state name
+ *
+ * Basic sensors
+ * acceleration (m/s²)
+ * pressure (mBar)
+ * altitude (m)
+ * height (m)
+ * accelerometer speed (m/s)
+ * barometer speed (m/s)
+ * temp (°C)
+ * battery (V)
+ * drogue (V)
+ * main (V)
+ *
+ * GPS data
+ * connected (1/0)
+ * locked (1/0)
+ * nsat (used for solution)
+ * latitude (°)
+ * longitude (°)
+ * altitude (m)
+ * year (e.g. 2010)
+ * month (1-12)
+ * day (1-31)
+ * hour (0-23)
+ * minute (0-59)
+ * second (0-59)
+ * from_pad_dist (m)
+ * from_pad_azimuth (deg true)
+ * from_pad_range (m)
+ * from_pad_elevation (deg from horizon)
+ * hdop
+ *
+ * GPS Sat data
+ * C/N0 data for all 32 valid SDIDs
+ */
+
+ void write_general_header() {
+ out.printf("version,serial,flight,call,time,rssi,lqi");
+ }
+
+ void write_general(AltosRecord record) {
+ out.printf("%s, %d, %d, %s, %8.2f, %4d, %3d",
+ ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign,
+ (double) record.time,
+ record.rssi,
+ record.status & 0x7f);
+ }
+
+ void write_flight_header() {
+ out.printf("state,state_name");
+ }
+
+ void write_flight(AltosRecord record) {
+ out.printf("%d,%8s", record.state, record.state());
+ }
+
+ void write_basic_header() {
+ out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,battery_voltage,drogue_voltage,main_voltage");
+ }
+
+ void write_basic(AltosRecord record) {
+ out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
+ record.acceleration(),
+ record.raw_pressure(),
+ record.raw_altitude(),
+ record.raw_height(),
+ record.accel_speed(),
+ state.baro_speed,
+ record.temperature(),
+ record.battery_voltage(),
+ record.drogue_voltage(),
+ record.main_voltage());
+ }
+
+ void write_gps_header() {
+ out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop");
+ }
+
+ void write_gps(AltosRecord record) {
+ AltosGPS gps = record.gps;
+ if (gps == null)
+ gps = new AltosGPS();
+
+ AltosGreatCircle from_pad = state.from_pad;
+ if (from_pad == null)
+ from_pad = new AltosGreatCircle();
+
+ out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
+ gps.connected?1:0,
+ gps.locked?1:0,
+ gps.nsat,
+ gps.lat,
+ gps.lon,
+ gps.alt,
+ gps.year,
+ gps.month,
+ gps.day,
+ gps.hour,
+ gps.minute,
+ gps.second,
+ from_pad.distance,
+ state.range,
+ from_pad.bearing,
+ state.elevation,
+ gps.hdop);
+ }
+
+ void write_gps_sat_header() {
+ for(int i = 1; i <= 32; i++) {
+ out.printf("sat%02d", i);
+ if (i != 32)
+ out.printf(",");
+ }
+ }
+
+ void write_gps_sat(AltosRecord record) {
+ AltosGPS gps = record.gps;
+ for(int i = 1; i <= 32; i++) {
+ int c_n0 = 0;
+ if (gps != null && gps.cc_gps_sat != null) {
+ for(int j = 0; j < gps.cc_gps_sat.length; j++)
+ if (gps.cc_gps_sat[j].svid == i) {
+ c_n0 = gps.cc_gps_sat[j].c_n0;
+ break;
+ }
+ }
+ out.printf ("%3d", c_n0);
+ if (i != 32)
+ out.printf(",");
+ }
+ }
+
+ void write_header() {
+ out.printf("#"); write_general_header();
+ out.printf(","); write_flight_header();
+ out.printf(","); write_basic_header();
+ out.printf(","); write_gps_header();
+ out.printf(","); write_gps_sat_header();
+ out.printf ("\n");
+ }
+
+ void write_one(AltosRecord record) {
+ state = new AltosState(record, state);
+ write_general(record); out.printf(",");
+ write_flight(record); out.printf(",");
+ write_basic(record); out.printf(",");
+ write_gps(record); out.printf(",");
+ write_gps_sat(record);
+ out.printf ("\n");
+ }
+
+ void flush_pad() {
+ while (!pad_records.isEmpty()) {
+ write_one (pad_records.remove());
+ }
+ }
+
+ public void write(AltosRecord record) {
+ if (!header_written) {
+ write_header();
+ header_written = true;
+ }
+ if (!seen_boost) {
+ if (record.state >= Altos.ao_flight_boost) {
+ seen_boost = true;
+ boost_tick = record.tick;
+ flush_pad();
+ }
+ }
+ if (seen_boost)
+ write_one(record);
+ else
+ pad_records.add(record);
+ }
+
+ public PrintStream out() {
+ return out;
+ }
+
+ public void close() {
+ if (!pad_records.isEmpty()) {
+ boost_tick = pad_records.element().tick;
+ flush_pad();
+ }
+ out.close();
+ }
+
+ public void write(AltosRecordIterable iterable) {
+ iterable.write_comments(out());
+ for (AltosRecord r : iterable)
+ write(r);
+ }
+
+ public AltosCSV(File in_name) throws FileNotFoundException {
+ name = in_name;
+ out = new PrintStream(name);
+ pad_records = new LinkedList<AltosRecord>();
+ }
+
+ public AltosCSV(String in_string) throws FileNotFoundException {
+ this(new File(in_string));
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosCSVUI
+ extends JDialog
+ implements ActionListener
+{
+ JFileChooser csv_chooser;
+ JPanel accessory;
+ JComboBox combo_box;
+ AltosRecordIterable iterable;
+ AltosWriter writer;
+
+ static String[] combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
+
+ void set_default_file() {
+ File current = csv_chooser.getSelectedFile();
+ String current_name = current.getName();
+ String new_name = null;
+ String selected = (String) combo_box.getSelectedItem();
+
+ if (selected.contains("CSV"))
+ new_name = Altos.replace_extension(current_name, ".csv");
+ else if (selected.contains("KML"))
+ new_name = Altos.replace_extension(current_name, ".kml");
+ if (new_name != null)
+ csv_chooser.setSelectedFile(new File(new_name));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand().equals("comboBoxChanged"))
+ set_default_file();
+ }
+
+ public AltosCSVUI(JFrame frame, AltosRecordIterable in_iterable, File source_file) {
+ iterable = in_iterable;
+ csv_chooser = new JFileChooser(source_file);
+
+ accessory = new JPanel();
+ accessory.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = 1;
+ c.weighty = 0;
+ c.insets = new Insets (4, 4, 4, 4);
+
+ JLabel accessory_label = new JLabel("Export File Type");
+ c.gridx = 0;
+ c.gridy = 0;
+ accessory.add(accessory_label, c);
+
+ combo_box = new JComboBox(combo_box_items);
+ combo_box.addActionListener(this);
+ c.gridx = 0;
+ c.gridy = 1;
+ accessory.add(combo_box, c);
+
+ csv_chooser.setAccessory(accessory);
+ csv_chooser.setSelectedFile(source_file);
+ set_default_file();
+ int ret = csv_chooser.showSaveDialog(frame);
+ if (ret == JFileChooser.APPROVE_OPTION) {
+ File file = csv_chooser.getSelectedFile();
+ String type = (String) combo_box.getSelectedItem();
+ try {
+ if (type.contains("CSV"))
+ writer = new AltosCSV(file);
+ else
+ writer = new AltosKML(file);
+ writer.write(iterable);
+ writer.close();
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(frame,
+ file.getName(),
+ "Cannot open file",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosChannelMenu extends JComboBox implements ActionListener {
+ int channel;
+
+ public AltosChannelMenu(int current_channel) {
+
+ channel = current_channel;
+
+ for (int c = 0; c <= 9; c++)
+ addItem(String.format("Channel %1d (%7.3fMHz)", c, 434.550 + c * 0.1));
+ setSelectedIndex(channel);
+ setMaximumRowCount(10);
+ }
+
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+
+import libaltosJNI.*;
+
+public class AltosConfig implements Runnable, ActionListener {
+
+ class int_ref {
+ int value;
+
+ public int get() {
+ return value;
+ }
+ public void set(int i) {
+ value = i;
+ }
+ public int_ref(int i) {
+ value = i;
+ }
+ }
+
+ class string_ref {
+ String value;
+
+ public String get() {
+ return value;
+ }
+ public void set(String i) {
+ value = i;
+ }
+ public string_ref(String i) {
+ value = i;
+ }
+ }
+
+ JFrame owner;
+ AltosDevice device;
+ AltosSerial serial_line;
+ boolean remote;
+ Thread config_thread;
+ int_ref serial;
+ int_ref main_deploy;
+ int_ref apogee_delay;
+ int_ref radio_channel;
+ int_ref radio_calibration;
+ string_ref version;
+ string_ref product;
+ string_ref callsign;
+ AltosConfigUI config_ui;
+ boolean serial_started;
+
+ boolean get_int(String line, String label, int_ref x) {
+ if (line.startsWith(label)) {
+ try {
+ String tail = line.substring(label.length()).trim();
+ String[] tokens = tail.split("\\s+");
+ if (tokens.length > 0) {
+ int i = Integer.parseInt(tokens[0]);
+ x.set(i);
+ return true;
+ }
+ } catch (NumberFormatException ne) {
+ }
+ }
+ return false;
+ }
+
+ boolean get_string(String line, String label, string_ref s) {
+ if (line.startsWith(label)) {
+ String quoted = line.substring(label.length()).trim();
+
+ if (quoted.startsWith("\""))
+ quoted = quoted.substring(1);
+ if (quoted.endsWith("\""))
+ quoted = quoted.substring(0,quoted.length()-1);
+ s.set(quoted);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void start_serial() throws InterruptedException {
+ serial_started = true;
+ if (remote) {
+ serial_line.set_radio();
+ serial_line.printf("p\nE 0\n");
+ serial_line.flush_input();
+ }
+ }
+
+ void stop_serial() throws InterruptedException {
+ if (!serial_started)
+ return;
+ serial_started = false;
+ if (remote) {
+ serial_line.printf("~");
+ serial_line.flush_output();
+ }
+ }
+
+ void get_data() throws InterruptedException, TimeoutException {
+ try {
+ start_serial();
+ serial_line.printf("c s\nv\n");
+ for (;;) {
+ String line = serial_line.get_reply(5000);
+ if (line == null)
+ throw new TimeoutException();
+ get_int(line, "serial-number", serial);
+ get_int(line, "Main deploy:", main_deploy);
+ get_int(line, "Apogee delay:", apogee_delay);
+ get_int(line, "Radio channel:", radio_channel);
+ get_int(line, "Radio cal:", radio_calibration);
+ get_string(line, "Callsign:", callsign);
+ get_string(line,"software-version", version);
+ get_string(line,"product", product);
+
+ /* signals the end of the version info */
+ if (line.startsWith("software-version"))
+ break;
+ }
+ } finally {
+ stop_serial();
+ }
+ }
+
+ void init_ui () throws InterruptedException, TimeoutException {
+ config_ui = new AltosConfigUI(owner, remote);
+ config_ui.addActionListener(this);
+ set_ui();
+ }
+
+ void abort() {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Connection to \"%s\" failed",
+ device.toShortString()),
+ "Connection Failed",
+ JOptionPane.ERROR_MESSAGE);
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ serial_line.close();
+ serial_line = null;
+ }
+
+ void set_ui() throws InterruptedException, TimeoutException {
+ if (serial_line != null)
+ get_data();
+ config_ui.set_serial(serial.get());
+ config_ui.set_product(product.get());
+ config_ui.set_version(version.get());
+ config_ui.set_main_deploy(main_deploy.get());
+ config_ui.set_apogee_delay(apogee_delay.get());
+ config_ui.set_radio_channel(radio_channel.get());
+ config_ui.set_radio_calibration(radio_calibration.get());
+ config_ui.set_callsign(callsign.get());
+ config_ui.set_clean();
+ }
+
+ void run_dialog() {
+ }
+
+ void save_data() {
+ main_deploy.set(config_ui.main_deploy());
+ apogee_delay.set(config_ui.apogee_delay());
+ radio_channel.set(config_ui.radio_channel());
+ radio_calibration.set(config_ui.radio_calibration());
+ callsign.set(config_ui.callsign());
+ try {
+ start_serial();
+ serial_line.printf("c m %d\n", main_deploy.get());
+ serial_line.printf("c d %d\n", apogee_delay.get());
+ if (!remote) {
+ serial_line.printf("c r %d\n", radio_channel.get());
+ serial_line.printf("c f %d\n", radio_calibration.get());
+ }
+ serial_line.printf("c c %s\n", callsign.get());
+ serial_line.printf("c w\n");
+ } catch (InterruptedException ie) {
+ } finally {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ try {
+ if (cmd.equals("Save")) {
+ save_data();
+ set_ui();
+ } else if (cmd.equals("Reset")) {
+ set_ui();
+ } else if (cmd.equals("Reboot")) {
+ if (serial_line != null) {
+ start_serial();
+ serial_line.printf("r eboot\n");
+ serial_line.flush_output();
+ stop_serial();
+ serial_line.close();
+ }
+ } else if (cmd.equals("Close")) {
+ if (serial_line != null)
+ serial_line.close();
+ }
+ } catch (InterruptedException ie) {
+ abort();
+ } catch (TimeoutException te) {
+ abort();
+ }
+ }
+
+ public void run () {
+ try {
+ init_ui();
+ config_ui.make_visible();
+ } catch (InterruptedException ie) {
+ abort();
+ } catch (TimeoutException te) {
+ abort();
+ }
+ }
+
+ public AltosConfig(JFrame given_owner) {
+ owner = given_owner;
+
+ serial = new int_ref(0);
+ main_deploy = new int_ref(250);
+ apogee_delay = new int_ref(0);
+ radio_channel = new int_ref(0);
+ radio_calibration = new int_ref(1186611);
+ callsign = new string_ref("N0CALL");
+ version = new string_ref("unknown");
+ product = new string_ref("unknown");
+
+ device = AltosDeviceDialog.show(owner, AltosDevice.product_any);
+ if (device != null) {
+ try {
+ serial_line = new AltosSerial(device);
+ if (!device.matchProduct(AltosDevice.product_telemetrum))
+ remote = true;
+ config_thread = new Thread(this);
+ config_thread.start();
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Cannot open device \"%s\"",
+ device.toShortString()),
+ "Cannot open target device",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (AltosSerialInUseException si) {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Device \"%s\" already in use",
+ device.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ee) {
+ JOptionPane.showMessageDialog(owner,
+ device.toShortString(),
+ ee.getLocalizedMessage(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import libaltosJNI.*;
+
+public class AltosConfigUI
+ extends JDialog
+ implements ActionListener, ItemListener, DocumentListener
+{
+
+ Container pane;
+ Box box;
+ JLabel product_label;
+ JLabel version_label;
+ JLabel serial_label;
+ JLabel main_deploy_label;
+ JLabel apogee_delay_label;
+ JLabel radio_channel_label;
+ JLabel radio_calibration_label;
+ JLabel callsign_label;
+
+ public boolean dirty;
+
+ JFrame owner;
+ JLabel product_value;
+ JLabel version_value;
+ JLabel serial_value;
+ JComboBox main_deploy_value;
+ JComboBox apogee_delay_value;
+ JComboBox radio_channel_value;
+ JTextField radio_calibration_value;
+ JTextField callsign_value;
+
+ JButton save;
+ JButton reset;
+ JButton reboot;
+ JButton close;
+
+ ActionListener listener;
+
+ static String[] main_deploy_values = {
+ "100", "150", "200", "250", "300", "350",
+ "400", "450", "500"
+ };
+
+ static String[] apogee_delay_values = {
+ "0", "1", "2", "3", "4", "5"
+ };
+
+ static String[] radio_channel_values = new String[10];
+ {
+ for (int i = 0; i <= 9; i++)
+ radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
+ i, 434.550 + i * 0.1);
+ }
+
+ /* A window listener to catch closing events and tell the config code */
+ class ConfigListener extends WindowAdapter {
+ AltosConfigUI ui;
+
+ public ConfigListener(AltosConfigUI this_ui) {
+ ui = this_ui;
+ }
+
+ public void windowClosing(WindowEvent e) {
+ ui.actionPerformed(new ActionEvent(e.getSource(),
+ ActionEvent.ACTION_PERFORMED,
+ "Close"));
+ }
+ }
+
+ /* Build the UI using a grid bag */
+ public AltosConfigUI(JFrame in_owner, boolean remote) {
+ super (in_owner, "Configure TeleMetrum", false);
+
+ owner = in_owner;
+ GridBagConstraints c;
+
+ Insets il = new Insets(4,4,4,4);
+ Insets ir = new Insets(4,4,4,4);
+
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ /* Product */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ product_label = new JLabel("Product:");
+ pane.add(product_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 0;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ product_value = new JLabel("");
+ pane.add(product_value, c);
+
+ /* Version */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 1;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ version_label = new JLabel("Software version:");
+ pane.add(version_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 1;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ version_value = new JLabel("");
+ pane.add(version_value, c);
+
+ /* Serial */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 2;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ serial_label = new JLabel("Serial:");
+ pane.add(serial_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 2;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ serial_value = new JLabel("");
+ pane.add(serial_value, c);
+
+ /* Main deploy */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 3;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ main_deploy_label = new JLabel("Main Deploy Altitude(m):");
+ pane.add(main_deploy_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 3;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ main_deploy_value = new JComboBox(main_deploy_values);
+ main_deploy_value.setEditable(true);
+ main_deploy_value.addItemListener(this);
+ pane.add(main_deploy_value, c);
+
+ /* Apogee delay */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 4;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ apogee_delay_label = new JLabel("Apogee Delay(s):");
+ pane.add(apogee_delay_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 4;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ apogee_delay_value = new JComboBox(apogee_delay_values);
+ apogee_delay_value.setEditable(true);
+ apogee_delay_value.addItemListener(this);
+ pane.add(apogee_delay_value, c);
+
+ /* Radio channel */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 5;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ radio_channel_label = new JLabel("Radio Channel:");
+ pane.add(radio_channel_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 5;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ radio_channel_value = new JComboBox(radio_channel_values);
+ radio_channel_value.setEditable(false);
+ radio_channel_value.addItemListener(this);
+ if (remote)
+ radio_channel_value.setEnabled(false);
+ pane.add(radio_channel_value, c);
+
+ /* Radio Calibration */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 6;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ radio_calibration_label = new JLabel("RF Calibration:");
+ pane.add(radio_calibration_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 6;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ radio_calibration_value = new JTextField(String.format("%d", 1186611));
+ radio_calibration_value.getDocument().addDocumentListener(this);
+ if (remote)
+ radio_calibration_value.setEnabled(false);
+ pane.add(radio_calibration_value, c);
+
+ /* Callsign */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 7;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ callsign_label = new JLabel("Callsign:");
+ pane.add(callsign_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 7;
+ c.gridwidth = 4;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ callsign_value = new JTextField(AltosPreferences.callsign());
+ callsign_value.getDocument().addDocumentListener(this);
+ pane.add(callsign_value, c);
+
+ /* Buttons */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 8;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ save = new JButton("Save");
+ pane.add(save, c);
+ save.addActionListener(this);
+ save.setActionCommand("Save");
+
+ c = new GridBagConstraints();
+ c.gridx = 2; c.gridy = 8;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = il;
+ reset = new JButton("Reset");
+ pane.add(reset, c);
+ reset.addActionListener(this);
+ reset.setActionCommand("Reset");
+
+ c = new GridBagConstraints();
+ c.gridx = 4; c.gridy = 8;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = il;
+ reboot = new JButton("Reboot");
+ pane.add(reboot, c);
+ reboot.addActionListener(this);
+ reboot.setActionCommand("Reboot");
+
+ c = new GridBagConstraints();
+ c.gridx = 6; c.gridy = 8;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_END;
+ c.insets = il;
+ close = new JButton("Close");
+ pane.add(close, c);
+ close.addActionListener(this);
+ close.setActionCommand("Close");
+
+ addWindowListener(new ConfigListener(this));
+ }
+
+ /* Once the initial values are set, the config code will show the dialog */
+ public void make_visible() {
+ pack();
+ setLocationRelativeTo(owner);
+ setVisible(true);
+ }
+
+ /* If any values have been changed, confirm before closing */
+ public boolean check_dirty(String operation) {
+ if (dirty) {
+ Object[] options = { String.format("%s anyway", operation), "Keep editing" };
+ int i;
+ i = JOptionPane.showOptionDialog(this,
+ String.format("Configuration modified. %s anyway?", operation),
+ "Configuration Modified",
+ JOptionPane.DEFAULT_OPTION,
+ JOptionPane.WARNING_MESSAGE,
+ null, options, options[1]);
+ if (i != 0)
+ return false;
+ }
+ return true;
+ }
+
+ /* Listen for events from our buttons */
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+
+ if (cmd.equals("Close") || cmd.equals("Reboot"))
+ if (!check_dirty(cmd))
+ return;
+ listener.actionPerformed(e);
+ if (cmd.equals("Close") || cmd.equals("Reboot")) {
+ setVisible(false);
+ dispose();
+ }
+ dirty = false;
+ }
+
+ /* ItemListener interface method */
+ public void itemStateChanged(ItemEvent e) {
+ dirty = true;
+ }
+
+ /* DocumentListener interface methods */
+ public void changedUpdate(DocumentEvent e) {
+ dirty = true;
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ dirty = true;
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ dirty = true;
+ }
+
+ /* Let the config code hook on a listener */
+ public void addActionListener(ActionListener l) {
+ listener = l;
+ }
+
+ /* set and get all of the dialog values */
+ public void set_product(String product) {
+ product_value.setText(product);
+ }
+
+ public void set_version(String version) {
+ version_value.setText(version);
+ }
+
+ public void set_serial(int serial) {
+ serial_value.setText(String.format("%d", serial));
+ }
+
+ public void set_main_deploy(int new_main_deploy) {
+ main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
+ }
+
+ public int main_deploy() {
+ return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
+ }
+
+ public void set_apogee_delay(int new_apogee_delay) {
+ apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
+ }
+
+ public int apogee_delay() {
+ return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
+ }
+
+ public void set_radio_channel(int new_radio_channel) {
+ radio_channel_value.setSelectedIndex(new_radio_channel);
+ }
+
+ public int radio_channel() {
+ return radio_channel_value.getSelectedIndex();
+ }
+
+ public void set_radio_calibration(int new_radio_calibration) {
+ radio_calibration_value.setText(String.format("%d", new_radio_calibration));
+ }
+
+ public int radio_calibration() {
+ return Integer.parseInt(radio_calibration_value.getText());
+ }
+
+ public void set_callsign(String new_callsign) {
+ callsign_value.setText(new_callsign);
+ }
+
+ public String callsign() {
+ return callsign_value.getText();
+ }
+
+ public void set_clean() {
+ dirty = false;
+ }
+
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosConfigureUI
+ extends JDialog
+ implements DocumentListener
+{
+ JFrame owner;
+ AltosVoice voice;
+ Container pane;
+
+ JRadioButton enable_voice;
+ JButton test_voice;
+ JButton close;
+
+ JButton configure_log;
+ JTextField log_directory;
+
+ JLabel callsign_label;
+ JTextField callsign_value;
+
+ /* DocumentListener interface methods */
+ public void changedUpdate(DocumentEvent e) {
+ AltosPreferences.set_callsign(callsign_value.getText());
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ changedUpdate(e);
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ changedUpdate(e);
+ }
+
+ public AltosConfigureUI(JFrame in_owner, AltosVoice in_voice) {
+ super(in_owner, "Configure AltosUI", false);
+
+ GridBagConstraints c;
+
+ Insets insets = new Insets(4, 4, 4, 4);
+
+ owner = in_owner;
+ voice = in_voice;
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ c = new GridBagConstraints();
+ c.insets = insets;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+
+ /* Nice label at the top */
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ pane.add(new JLabel ("Configure AltOS UI"), c);
+
+ /* Voice settings */
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(new JLabel("Voice"), c);
+
+ enable_voice = new JRadioButton("Enable", AltosPreferences.voice());
+ enable_voice.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JRadioButton item = (JRadioButton) e.getSource();
+ boolean enabled = item.isSelected();
+ AltosPreferences.set_voice(enabled);
+ if (enabled)
+ voice.speak_always("Enable voice.");
+ else
+ voice.speak_always("Disable voice.");
+ }
+ });
+ c.gridx = 1;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.weightx = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(enable_voice, c);
+
+ c.gridx = 2;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.weightx = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.EAST;
+ test_voice = new JButton("Test Voice");
+ test_voice.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ voice.speak("That's one small step for man; one giant leap for mankind.");
+ }
+ });
+ pane.add(test_voice, c);
+
+ /* Log directory settings */
+ c.gridx = 0;
+ c.gridy = 2;
+ c.gridwidth = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(new JLabel("Log Directory"), c);
+
+ configure_log = new JButton(AltosPreferences.logdir().getPath());
+ configure_log.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ AltosPreferences.ConfigureLog();
+ configure_log.setText(AltosPreferences.logdir().getPath());
+ }
+ });
+ c.gridx = 1;
+ c.gridy = 2;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(configure_log, c);
+
+ /* Callsign setting */
+ c.gridx = 0;
+ c.gridy = 3;
+ c.gridwidth = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(new JLabel("Callsign"), c);
+
+ callsign_value = new JTextField(AltosPreferences.callsign());
+ callsign_value.getDocument().addDocumentListener(this);
+ c.gridx = 1;
+ c.gridy = 3;
+ c.gridwidth = 2;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.WEST;
+ pane.add(callsign_value, c);
+
+ /* And a close button at the bottom */
+ close = new JButton("Close");
+ close.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setVisible(false);
+ }
+ });
+ c.gridx = 0;
+ c.gridy = 4;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ pane.add(close, c);
+
+ pack();
+ setLocationRelativeTo(owner);
+ setVisible(true);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ * Sensor data conversion functions
+ */
+package altosui;
+
+public class AltosConvert {
+ /*
+ * Pressure Sensor Model, version 1.1
+ *
+ * written by Holly Grimes
+ *
+ * Uses the International Standard Atmosphere as described in
+ * "A Quick Derivation relating altitude to air pressure" (version 1.03)
+ * from the Portland State Aerospace Society, except that the atmosphere
+ * is divided into layers with each layer having a different lapse rate.
+ *
+ * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
+ * at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
+ *
+ * Height measurements use the local tangent plane. The postive z-direction is up.
+ *
+ * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
+ * The lapse rate is given in Kelvin/meter, the gas constant for air is given
+ * in Joules/(kilogram-Kelvin).
+ */
+
+ static final double GRAVITATIONAL_ACCELERATION = -9.80665;
+ static final double AIR_GAS_CONSTANT = 287.053;
+ static final double NUMBER_OF_LAYERS = 7;
+ static final double MAXIMUM_ALTITUDE = 84852.0;
+ static final double MINIMUM_PRESSURE = 0.3734;
+ static final double LAYER0_BASE_TEMPERATURE = 288.15;
+ static final double LAYER0_BASE_PRESSURE = 101325;
+
+ /* lapse rate and base altitude for each layer in the atmosphere */
+ static final double[] lapse_rate = {
+ -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
+ };
+
+ static final int[] base_altitude = {
+ 0, 11000, 20000, 32000, 47000, 51000, 71000
+ };
+
+ /* outputs atmospheric pressure associated with the given altitude.
+ * altitudes are measured with respect to the mean sea level
+ */
+ static double
+ altitude_to_pressure(double altitude)
+ {
+ double base_temperature = LAYER0_BASE_TEMPERATURE;
+ double base_pressure = LAYER0_BASE_PRESSURE;
+
+ double pressure;
+ double base; /* base for function to determine pressure */
+ double exponent; /* exponent for function to determine pressure */
+ int layer_number; /* identifies layer in the atmosphere */
+ double delta_z; /* difference between two altitudes */
+
+ if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
+ return 0;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted altitude */
+ for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ base_pressure *= Math.exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ base_pressure *= Math.pow(base, exponent);
+ }
+ base_temperature += delta_z * lapse_rate[layer_number];
+ }
+
+ /* calculate the pressure at the inputted altitude */
+ delta_z = altitude - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ pressure = base_pressure * Math.exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ pressure = base_pressure * Math.pow(base, exponent);
+ }
+
+ return pressure;
+ }
+
+
+/* outputs the altitude associated with the given pressure. the altitude
+ returned is measured with respect to the mean sea level */
+ static double
+ pressure_to_altitude(double pressure)
+ {
+
+ double next_base_temperature = LAYER0_BASE_TEMPERATURE;
+ double next_base_pressure = LAYER0_BASE_PRESSURE;
+
+ double altitude;
+ double base_pressure;
+ double base_temperature;
+ double base; /* base for function to determine base pressure of next layer */
+ double exponent; /* exponent for function to determine base pressure
+ of next layer */
+ double coefficient;
+ int layer_number; /* identifies layer in the atmosphere */
+ int delta_z; /* difference between two altitudes */
+
+ if (pressure < 0) /* illegal pressure */
+ return -1;
+ if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
+ return MAXIMUM_ALTITUDE;
+
+ /* calculate the base temperature and pressure for the atmospheric layer
+ associated with the inputted pressure. */
+ layer_number = -1;
+ do {
+ layer_number++;
+ base_pressure = next_base_pressure;
+ base_temperature = next_base_temperature;
+ delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
+ if (lapse_rate[layer_number] == 0.0) {
+ exponent = GRAVITATIONAL_ACCELERATION * delta_z
+ / AIR_GAS_CONSTANT / base_temperature;
+ next_base_pressure *= Math.exp(exponent);
+ }
+ else {
+ base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
+ exponent = GRAVITATIONAL_ACCELERATION /
+ (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
+ next_base_pressure *= Math.pow(base, exponent);
+ }
+ next_base_temperature += delta_z * lapse_rate[layer_number];
+ }
+ while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
+
+ /* calculate the altitude associated with the inputted pressure */
+ if (lapse_rate[layer_number] == 0.0) {
+ coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
+ * base_temperature;
+ altitude = base_altitude[layer_number]
+ + coefficient * Math.log(pressure / base_pressure);
+ }
+ else {
+ base = pressure / base_pressure;
+ exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
+ / GRAVITATIONAL_ACCELERATION;
+ coefficient = base_temperature / lapse_rate[layer_number];
+ altitude = base_altitude[layer_number]
+ + coefficient * (Math.pow(base, exponent) - 1);
+ }
+
+ return altitude;
+ }
+
+ static double
+ cc_battery_to_voltage(double battery)
+ {
+ return battery / 32767.0 * 5.0;
+ }
+
+ static double
+ cc_ignitor_to_voltage(double ignite)
+ {
+ return ignite / 32767 * 15.0;
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+
+public class AltosDataChooser extends JFileChooser {
+ JFrame frame;
+ String filename;
+ File file;
+
+ public String filename() {
+ return filename;
+ }
+
+ public File file() {
+ return file;
+ }
+
+ public AltosRecordIterable runDialog() {
+ int ret;
+
+ ret = showOpenDialog(frame);
+ if (ret == APPROVE_OPTION) {
+ file = getSelectedFile();
+ if (file == null)
+ return null;
+ filename = file.getName();
+ try {
+ if (filename.endsWith("eeprom")) {
+ FileInputStream in = new FileInputStream(file);
+ return new AltosEepromIterable(in);
+ } else if (filename.endsWith("telem")) {
+ FileInputStream in = new FileInputStream(file);
+ return new AltosTelemetryIterable(in);
+ } else {
+ throw new FileNotFoundException();
+ }
+ } catch (FileNotFoundException fe) {
+ JOptionPane.showMessageDialog(frame,
+ filename,
+ "Cannot open file",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ return null;
+ }
+
+ public AltosDataChooser(JFrame in_frame) {
+ frame = in_frame;
+ setDialogTitle("Select Flight Record File");
+ setFileFilter(new FileNameExtensionFilter("Flight data file",
+ "telem", "eeprom"));
+ setCurrentDirectory(AltosPreferences.logdir());
+ }
+}
--- /dev/null
+
+// Copyright (c) 2010 Anthony Towns
+// GPL v2 or later
+
+package altosui;
+
+interface AltosDataPoint {
+ int version();
+ int serial();
+ int flight();
+ String callsign();
+ double time();
+ double rssi();
+
+ int state();
+ String state_name();
+
+ double acceleration();
+ double pressure();
+ double altitude();
+ double height();
+ double accel_speed();
+ double baro_speed();
+ double temperature();
+ double battery_voltage();
+ double drogue_voltage();
+ double main_voltage();
+}
+
--- /dev/null
+
+// Copyright (c) 2010 Anthony Towns
+// GPL v2 or later
+
+package altosui;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.lang.UnsupportedOperationException;
+import java.util.NoSuchElementException;
+import java.util.Iterator;
+
+class AltosDataPointReader implements Iterable<AltosDataPoint> {
+ Iterator<AltosRecord> iter;
+ AltosState state;
+ AltosRecord record;
+
+ public AltosDataPointReader(Iterable<AltosRecord> reader) {
+ this.iter = reader.iterator();
+ this.state = null;
+ }
+
+ private void read_next_record()
+ throws NoSuchElementException
+ {
+ record = iter.next();
+ state = new AltosState(record, state);
+ }
+
+ private AltosDataPoint current_dp() {
+ assert this.record != null;
+
+ return new AltosDataPoint() {
+ public int version() { return record.version; }
+ public int serial() { return record.serial; }
+ public int flight() { return record.flight; }
+ public String callsign() { return record.callsign; }
+ public double time() { return record.time; }
+ public double rssi() { return record.rssi; }
+
+ public int state() { return record.state; }
+ public String state_name() { return record.state(); }
+
+ public double acceleration() { return record.acceleration(); }
+ public double pressure() { return record.raw_pressure(); }
+ public double altitude() { return record.raw_altitude(); }
+ public double height() { return record.raw_height(); }
+ public double accel_speed() { return record.accel_speed(); }
+ public double baro_speed() { return state.baro_speed; }
+ public double temperature() { return record.temperature(); }
+ public double battery_voltage() { return record.battery_voltage(); }
+ public double drogue_voltage() { return record.drogue_voltage(); }
+ public double main_voltage() { return record.main_voltage(); }
+ };
+ }
+
+ public Iterator<AltosDataPoint> iterator() {
+ return new Iterator<AltosDataPoint>() {
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+ public AltosDataPoint next() {
+ read_next_record();
+ return current_dp();
+ }
+ };
+ }
+}
+
--- /dev/null
+/*
+ * 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.concurrent.*;
+import java.util.*;
+
+import libaltosJNI.*;
+
+public class AltosDebug extends AltosSerial {
+
+ public static final byte WR_CONFIG = 0x1d;
+ public static final byte RD_CONFIG = 0x24;
+ public static final byte CONFIG_TIMERS_OFF = (1 << 3);
+ public static final byte CONFIG_DMA_PAUSE = (1 << 2);
+ public static final byte CONFIG_TIMER_SUSPEND = (1 << 1);
+ public static final byte SET_FLASH_INFO_PAGE = (1 << 0);
+
+ public static final byte GET_PC = 0x28;
+ public static final byte READ_STATUS = 0x34;
+ public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7);
+ public static final byte STATUS_PCON_IDLE = (1 << 6);
+ public static final byte STATUS_CPU_HALTED = (1 << 5);
+ public static final byte STATUS_POWER_MODE_0 = (1 << 4);
+ public static final byte STATUS_HALT_STATUS = (1 << 3);
+ public static final byte STATUS_DEBUG_LOCKED = (1 << 2);
+ public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1);
+ public static final byte STATUS_STACK_OVERFLOW = (1 << 0);
+
+ public static final byte SET_HW_BRKPNT = 0x3b;
+ public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); }
+ public static final byte HW_BRKPNT_N_MASK = (0x3 << 3);
+ public static final byte HW_BRKPNT_ENABLE = (1 << 2);
+
+ public static final byte HALT = 0x44;
+ public static final byte RESUME = 0x4c;
+ public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); }
+ public static final byte STEP_INSTR = 0x5c;
+ public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); }
+ public static final byte GET_CHIP_ID = 0x68;
+
+
+ boolean debug_mode;
+
+ void ensure_debug_mode() {
+ if (!debug_mode) {
+ printf("D\n");
+ flush_input();
+ debug_mode = true;
+ }
+ }
+
+ void dump_memory(String header, int address, byte[] bytes, int start, int len) {
+ System.out.printf("%s\n", header);
+ for (int j = 0; j < len; j++) {
+ if ((j & 15) == 0) {
+ if (j != 0)
+ System.out.printf("\n");
+ System.out.printf ("%04x:", address + j);
+ }
+ System.out.printf(" %02x", bytes[start + j]);
+ }
+ System.out.printf("\n");
+ }
+
+ /*
+ * Write target memory
+ */
+ public void write_memory(int address, byte[] bytes, int start, int len) {
+ ensure_debug_mode();
+// dump_memory("write_memory", address, bytes, start, len);
+ printf("O %x %x\n", len, address);
+ for (int i = 0; i < len; i++)
+ printf("%02x", bytes[start + i]);
+ }
+
+ public void write_memory(int address, byte[] bytes) {
+ write_memory(address, bytes, 0, bytes.length);
+ }
+
+ /*
+ * Read target memory
+ */
+ public byte[] read_memory(int address, int length)
+ throws IOException, InterruptedException {
+ byte[] data = new byte[length];
+
+ flush_input();
+ ensure_debug_mode();
+ printf("I %x %x\n", length, address);
+ int i = 0;
+ int start = 0;
+ while (i < length) {
+ String line = get_reply().trim();
+ if (!Altos.ishex(line) || line.length() % 2 != 0)
+ throw new IOException(
+ String.format
+ ("Invalid reply \"%s\"", line));
+ int this_time = line.length() / 2;
+ for (int j = 0; j < this_time; j++)
+ data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) +
+ Altos.fromhex(line.charAt(j*2+1)));
+ start += this_time;
+ i += this_time;
+ }
+// dump_memory("read_memory", address, data, 0, length);
+
+ return data;
+ }
+
+ /*
+ * Write raw bytes to the debug link using the 'P' command
+ */
+ public void write_bytes(byte[] bytes) throws IOException {
+ int i = 0;
+ ensure_debug_mode();
+ while (i < bytes.length) {
+ int this_time = bytes.length - i;
+ if (this_time > 8)
+ this_time = 0;
+ printf("P");
+ for (int j = 0; j < this_time; j++)
+ printf(" %02x", bytes[i+j]);
+ printf("\n");
+ i += this_time;
+ }
+ }
+
+ public void write_byte(byte b) throws IOException {
+ byte[] bytes = { b };
+ write_bytes(bytes);
+ }
+
+ /*
+ * Read raw bytes from the debug link using the 'G' command
+ */
+ public byte[] read_bytes(int length)
+ throws IOException, InterruptedException {
+
+ flush_input();
+ ensure_debug_mode();
+ printf("G %x\n", length);
+ int i = 0;
+ byte[] data = new byte[length];
+ while (i < length) {
+ String line = get_reply().trim();
+ String tokens[] = line.split("\\s+");
+ for (int j = 0; j < tokens.length; j++) {
+ if (!Altos.ishex(tokens[j]) ||
+ tokens[j].length() != 2)
+ throw new IOException(
+ String.format
+ ("Invalid read_bytes reply \"%s\"", line));
+ try {
+ data[i + j] = (byte) Integer.parseInt(tokens[j], 16);
+ } catch (NumberFormatException ne) {
+ throw new IOException(
+ String.format
+ ("Invalid read_bytes reply \"%s\"", line));
+ }
+ }
+ i += tokens.length;
+ }
+ return data;
+ }
+
+ public byte read_byte() throws IOException, InterruptedException {
+ return read_bytes(1)[0];
+ }
+
+ public byte debug_instr(byte[] instruction) throws IOException, InterruptedException {
+ byte[] command = new byte[1 + instruction.length];
+ command[0] = DEBUG_INSTR((byte) instruction.length);
+ for (int i = 0; i < instruction.length; i++)
+ command[i+1] = instruction[i];
+ write_bytes(command);
+ return read_byte();
+ }
+
+ public byte resume() throws IOException, InterruptedException {
+ write_byte(RESUME);
+ return read_byte();
+ }
+
+ public int read_uint16() throws IOException, InterruptedException {
+ byte[] d = read_bytes(2);
+ return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff);
+ }
+
+ public int read_uint8() throws IOException, InterruptedException {
+ byte[] d = read_bytes(1);
+ return (int) (d[0] & 0xff);
+ }
+
+ public int get_chip_id() throws IOException, InterruptedException {
+ write_byte(GET_CHIP_ID);
+ return read_uint16();
+ }
+
+ public int get_pc() throws IOException, InterruptedException {
+ write_byte(GET_PC);
+ return read_uint16();
+ }
+
+ public byte read_status() throws IOException, InterruptedException {
+ write_byte(READ_STATUS);
+ return read_byte();
+ }
+
+ static final byte LJMP = 0x02;
+
+ public void set_pc(int pc) throws IOException, InterruptedException {
+ byte high = (byte) (pc >> 8);
+ byte low = (byte) pc;
+ byte[] jump_mem = { LJMP, high, low };
+ debug_instr(jump_mem);
+ }
+
+ public boolean check_connection() throws IOException, InterruptedException {
+ byte reply = read_status();
+ if ((reply & STATUS_CHIP_ERASE_DONE) == 0)
+ return false;
+ if ((reply & STATUS_PCON_IDLE) != 0)
+ return false;
+ if ((reply & STATUS_POWER_MODE_0) == 0)
+ return false;
+ return true;
+ }
+
+ public AltosRomconfig romconfig() {
+ try {
+ byte[] bytes = read_memory(0xa0, 10);
+ return new AltosRomconfig(bytes, 0);
+ } catch (IOException ie) {
+ } catch (InterruptedException ie) {
+ }
+ return new AltosRomconfig();
+ }
+
+ /*
+ * Reset target
+ */
+ public void reset() {
+ printf ("R\n");
+ }
+
+ public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
+ super(in_device);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosDescent extends JComponent implements AltosFlightDisplay {
+ GridBagLayout layout;
+
+ public abstract class DescentStatus {
+ JLabel label;
+ JTextField value;
+ AltosLights lights;
+
+ abstract void show(AltosState state, int crc_errors);
+ void reset() {
+ value.setText("");
+ lights.set(false);
+ }
+
+ public DescentStatus (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ lights = new AltosLights();
+ c.gridx = 0; c.gridy = y;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(lights, c);
+ add(lights);
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.gridwidth = 3;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 4; c.gridy = y;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+
+ }
+ }
+
+ public abstract class DescentValue {
+ JLabel label;
+ JTextField value;
+
+ void reset() {
+ value.setText("");
+ }
+
+ abstract void show(AltosState state, int crc_errors);
+
+ void show(String format, double v) {
+ value.setText(String.format(format, v));
+ }
+
+ void show(String v) {
+ value.setText(v);
+ }
+
+ public DescentValue (GridBagLayout layout, int x, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = x + 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ add(label, c);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = x + 2; c.gridy = y;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ add(value, c);
+ }
+ }
+
+ public abstract class DescentDualValue {
+ JLabel label;
+ JTextField value1;
+ JTextField value2;
+
+ void reset() {
+ value1.setText("");
+ value2.setText("");
+ }
+
+ abstract void show(AltosState state, int crc_errors);
+ void show(String v1, String v2) {
+ value1.setText(v1);
+ value2.setText(v2);
+ }
+ void show(String f1, double v1, String f2, double v2) {
+ value1.setText(String.format(f1, v1));
+ value2.setText(String.format(f2, v2));
+ }
+
+ public DescentDualValue (GridBagLayout layout, int x, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = x + 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value1 = new JTextField(Altos.text_width);
+ value1.setFont(Altos.value_font);
+ value1.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = x + 2; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value1, c);
+ add(value1);
+
+ value2 = new JTextField(Altos.text_width);
+ value2.setFont(Altos.value_font);
+ value2.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = x + 4; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ c.gridwidth = 1;
+ layout.setConstraints(value2, c);
+ add(value2);
+ }
+ }
+
+ class Height extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m", state.height);
+ }
+ public Height (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Height");
+ }
+ }
+
+ Height height;
+
+ class Speed extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ double speed = state.speed;
+ if (!state.ascent)
+ speed = state.baro_speed;
+ show("%6.0f m/s", speed);
+ }
+ public Speed (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Speed");
+ }
+ }
+
+ Speed speed;
+
+ String pos(double p, String pos, String neg) {
+ String h = pos;
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%s %d° %9.6f", h, deg, min);
+ }
+
+ class Lat extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ show(pos(state.gps.lat,"N", "S"));
+ else
+ show("???");
+ }
+ public Lat (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Latitude");
+ }
+ }
+
+ Lat lat;
+
+ class Lon extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ show(pos(state.gps.lon,"W", "E"));
+ else
+ show("???");
+ }
+ public Lon (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Longitude");
+ }
+ }
+
+ Lon lon;
+
+ class Apogee extends DescentStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.drogue_sense));
+ lights.set(state.drogue_sense > 3.2);
+ }
+ public Apogee (GridBagLayout layout, int y) {
+ super(layout, y, "Apogee Igniter Voltage");
+ }
+ }
+
+ Apogee apogee;
+
+ class Main extends DescentStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.main_sense));
+ lights.set(state.main_sense > 3.2);
+ }
+ public Main (GridBagLayout layout, int y) {
+ super(layout, y, "Main Igniter Voltage");
+ }
+ }
+
+ Main main;
+
+ class Bearing extends DescentDualValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.from_pad != null) {
+ show( String.format("%3.0f°", state.from_pad.bearing),
+ state.from_pad.bearing_words(
+ AltosGreatCircle.BEARING_LONG));
+ } else {
+ show("???", "???");
+ }
+ }
+ public Bearing (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Bearing");
+ }
+ }
+
+ Bearing bearing;
+
+ class Range extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m", state.range);
+ }
+ public Range (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Range");
+ }
+ }
+
+ Range range;
+
+ class Elevation extends DescentValue {
+ void show (AltosState state, int crc_errors) {
+ show("%3.0f°", state.elevation);
+ }
+ public Elevation (GridBagLayout layout, int x, int y) {
+ super (layout, x, y, "Elevation");
+ }
+ }
+
+ Elevation elevation;
+
+ public void reset() {
+ lat.reset();
+ lon.reset();
+ height.reset();
+ speed.reset();
+ bearing.reset();
+ range.reset();
+ elevation.reset();
+ main.reset();
+ apogee.reset();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ height.show(state, crc_errors);
+ speed.show(state, crc_errors);
+ bearing.show(state, crc_errors);
+ range.show(state, crc_errors);
+ elevation.show(state, crc_errors);
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ main.show(state, crc_errors);
+ apogee.show(state, crc_errors);
+ }
+
+ public AltosDescent() {
+ layout = new GridBagLayout();
+
+ setLayout(layout);
+
+ /* Elements in descent display */
+ speed = new Speed(layout, 0, 0);
+ height = new Height(layout, 2, 0);
+ elevation = new Elevation(layout, 0, 1);
+ range = new Range(layout, 2, 1);
+ bearing = new Bearing(layout, 0, 2);
+ lat = new Lat(layout, 0, 3);
+ lon = new Lon(layout, 2, 3);
+
+ apogee = new Apogee(layout, 4);
+ main = new Main(layout, 5);
+ }
+}
--- /dev/null
+/*
+ * 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.util.*;
+import libaltosJNI.*;
+
+public class AltosDevice extends altos_device {
+
+ static public boolean initialized = false;
+ static public boolean loaded_library = false;
+
+ public static boolean load_library() {
+ if (!initialized) {
+ try {
+ System.loadLibrary("altos");
+ libaltos.altos_init();
+ loaded_library = true;
+ } catch (UnsatisfiedLinkError e) {
+ loaded_library = false;
+ }
+ initialized = true;
+ }
+ return loaded_library;
+ }
+
+ static int usb_vendor_altusmetrum() {
+ if (load_library())
+ return libaltosConstants.USB_VENDOR_ALTUSMETRUM;
+ return 0x000a;
+ }
+
+ static int usb_product_altusmetrum() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_ALTUSMETRUM;
+ return 0x000a;
+ }
+
+ static int usb_product_altusmetrum_min() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN;
+ return 0x000a;
+ }
+
+ static int usb_product_altusmetrum_max() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX;
+ return 0x000d;
+ }
+
+ static int usb_product_telemetrum() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_TELEMETRUM;
+ return 0x000b;
+ }
+
+ static int usb_product_teledongle() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_TELEDONGLE;
+ return 0x000c;
+ }
+
+ static int usb_product_teleterra() {
+ if (load_library())
+ return libaltosConstants.USB_PRODUCT_TELETERRA;
+ return 0x000d;
+ }
+
+ public final static int vendor_altusmetrum = usb_vendor_altusmetrum();
+ public final static int product_altusmetrum = usb_product_altusmetrum();
+ public final static int product_telemetrum = usb_product_telemetrum();
+ public final static int product_teledongle = usb_product_teledongle();
+ public final static int product_teleterra = usb_product_teleterra();
+ public final static int product_altusmetrum_min = usb_product_altusmetrum_min();
+ public final static int product_altusmetrum_max = usb_product_altusmetrum_max();
+
+
+ public final static int product_any = 0x10000;
+ public final static int product_basestation = 0x10000 + 1;
+
+ public String toString() {
+ String name = getName();
+ if (name == null)
+ name = "Altus Metrum";
+ return String.format("%-20.20s %4d %s",
+ getName(), getSerial(), getPath());
+ }
+
+ public String toShortString() {
+ String name = getName();
+ if (name == null)
+ name = "Altus Metrum";
+ return String.format("%s %d %s",
+ name, getSerial(), getPath());
+
+ }
+
+ public boolean isAltusMetrum() {
+ if (getVendor() != vendor_altusmetrum)
+ return false;
+ if (getProduct() < product_altusmetrum_min)
+ return false;
+ if (getProduct() > product_altusmetrum_max)
+ return false;
+ return true;
+ }
+
+ public boolean matchProduct(int want_product) {
+
+ if (!isAltusMetrum())
+ return false;
+
+ if (want_product == product_any)
+ return true;
+
+ if (want_product == product_basestation)
+ return matchProduct(product_teledongle) || matchProduct(product_teleterra);
+
+ int have_product = getProduct();
+
+ if (have_product == product_altusmetrum) /* old devices match any request */
+ return true;
+
+ if (want_product == have_product)
+ return true;
+
+ return false;
+ }
+
+ static AltosDevice[] list(int product) {
+ if (!load_library())
+ return null;
+
+ 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;
+ if (device.matchProduct(product))
+ 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
--- /dev/null
+/*
+ * 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.util.*;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import libaltosJNI.libaltos;
+import libaltosJNI.altos_device;
+import libaltosJNI.SWIGTYPE_p_altos_file;
+import libaltosJNI.SWIGTYPE_p_altos_list;
+
+public class AltosDeviceDialog extends JDialog implements ActionListener {
+
+ private static AltosDeviceDialog dialog;
+ private static AltosDevice value = null;
+ private JList list;
+
+ public static AltosDevice show (Component frameComp, int product) {
+
+ Frame frame = JOptionPane.getFrameForComponent(frameComp);
+ AltosDevice[] devices;
+ devices = AltosDevice.list(product);
+
+ if (devices != null && devices.length > 0) {
+ value = null;
+ dialog = new AltosDeviceDialog(frame, frameComp,
+ devices,
+ devices[0]);
+
+ dialog.setVisible(true);
+ return value;
+ } else {
+ /* check for missing altos JNI library, which
+ * will put up its own error dialog
+ */
+ if (AltosUI.load_library(frame)) {
+ JOptionPane.showMessageDialog(frame,
+ "No AltOS devices available",
+ "No AltOS devices",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ return null;
+ }
+ }
+
+ private AltosDeviceDialog (Frame frame, Component location,
+ AltosDevice[] devices,
+ AltosDevice initial) {
+ super(frame, "Device Selection", true);
+
+ value = null;
+
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(this);
+
+ final JButton selectButton = new JButton("Select");
+ selectButton.setActionCommand("select");
+ selectButton.addActionListener(this);
+ getRootPane().setDefaultButton(selectButton);
+
+ list = new JList(devices) {
+ //Subclass JList to workaround bug 4832765, which can cause the
+ //scroll pane to not let the user easily scroll up to the beginning
+ //of the list. An alternative would be to set the unitIncrement
+ //of the JScrollBar to a fixed value. You wouldn't get the nice
+ //aligned scrolling, but it should work.
+ public int getScrollableUnitIncrement(Rectangle visibleRect,
+ int orientation,
+ int direction) {
+ int row;
+ if (orientation == SwingConstants.VERTICAL &&
+ direction < 0 && (row = getFirstVisibleIndex()) != -1) {
+ Rectangle r = getCellBounds(row, row);
+ if ((r.y == visibleRect.y) && (row != 0)) {
+ Point loc = r.getLocation();
+ loc.y--;
+ int prevIndex = locationToIndex(loc);
+ Rectangle prevR = getCellBounds(prevIndex, prevIndex);
+
+ if (prevR == null || prevR.y >= r.y) {
+ return 0;
+ }
+ return prevR.height;
+ }
+ }
+ return super.getScrollableUnitIncrement(
+ visibleRect, orientation, direction);
+ }
+ };
+
+ list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
+ list.setVisibleRowCount(-1);
+ list.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ selectButton.doClick(); //emulate button click
+ }
+ }
+ });
+ JScrollPane listScroller = new JScrollPane(list);
+ listScroller.setPreferredSize(new Dimension(400, 80));
+ listScroller.setAlignmentX(LEFT_ALIGNMENT);
+
+ //Create a container so that we can add a title around
+ //the scroll pane. Can't add a title directly to the
+ //scroll pane because its background would be white.
+ //Lay out the label and scroll pane from top to bottom.
+ JPanel listPane = new JPanel();
+ listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
+
+ JLabel label = new JLabel("Select Device");
+ label.setLabelFor(list);
+ listPane.add(label);
+ listPane.add(Box.createRigidArea(new Dimension(0,5)));
+ listPane.add(listScroller);
+ listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+
+ //Lay out the buttons from left to right.
+ JPanel buttonPane = new JPanel();
+ buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
+ buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+ buttonPane.add(Box.createHorizontalGlue());
+ buttonPane.add(cancelButton);
+ buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
+ buttonPane.add(selectButton);
+
+ //Put everything together, using the content pane's BorderLayout.
+ Container contentPane = getContentPane();
+ contentPane.add(listPane, BorderLayout.CENTER);
+ contentPane.add(buttonPane, BorderLayout.PAGE_END);
+
+ //Initialize values.
+ list.setSelectedValue(initial, true);
+ pack();
+ setLocationRelativeTo(location);
+ }
+
+ //Handle clicks on the Set and Cancel buttons.
+ public void actionPerformed(ActionEvent e) {
+ if ("select".equals(e.getActionCommand()))
+ AltosDeviceDialog.value = (AltosDevice)(list.getSelectedValue());
+ AltosDeviceDialog.dialog.setVisible(false);
+ }
+
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosDisplayThread extends Thread {
+
+ Frame parent;
+ IdleThread idle_thread;
+ AltosVoice voice;
+ String name;
+ AltosFlightReader reader;
+ int crc_errors;
+ AltosFlightDisplay display;
+
+ synchronized void show(AltosState state, int crc_errors) {
+ if (state != null)
+ display.show(state, crc_errors);
+ }
+
+ class IdleThread extends Thread {
+
+ boolean started;
+ private AltosState state;
+ int reported_landing;
+ int report_interval;
+ long report_time;
+
+ public synchronized void report(boolean last) {
+ if (state == null)
+ return;
+
+ /* reset the landing count once we hear about a new flight */
+ if (state.state < Altos.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 (Altos.ao_flight_drogue <= state.state &&
+ state.state < Altos.ao_flight_landed &&
+ state.range >= 0)
+ {
+ voice.speak("Height %d, bearing %s %d, elevation %d, range %d.\n",
+ (int) (state.height + 0.5),
+ state.from_pad.bearing_words(
+ AltosGreatCircle.BEARING_VOICE),
+ (int) (state.from_pad.bearing + 0.5),
+ (int) (state.elevation + 0.5),
+ (int) (state.range + 0.5));
+ } else if (state.state > Altos.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.state >= Altos.ao_flight_drogue &&
+ (last ||
+ System.currentTimeMillis() - state.report_time >= 15000 ||
+ state.state == Altos.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.from_pad != 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;
+ if (state.state != Altos.ao_flight_landed) {
+ state.state = Altos.ao_flight_landed;
+ show(state, 0);
+ }
+ }
+ }
+
+ long now () {
+ return System.currentTimeMillis();
+ }
+
+ void set_report_time() {
+ report_time = now() + report_interval;
+ }
+
+ public void run () {
+ try {
+ for (;;) {
+ set_report_time();
+ for (;;) {
+ voice.drain();
+ synchronized (this) {
+ long sleep_time = report_time - now();
+ if (sleep_time <= 0)
+ break;
+ wait(sleep_time);
+ }
+ }
+ report(false);
+ }
+ } catch (InterruptedException ie) {
+ try {
+ voice.drain();
+ } catch (InterruptedException iie) { }
+ }
+ }
+
+ public synchronized void notice(AltosState new_state, boolean spoken) {
+ AltosState old_state = state;
+ state = new_state;
+ if (!started && state.state > Altos.ao_flight_pad) {
+ started = true;
+ start();
+ }
+
+ if (state.state < Altos.ao_flight_drogue)
+ report_interval = 10000;
+ else
+ report_interval = 20000;
+ if (old_state != null && old_state.state != state.state) {
+ report_time = now();
+ this.notify();
+ } else if (spoken)
+ set_report_time();
+ }
+
+ public IdleThread() {
+ state = null;
+ reported_landing = 0;
+ report_interval = 10000;
+ }
+ }
+
+ boolean tell(AltosState state, AltosState old_state) {
+ boolean ret = false;
+ if (old_state == null || old_state.state != state.state) {
+ voice.speak(state.data.state());
+ if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&
+ state.state > Altos.ao_flight_boost) {
+ voice.speak("max speed: %d meters per second.",
+ (int) (state.max_speed + 0.5));
+ ret = true;
+ } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&
+ state.state >= Altos.ao_flight_drogue) {
+ voice.speak("max height: %d meters.",
+ (int) (state.max_height + 0.5));
+ ret = true;
+ }
+ }
+ if (old_state == null || old_state.gps_ready != state.gps_ready) {
+ if (state.gps_ready) {
+ voice.speak("GPS ready");
+ ret = true;
+ }
+ else if (old_state != null) {
+ voice.speak("GPS lost");
+ ret = true;
+ }
+ }
+ old_state = state;
+ return ret;
+ }
+
+ public void run() {
+ boolean interrupted = false;
+ String line;
+ AltosState state = null;
+ AltosState old_state = null;
+ boolean told;
+
+ idle_thread = new IdleThread();
+
+ display.reset();
+ try {
+ for (;;) {
+ try {
+ AltosRecord record = reader.read();
+ if (record == null)
+ break;
+ old_state = state;
+ state = new AltosState(record, state);
+ reader.update(state);
+ show(state, crc_errors);
+ told = tell(state, old_state);
+ idle_thread.notice(state, told);
+ } catch (ParseException pp) {
+ System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
+ } catch (AltosCRCException ce) {
+ ++crc_errors;
+ show(state, crc_errors);
+ }
+ }
+ } catch (InterruptedException ee) {
+ interrupted = true;
+ } catch (IOException ie) {
+ JOptionPane.showMessageDialog(parent,
+ String.format("Error reading from \"%s\"", name),
+ "Telemetry Read Error",
+ JOptionPane.ERROR_MESSAGE);
+ } finally {
+ if (!interrupted)
+ idle_thread.report(true);
+ reader.close(interrupted);
+ idle_thread.interrupt();
+ try {
+ idle_thread.join();
+ } catch (InterruptedException ie) {}
+ }
+ }
+
+ public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
+ parent = in_parent;
+ voice = in_voice;
+ display = in_display;
+ reader = in_reader;
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+
+import libaltosJNI.*;
+
+public class AltosEepromDownload implements Runnable {
+
+ static final String[] state_names = {
+ "startup",
+ "idle",
+ "pad",
+ "boost",
+ "fast",
+ "coast",
+ "drogue",
+ "main",
+ "landed",
+ "invalid",
+ };
+
+ int[] ParseHex(String line) {
+ String[] tokens = line.split("\\s+");
+ int[] array = new int[tokens.length];
+
+ for (int i = 0; i < tokens.length; i++)
+ try {
+ array[i] = Integer.parseInt(tokens[i], 16);
+ } catch (NumberFormatException ne) {
+ return null;
+ }
+ return array;
+ }
+
+ int checksum(int[] line) {
+ int csum = 0x5a;
+ for (int i = 1; i < line.length; i++)
+ csum += line[i];
+ return csum & 0xff;
+ }
+
+ void FlushPending(FileWriter file, LinkedList<String> pending) throws IOException {
+ while (!pending.isEmpty()) {
+ file.write(pending.remove());
+ }
+ }
+
+ JFrame frame;
+ AltosDevice device;
+ AltosSerial serial_line;
+ boolean remote;
+ Thread eeprom_thread;
+ AltosEepromMonitor monitor;
+
+ void CaptureLog() throws IOException, InterruptedException, TimeoutException {
+ int serial = 0;
+ int block, state_block = 0;
+ int addr;
+ int flight = 0;
+ int year = 0, month = 0, day = 0;
+ int state = 0;
+ boolean done = false;
+ boolean want_file = false;
+ boolean any_valid;
+ FileWriter eeprom_file = null;
+ AltosFile eeprom_name;
+ LinkedList<String> eeprom_pending = new LinkedList<String>();
+
+ serial_line.printf("\nc s\nv\n");
+
+ /* Pull the serial number out of the version information */
+
+ for (;;) {
+ String line = serial_line.get_reply(5000);
+
+ if (line == null)
+ throw new TimeoutException();
+ if (line.startsWith("serial-number")) {
+ try {
+ serial = Integer.parseInt(line.substring(13).trim());
+ } catch (NumberFormatException ne) {
+ serial = 0;
+ }
+ }
+
+ eeprom_pending.add(String.format("%s\n", line));
+
+ /* signals the end of the version info */
+ if (line.startsWith("software-version"))
+ break;
+ }
+ if (serial == 0)
+ throw new IOException("no serial number found");
+
+ monitor.set_serial(serial);
+ /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
+
+ state = 0; state_block = 0;
+ for (block = 0; !done && block < 511; block++) {
+ serial_line.printf("e %x\n", block);
+ any_valid = false;
+ monitor.set_value(state_names[state], state, block - state_block);
+ for (addr = 0; addr < 0x100;) {
+ String line = serial_line.get_reply(5000);
+ if (line == null)
+ throw new TimeoutException();
+ int[] values = ParseHex(line);
+
+ if (values == null) {
+ System.out.printf("invalid line: %s\n", line);
+ continue;
+ } else if (values[0] != addr) {
+ System.out.printf("data address out of sync at 0x%x\n",
+ block * 256 + values[0]);
+ } else if (checksum(values) != 0) {
+ System.out.printf("invalid checksum at 0x%x\n",
+ block * 256 + values[0]);
+ } else {
+ any_valid = true;
+ int cmd = values[1];
+ int tick = values[3] + (values[4] << 8);
+ int a = values[5] + (values[6] << 8);
+ int b = values[7] + (values[8] << 8);
+
+ if (cmd == Altos.AO_LOG_FLIGHT) {
+ flight = b;
+ monitor.set_flight(flight);
+ }
+
+ /* Monitor state transitions to update display */
+ if (cmd == Altos.AO_LOG_STATE && a <= Altos.ao_flight_landed) {
+ if (a > Altos.ao_flight_pad)
+ want_file = true;
+ if (a > state)
+ state_block = block;
+ state = a;
+ }
+
+ if (cmd == Altos.AO_LOG_GPS_DATE) {
+ year = 2000 + (a & 0xff);
+ month = (a >> 8) & 0xff;
+ day = (b & 0xff);
+ want_file = true;
+ }
+
+ if (eeprom_file == null) {
+ if (serial != 0 && flight != 0 && want_file) {
+ if (year != 0 && month != 0 && day != 0)
+ eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom");
+ else
+ eeprom_name = new AltosFile(serial, flight, "eeprom");
+
+ monitor.set_file(eeprom_name.getName());
+ eeprom_file = new FileWriter(eeprom_name);
+ if (eeprom_file != null) {
+ FlushPending(eeprom_file, eeprom_pending);
+ eeprom_pending = null;
+ }
+ }
+ }
+
+ String log_line = String.format("%c %4x %4x %4x\n",
+ cmd, tick, a, b);
+ if (eeprom_file != null)
+ eeprom_file.write(log_line);
+ else
+ eeprom_pending.add(log_line);
+
+ if (cmd == Altos.AO_LOG_STATE && a == Altos.ao_flight_landed) {
+ done = true;
+ }
+ }
+ addr += 8;
+ }
+ if (!any_valid)
+ done = true;
+ }
+ if (eeprom_file == null) {
+ eeprom_name = new AltosFile(serial,flight,"eeprom");
+ eeprom_file = new FileWriter(eeprom_name);
+ if (eeprom_file != null) {
+ FlushPending(eeprom_file, eeprom_pending);
+ }
+ }
+ if (eeprom_file != null) {
+ eeprom_file.flush();
+ eeprom_file.close();
+ }
+ }
+
+ public void run () {
+ if (remote) {
+ serial_line.set_radio();
+ serial_line.printf("p\nE 0\n");
+ serial_line.flush_input();
+ }
+
+ monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
+ monitor.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ eeprom_thread.interrupt();
+ }
+ });
+ try {
+ CaptureLog();
+ } catch (IOException ee) {
+ JOptionPane.showMessageDialog(frame,
+ device.toShortString(),
+ ee.getLocalizedMessage(),
+ JOptionPane.ERROR_MESSAGE);
+ } catch (InterruptedException ie) {
+ } catch (TimeoutException te) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("Connection to \"%s\" failed",
+ device.toShortString()),
+ "Connection Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ if (remote)
+ serial_line.printf("~");
+ monitor.done();
+ serial_line.flush_output();
+ serial_line.close();
+ }
+
+ public AltosEepromDownload(JFrame given_frame) {
+ frame = given_frame;
+ device = AltosDeviceDialog.show(frame, AltosDevice.product_any);
+
+ remote = false;
+
+ if (device != null) {
+ try {
+ serial_line = new AltosSerial(device);
+ if (!device.matchProduct(AltosDevice.product_telemetrum))
+ remote = true;
+ eeprom_thread = new Thread(this);
+ eeprom_thread.start();
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("Cannot open device \"%s\"",
+ device.toShortString()),
+ "Cannot open target device",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (AltosSerialInUseException si) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("Device \"%s\" already in use",
+ device.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ee) {
+ JOptionPane.showMessageDialog(frame,
+ device.toShortString(),
+ ee.getLocalizedMessage(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/*
+ * AltosRecords with an index field so they can be sorted by tick while preserving
+ * the original ordering for elements with matching ticks
+ */
+class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> {
+
+ public int index;
+
+ public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
+ throws ParseException {
+ super(line);
+ if (prev_tick_valid) {
+ tick |= (prev_tick & ~0xffff);
+ if (tick < prev_tick) {
+ if (prev_tick - tick > 0x8000)
+ tick += 0x10000;
+ } else {
+ if (tick - prev_tick > 0x8000)
+ tick -= 0x10000;
+ }
+ }
+ index = in_index;
+ }
+
+ public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
+ super(in_cmd, in_tick, in_a, in_b);
+ index = in_index;
+ }
+
+ public int compareTo(AltosOrderedRecord o) {
+ int tick_diff = tick - o.tick;
+ if (tick_diff != 0)
+ return tick_diff;
+ return index - o.index;
+ }
+}
+
+public class AltosEepromIterable extends AltosRecordIterable {
+
+ static final int seen_flight = 1;
+ static final int seen_sensor = 2;
+ static final int seen_temp_volt = 4;
+ static final int seen_deploy = 8;
+ static final int seen_gps_time = 16;
+ static final int seen_gps_lat = 32;
+ static final int seen_gps_lon = 64;
+
+ static final int seen_basic = seen_flight|seen_sensor|seen_temp_volt|seen_deploy;
+
+ AltosEepromRecord flight_record;
+ AltosEepromRecord gps_date_record;
+
+ TreeSet<AltosOrderedRecord> records;
+
+ LinkedList<AltosRecord> list;
+
+ class EepromState {
+ int seen;
+ int n_pad_samples;
+ double ground_pres;
+ int gps_tick;
+ int boost_tick;
+
+ EepromState() {
+ seen = 0;
+ n_pad_samples = 0;
+ ground_pres = 0.0;
+ gps_tick = 0;
+ }
+ }
+
+ void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) {
+ state.tick = record.tick;
+ switch (record.cmd) {
+ case Altos.AO_LOG_FLIGHT:
+ eeprom.seen |= seen_flight;
+ state.ground_accel = record.a;
+ state.flight_accel = record.a;
+ state.flight = record.b;
+ eeprom.boost_tick = record.tick;
+ break;
+ case Altos.AO_LOG_SENSOR:
+ state.accel = record.a;
+ state.pres = record.b;
+ if (state.state < Altos.ao_flight_boost) {
+ eeprom.n_pad_samples++;
+ eeprom.ground_pres += state.pres;
+ state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
+ state.flight_pres = state.ground_pres;
+ } else {
+ state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
+ state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
+ state.flight_vel += (state.accel_plus_g - state.accel);
+ }
+ eeprom.seen |= seen_sensor;
+ break;
+ case Altos.AO_LOG_TEMP_VOLT:
+ state.temp = record.a;
+ state.batt = record.b;
+ eeprom.seen |= seen_temp_volt;
+ break;
+ case Altos.AO_LOG_DEPLOY:
+ state.drogue = record.a;
+ state.main = record.b;
+ eeprom.seen |= seen_deploy;
+ break;
+ case Altos.AO_LOG_STATE:
+ state.state = record.a;
+ break;
+ case Altos.AO_LOG_GPS_TIME:
+ eeprom.gps_tick = state.tick;
+ AltosGPS old = state.gps;
+ state.gps = new AltosGPS();
+
+ /* GPS date doesn't get repeated through the file */
+ if (old != null) {
+ state.gps.year = old.year;
+ state.gps.month = old.month;
+ state.gps.day = old.day;
+ }
+ state.gps.hour = (record.a & 0xff);
+ state.gps.minute = (record.a >> 8);
+ state.gps.second = (record.b & 0xff);
+
+ int flags = (record.b >> 8);
+ state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0;
+ state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0;
+ state.gps.date_valid = (flags & Altos.AO_GPS_DATE_VALID) != 0;
+ state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >>
+ Altos.AO_GPS_NUM_SAT_SHIFT;
+ break;
+ case Altos.AO_LOG_GPS_LAT:
+ int lat32 = record.a | (record.b << 16);
+ state.gps.lat = (double) lat32 / 1e7;
+ break;
+ case Altos.AO_LOG_GPS_LON:
+ int lon32 = record.a | (record.b << 16);
+ state.gps.lon = (double) lon32 / 1e7;
+ break;
+ case Altos.AO_LOG_GPS_ALT:
+ state.gps.alt = record.a;
+ break;
+ case Altos.AO_LOG_GPS_SAT:
+ if (state.tick == eeprom.gps_tick) {
+ int svid = record.a;
+ int c_n0 = record.b >> 8;
+ state.gps.add_sat(svid, c_n0);
+ }
+ break;
+ case Altos.AO_LOG_GPS_DATE:
+ state.gps.year = (record.a & 0xff) + 2000;
+ state.gps.month = record.a >> 8;
+ state.gps.day = record.b & 0xff;
+ break;
+
+ case Altos.AO_LOG_CONFIG_VERSION:
+ break;
+ case Altos.AO_LOG_MAIN_DEPLOY:
+ break;
+ case Altos.AO_LOG_APOGEE_DELAY:
+ break;
+ case Altos.AO_LOG_RADIO_CHANNEL:
+ break;
+ case Altos.AO_LOG_CALLSIGN:
+ state.callsign = record.data;
+ break;
+ case Altos.AO_LOG_ACCEL_CAL:
+ state.accel_plus_g = record.a;
+ state.accel_minus_g = record.b;
+ break;
+ case Altos.AO_LOG_RADIO_CAL:
+ break;
+ case Altos.AO_LOG_MANUFACTURER:
+ break;
+ case Altos.AO_LOG_PRODUCT:
+ break;
+ case Altos.AO_LOG_SERIAL_NUMBER:
+ state.serial = record.a;
+ break;
+ case Altos.AO_LOG_SOFTWARE_VERSION:
+ break;
+ }
+ }
+
+ LinkedList<AltosRecord> make_list() {
+ LinkedList<AltosRecord> list = new LinkedList<AltosRecord>();
+ Iterator<AltosOrderedRecord> iterator = records.iterator();
+ AltosOrderedRecord record = null;
+ AltosRecord state = new AltosRecord();
+ boolean last_reported = false;
+ EepromState eeprom = new EepromState();
+
+ state.state = Altos.ao_flight_pad;
+ state.accel_plus_g = 15758;
+ state.accel_minus_g = 16294;
+
+ /* Pull in static data from the flight and gps_date records */
+ if (flight_record != null)
+ update_state(state, flight_record, eeprom);
+ if (gps_date_record != null)
+ update_state(state, gps_date_record, eeprom);
+
+ while (iterator.hasNext()) {
+ record = iterator.next();
+ if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+ AltosRecord r = new AltosRecord(state);
+ r.time = (r.tick - eeprom.boost_tick) / 100.0;
+ list.add(r);
+ }
+ update_state(state, record, eeprom);
+ }
+ AltosRecord r = new AltosRecord(state);
+ r.time = (r.tick - eeprom.boost_tick) / 100.0;
+ list.add(r);
+ return list;
+ }
+
+ public Iterator<AltosRecord> iterator() {
+ if (list == null)
+ list = make_list();
+ return list.iterator();
+ }
+
+ public void write_comments(PrintStream out) {
+ Iterator<AltosOrderedRecord> iterator = records.iterator();
+ out.printf("# Comments\n");
+ while (iterator.hasNext()) {
+ AltosOrderedRecord record = iterator.next();
+ switch (record.cmd) {
+ case Altos.AO_LOG_CONFIG_VERSION:
+ out.printf("# Config version: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_MAIN_DEPLOY:
+ out.printf("# Main deploy: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_APOGEE_DELAY:
+ out.printf("# Apogee delay: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_RADIO_CHANNEL:
+ out.printf("# Radio channel: %s\n", record.a);
+ break;
+ case Altos.AO_LOG_CALLSIGN:
+ out.printf("# Callsign: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_ACCEL_CAL:
+ out.printf ("# Accel cal: %d %d\n", record.a, record.b);
+ break;
+ case Altos.AO_LOG_RADIO_CAL:
+ out.printf ("# Radio cal: %d\n", record.a);
+ break;
+ case Altos.AO_LOG_MANUFACTURER:
+ out.printf ("# Manufacturer: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_PRODUCT:
+ out.printf ("# Product: %s\n", record.data);
+ break;
+ case Altos.AO_LOG_SERIAL_NUMBER:
+ out.printf ("# Serial number: %d\n", record.a);
+ break;
+ case Altos.AO_LOG_SOFTWARE_VERSION:
+ out.printf ("# Software version: %s\n", record.data);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Given an AO_LOG_GPS_TIME record with correct time, and one
+ * missing time, rewrite the missing time values with the good
+ * ones, assuming that the difference between them is 'diff' seconds
+ */
+ void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
+
+ int diff = (bad.tick - good.tick + 50) / 100;
+
+ int hour = (good.a & 0xff);
+ int minute = (good.a >> 8);
+ int second = (good.b & 0xff);
+ int flags = (good.b >> 8);
+ int seconds = hour * 3600 + minute * 60 + second;
+
+ /* Make sure this looks like a good GPS value */
+ if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4)
+ flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT);
+ flags |= Altos.AO_GPS_RUNNING;
+ flags |= Altos.AO_GPS_VALID;
+
+ int new_seconds = seconds + diff;
+ if (new_seconds < 0)
+ new_seconds += 24 * 3600;
+ int new_second = (new_seconds % 60);
+ int new_minutes = (new_seconds / 60);
+ int new_minute = (new_minutes % 60);
+ int new_hours = (new_minutes / 60);
+ int new_hour = (new_hours % 24);
+
+ bad.a = new_hour + (new_minute << 8);
+ bad.b = new_second + (flags << 8);
+ }
+
+ /*
+ * Read the whole file, dumping records into a RB tree so
+ * we can enumerate them in time order -- the eeprom data
+ * are sometimes out of order with GPS data getting timestamps
+ * matching the first packet out of the GPS unit but not
+ * written until the final GPS packet has been received.
+ */
+ public AltosEepromIterable (FileInputStream input) {
+ records = new TreeSet<AltosOrderedRecord>();
+
+ AltosOrderedRecord last_gps_time = null;
+
+ int index = 0;
+ int prev_tick = 0;
+ boolean prev_tick_valid = false;
+ boolean missing_time = false;
+
+ try {
+ for (;;) {
+ String line = AltosRecord.gets(input);
+ if (line == null)
+ break;
+ AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
+ if (record == null)
+ break;
+ if (record.cmd == Altos.AO_LOG_INVALID)
+ continue;
+ prev_tick = record.tick;
+ if (record.cmd < Altos.AO_LOG_CONFIG_VERSION)
+ prev_tick_valid = true;
+ if (record.cmd == Altos.AO_LOG_FLIGHT) {
+ flight_record = record;
+ continue;
+ }
+
+ /* Two firmware bugs caused the loss of some GPS data.
+ * The flight date would never be recorded, and often
+ * the flight time would get overwritten by another
+ * record. Detect the loss of the GPS date and fix up the
+ * missing time records
+ */
+ if (record.cmd == Altos.AO_LOG_GPS_DATE) {
+ gps_date_record = record;
+ continue;
+ }
+
+ /* go back and fix up any missing time values */
+ if (record.cmd == Altos.AO_LOG_GPS_TIME) {
+ last_gps_time = record;
+ if (missing_time) {
+ Iterator<AltosOrderedRecord> iterator = records.iterator();
+ while (iterator.hasNext()) {
+ AltosOrderedRecord old = iterator.next();
+ if (old.cmd == Altos.AO_LOG_GPS_TIME &&
+ old.a == -1 && old.b == -1)
+ {
+ update_time(record, old);
+ }
+ }
+ missing_time = false;
+ }
+ }
+
+ if (record.cmd == Altos.AO_LOG_GPS_LAT) {
+ if (last_gps_time == null || last_gps_time.tick != record.tick) {
+ AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME,
+ record.tick,
+ -1, -1, index-1);
+ if (last_gps_time != null)
+ update_time(last_gps_time, add_gps_time);
+ else
+ missing_time = true;
+
+ records.add(add_gps_time);
+ record.index = index++;
+ }
+ }
+ records.add(record);
+
+ /* Bail after reading the 'landed' record; we're all done */
+ if (record.cmd == Altos.AO_LOG_STATE &&
+ record.a == Altos.ao_flight_landed)
+ break;
+ }
+ } catch (IOException io) {
+ } catch (ParseException pe) {
+ }
+ try {
+ input.close();
+ } catch (IOException ie) {
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosEepromMonitor extends JDialog {
+
+ Container pane;
+ Box box;
+ JLabel serial_label;
+ JLabel flight_label;
+ JLabel file_label;
+ JLabel serial_value;
+ JLabel flight_value;
+ JLabel file_value;
+ JButton cancel;
+ JProgressBar pbar;
+ int min_state, max_state;
+
+ public AltosEepromMonitor(JFrame owner, int in_min_state, int in_max_state) {
+ super (owner, "Download Flight Data", false);
+
+ GridBagConstraints c;
+ Insets il = new Insets(4,4,4,4);
+ Insets ir = new Insets(4,4,4,4);
+
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ serial_label = new JLabel("Serial:");
+ pane.add(serial_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 1; c.gridy = 0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ serial_value = new JLabel("");
+ pane.add(serial_value, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ flight_label = new JLabel("Flight:");
+ pane.add(flight_label, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.gridx = 1; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ flight_value = new JLabel("");
+ pane.add(flight_value, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 0; c.gridy = 2;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ file_label = new JLabel("File:");
+ pane.add(file_label, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.gridx = 1; c.gridy = 2;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ file_value = new JLabel("");
+ pane.add(file_value, c);
+
+ min_state = in_min_state;
+ max_state = in_max_state;
+ pbar = new JProgressBar();
+ pbar.setMinimum(0);
+ pbar.setMaximum((max_state - min_state) * 100);
+ pbar.setValue(0);
+ pbar.setString("startup");
+ pbar.setStringPainted(true);
+ pbar.setPreferredSize(new Dimension(600, 20));
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 3;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ib = new Insets(4,4,4,4);
+ c.insets = ib;
+ pane.add(pbar, c);
+
+
+ cancel = new JButton("Cancel");
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 4;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ic = new Insets(4,4,4,4);
+ c.insets = ic;
+ pane.add(cancel, c);
+
+ pack();
+ setLocationRelativeTo(owner);
+ setVisible(true);
+ }
+
+ public void addActionListener (ActionListener l) {
+ cancel.addActionListener(l);
+ }
+
+ public void set_value(String state_name, int in_state, int in_block) {
+ int block = in_block;
+ int state = in_state;
+
+ if (block > 100)
+ block = 100;
+ if (state < min_state) state = min_state;
+ if (state >= max_state) state = max_state - 1;
+ state -= min_state;
+
+ int pos = state * 100 + block;
+
+ pbar.setString(state_name);
+ pbar.setValue(pos);
+ }
+
+ public void set_serial(int serial) {
+ serial_value.setText(String.format("%d", serial));
+ }
+
+ public void set_flight(int flight) {
+ flight_value.setText(String.format("%d", flight));
+ }
+
+ public void set_file(String file) {
+ file_value.setText(String.format("%s", file));
+ }
+
+ public void done() {
+ setVisible(false);
+ dispose();
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosEepromRecord {
+ public int cmd;
+ public int tick;
+ public int a;
+ public int b;
+ public String data;
+ public boolean tick_valid;
+
+ public AltosEepromRecord (String line) {
+ tick_valid = false;
+ tick = 0;
+ a = 0;
+ b = 0;
+ data = null;
+ if (line == null) {
+ cmd = Altos.AO_LOG_INVALID;
+ data = "";
+ } else {
+ try {
+ String[] tokens = line.split("\\s+");
+
+ if (tokens[0].length() == 1) {
+ if (tokens.length != 4) {
+ cmd = Altos.AO_LOG_INVALID;
+ data = line;
+ } else {
+ cmd = tokens[0].codePointAt(0);
+ tick = Integer.parseInt(tokens[1],16);
+ tick_valid = true;
+ a = Integer.parseInt(tokens[2],16);
+ b = Integer.parseInt(tokens[3],16);
+ }
+ } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+ cmd = Altos.AO_LOG_CONFIG_VERSION;
+ data = tokens[2];
+ } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+ cmd = Altos.AO_LOG_MAIN_DEPLOY;
+ a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+ cmd = Altos.AO_LOG_APOGEE_DELAY;
+ a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+ cmd = Altos.AO_LOG_RADIO_CHANNEL;
+ a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("Callsign:")) {
+ cmd = Altos.AO_LOG_CALLSIGN;
+ data = tokens[1].replaceAll("\"","");
+ } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+ cmd = Altos.AO_LOG_ACCEL_CAL;
+ a = Integer.parseInt(tokens[3]);
+ b = Integer.parseInt(tokens[5]);
+ } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+ cmd = Altos.AO_LOG_RADIO_CAL;
+ a = Integer.parseInt(tokens[2]);
+ } else if (tokens[0].equals("manufacturer")) {
+ cmd = Altos.AO_LOG_MANUFACTURER;
+ data = tokens[1];
+ } else if (tokens[0].equals("product")) {
+ cmd = Altos.AO_LOG_PRODUCT;
+ data = tokens[1];
+ } else if (tokens[0].equals("serial-number")) {
+ cmd = Altos.AO_LOG_SERIAL_NUMBER;
+ a = Integer.parseInt(tokens[1]);
+ } else if (tokens[0].equals("software-version")) {
+ cmd = Altos.AO_LOG_SOFTWARE_VERSION;
+ data = tokens[1];
+ } else {
+ cmd = Altos.AO_LOG_INVALID;
+ data = line;
+ }
+ } catch (NumberFormatException ne) {
+ cmd = Altos.AO_LOG_INVALID;
+ data = line;
+ }
+ }
+ }
+
+ public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) {
+ tick_valid = true;
+ cmd = in_cmd;
+ tick = in_tick;
+ a = in_a;
+ b = in_b;
+ }
+}
--- /dev/null
+/*
+ * 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.File;
+import java.util.*;
+
+class AltosFile extends File {
+
+ public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
+ super (AltosPreferences.logdir(),
+ String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
+ year, month, day, serial, flight, extension));
+ }
+
+ public AltosFile(int serial, int flight, String extension) {
+ this(Calendar.getInstance().get(Calendar.YEAR),
+ Calendar.getInstance().get(Calendar.MONTH) + 1,
+ Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
+ serial,
+ flight,
+ extension);
+ }
+
+ public AltosFile(AltosTelemetry telem) {
+ this(telem.serial, telem.flight, "telem");
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlash {
+ File file;
+ FileInputStream input;
+ AltosHexfile image;
+ JFrame frame;
+ AltosDevice debug_dongle;
+ AltosDebug debug;
+ AltosRomconfig rom_config;
+ ActionListener listener;
+ boolean aborted;
+
+ static final byte MOV_direct_data = (byte) 0x75;
+ static final byte MOV_DPTR_data16 = (byte) 0x90;
+ static final byte MOV_A_data = (byte) 0x74;
+ static final byte MOVX_atDPTR_A = (byte) 0xf0;
+ static final byte MOVX_A_atDPTR = (byte) 0xe0;
+ static final byte INC_DPTR = (byte) 0xa3;
+ static final byte TRAP = (byte) 0xa5;
+
+ static final byte JB = (byte) 0x20;
+
+ static final byte MOV_A_direct = (byte) 0xe5;
+ static final byte MOV_direct1_direct2 = (byte) 0x85;
+ static final byte MOV_direct_A = (byte) 0xf5;
+ static final byte MOV_R0_data = (byte) (0x78 | 0);
+ static final byte MOV_R1_data = (byte) (0x78 | 1);
+ static final byte MOV_R2_data = (byte) (0x78 | 2);
+ static final byte MOV_R3_data = (byte) (0x78 | 3);
+ static final byte MOV_R4_data = (byte) (0x78 | 4);
+ static final byte MOV_R5_data = (byte) (0x78 | 5);
+ static final byte MOV_R6_data = (byte) (0x78 | 6);
+ static final byte MOV_R7_data = (byte) (0x78 | 7);
+ static final byte DJNZ_R0_rel = (byte) (0xd8 | 0);
+ static final byte DJNZ_R1_rel = (byte) (0xd8 | 1);
+ static final byte DJNZ_R2_rel = (byte) (0xd8 | 2);
+ static final byte DJNZ_R3_rel = (byte) (0xd8 | 3);
+ static final byte DJNZ_R4_rel = (byte) (0xd8 | 4);
+ static final byte DJNZ_R5_rel = (byte) (0xd8 | 5);
+ static final byte DJNZ_R6_rel = (byte) (0xd8 | 6);
+ static final byte DJNZ_R7_rel = (byte) (0xd8 | 7);
+
+ static final byte P1DIR = (byte) 0xFE;
+ static final byte P1 = (byte) 0x90;
+
+ /* flash controller */
+ static final byte FWT = (byte) 0xAB;
+ static final byte FADDRL = (byte) 0xAC;
+ static final byte FADDRH = (byte) 0xAD;
+ static final byte FCTL = (byte) 0xAE;
+ static final byte FCTL_BUSY = (byte) 0x80;
+ static final byte FCTL_BUSY_BIT = (byte) 7;
+ static final byte FCTL_SWBSY = (byte) 0x40;
+ static final byte FCTL_SWBSY_BIT = (byte) 6;
+ static final byte FCTL_CONTRD = (byte) 0x10;
+ static final byte FCTL_WRITE = (byte) 0x02;
+ static final byte FCTL_ERASE = (byte) 0x01;
+ static final byte FWDATA = (byte) 0xAF;
+
+ static final byte ACC = (byte) 0xE0;
+
+ /* offsets within the flash_page program */
+ static final int FLASH_ADDR_HIGH = 8;
+ static final int FLASH_ADDR_LOW = 11;
+ static final int RAM_ADDR_HIGH = 13;
+ static final int RAM_ADDR_LOW = 14;
+ static final int FLASH_WORDS_HIGH = 16;
+ static final int FLASH_WORDS_LOW = 18;
+ static final int FLASH_TIMING = 21;
+
+ /* sleep mode control */
+ static final int SLEEP = (byte) 0xbe;
+ static final int SLEEP_USB_EN = (byte) 0x80;
+ static final int SLEEP_XOSC_STB = (byte) 0x40;
+ static final int SLEEP_HFRC_STB = (byte) 0x20;
+ static final int SLEEP_RST_MASK = (byte) 0x18;
+ static final int SLEEP_RST_POWERON = (byte) 0x00;
+ static final int SLEEP_RST_EXTERNAL = (byte) 0x10;
+ static final int SLEEP_RST_WATCHDOG = (byte) 0x08;
+ static final int SLEEP_OSC_PD = (byte) 0x04;
+ static final int SLEEP_MODE_MASK = (byte) 0x03;
+ static final int SLEEP_MODE_PM0 = (byte) 0x00;
+ static final int SLEEP_MODE_PM1 = (byte) 0x01;
+ static final int SLEEP_MODE_PM2 = (byte) 0x02;
+ static final int SLEEP_MODE_PM3 = (byte) 0x03;
+
+ /* clock controller */
+ static final byte CLKCON = (byte) 0xC6;
+ static final byte CLKCON_OSC32K = (byte) 0x80;
+ static final byte CLKCON_OSC = (byte) 0x40;
+ static final byte CLKCON_TICKSPD = (byte) 0x38;
+ static final byte CLKCON_CLKSPD = (byte) 0x07;
+
+ static final byte[] flash_page_proto = {
+
+ MOV_direct_data, P1DIR, (byte) 0x02,
+ MOV_direct_data, P1, (byte) 0xFF,
+
+ MOV_direct_data, FADDRH, 0, /* FLASH_ADDR_HIGH */
+
+ MOV_direct_data, FADDRL, 0, /* FLASH_ADDR_LOW */
+
+ MOV_DPTR_data16, 0, 0, /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
+
+ MOV_R7_data, 0, /* FLASH_WORDS_HIGH */
+
+ MOV_R6_data, 0, /* FLASH_WORDS_LOW */
+
+
+ MOV_direct_data, FWT, 0x20, /* FLASH_TIMING */
+
+ MOV_direct_data, FCTL, FCTL_ERASE,
+/* eraseWaitLoop: */
+ MOV_A_direct, FCTL,
+ JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
+
+ MOV_direct_data, P1, (byte) 0xfd,
+
+ MOV_direct_data, FCTL, FCTL_WRITE,
+/* writeLoop: */
+ MOV_R5_data, 2,
+/* writeWordLoop: */
+ MOVX_A_atDPTR,
+ INC_DPTR,
+ MOV_direct_A, FWDATA,
+ DJNZ_R5_rel, (byte) 0xfa, /* writeWordLoop */
+/* writeWaitLoop: */
+ MOV_A_direct, FCTL,
+ JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb, /* writeWaitLoop */
+ DJNZ_R6_rel, (byte) 0xf1, /* writeLoop */
+ DJNZ_R7_rel, (byte) 0xef, /* writeLoop */
+
+ MOV_direct_data, P1DIR, (byte) 0x00,
+ MOV_direct_data, P1, (byte) 0xFF,
+ TRAP,
+ };
+
+ public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
+ int flash_word_addr = flash_addr >> 1;
+ int flash_word_count = ((byte_count + 1) >> 1);
+
+ byte[] flash_page = new byte[flash_page_proto.length];
+ for (int i = 0; i < flash_page.length; i++)
+ flash_page[i] = flash_page_proto[i];
+
+ flash_page[FLASH_ADDR_HIGH] = (byte) (flash_word_addr >> 8);
+ flash_page[FLASH_ADDR_LOW] = (byte) (flash_word_addr);
+ flash_page[RAM_ADDR_HIGH] = (byte) (ram_addr >> 8);
+ flash_page[RAM_ADDR_LOW] = (byte) (ram_addr);
+
+ byte flash_words_low = (byte) (flash_word_count);
+ byte flash_words_high = (byte) (flash_word_count >> 8);
+ /* the flashing code has a minor 'bug' */
+ if (flash_words_low != 0)
+ flash_words_high++;
+
+ flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
+ flash_page[FLASH_WORDS_LOW] = (byte) flash_words_low;
+ return flash_page;
+ }
+
+ static byte[] set_clkcon_fast = {
+ MOV_direct_data, CLKCON, 0x00
+ };
+
+ static byte[] get_sleep = {
+ MOV_A_direct, SLEEP
+ };
+
+ public void clock_init() throws IOException, InterruptedException {
+ debug.debug_instr(set_clkcon_fast);
+
+ byte status;
+ for (int times = 0; times < 20; times++) {
+ Thread.sleep(1);
+ status = debug.debug_instr(get_sleep);
+ if ((status & SLEEP_XOSC_STB) != 0)
+ return;
+ }
+ throw new IOException("Failed to initialize target clock");
+ }
+
+ void action(String s, int percent) {
+ if (listener != null && !aborted)
+ listener.actionPerformed(new ActionEvent(this,
+ percent,
+ s));
+ }
+
+ void action(int part, int total) {
+ int percent = 100 * part / total;
+ action(String.format("%d/%d (%d%%)",
+ part, total, percent),
+ percent);
+ }
+
+ void run(int pc) throws IOException, InterruptedException {
+ debug.set_pc(pc);
+ int set_pc = debug.get_pc();
+ if (pc != set_pc)
+ throw new IOException("Failed to set target program counter");
+ debug.resume();
+
+ for (int times = 0; times < 20; times++) {
+ byte status = debug.read_status();
+ if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
+ return;
+ }
+
+ throw new IOException("Failed to execute program on target");
+ }
+
+ public void flash() throws IOException, FileNotFoundException, InterruptedException {
+ if (!check_rom_config())
+ throw new IOException("Invalid rom config settings");
+ if (image.address + image.data.length > 0x8000)
+ throw new IOException(String.format("Flash image too long %d",
+ image.address +
+ image.data.length));
+ if ((image.address & 0x3ff) != 0)
+ throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
+ image.address));
+ int ram_address = 0xf000;
+ int flash_prog = 0xf400;
+
+ /*
+ * Store desired config values into image
+ */
+ rom_config.write(image);
+ /*
+ * Bring up the clock
+ */
+ clock_init();
+
+ int remain = image.data.length;
+ int flash_addr = image.address;
+ int image_start = 0;
+
+ action("start", 0);
+ action(0, image.data.length);
+ while (remain > 0 && !aborted) {
+ int this_time = remain;
+ if (this_time > 0x400)
+ this_time = 0x400;
+
+ /* write the data */
+ debug.write_memory(ram_address, image.data,
+ image_start, this_time);
+
+ /* write the flash program */
+ byte[] flash_page = make_flash_page(flash_addr,
+ ram_address,
+ this_time);
+ debug.write_memory(flash_prog, flash_page);
+
+ run(flash_prog);
+
+ byte[] check = debug.read_memory(flash_addr, this_time);
+ for (int i = 0; i < this_time; i++)
+ if (check[i] != image.data[image_start + i])
+ throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+ image.address + image_start + i,
+ check[i], image.data[image_start + i]));
+ remain -= this_time;
+ flash_addr += this_time;
+ image_start += this_time;
+
+ action(image.data.length - remain, image.data.length);
+ }
+ if (!aborted) {
+ action("done", 100);
+ debug.set_pc(image.address);
+ debug.resume();
+ }
+ debug.close();
+ }
+
+ public void abort() {
+ aborted = true;
+ debug.close();
+ }
+
+ public void addActionListener(ActionListener l) {
+ listener = l;
+ }
+
+ public boolean check_rom_config() {
+ if (rom_config == null)
+ rom_config = debug.romconfig();
+ return rom_config != null && rom_config.valid();
+ }
+
+ public void set_romconfig (AltosRomconfig romconfig) {
+ rom_config = romconfig;
+ }
+
+ public AltosRomconfig romconfig() {
+ if (!check_rom_config())
+ return null;
+ return rom_config;
+ }
+
+ public AltosFlash(File in_file, AltosDevice in_debug_dongle)
+ throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException {
+ file = in_file;
+ debug_dongle = in_debug_dongle;
+ debug = new AltosDebug(in_debug_dongle);
+ input = new FileInputStream(file);
+ image = new AltosHexfile(input);
+ if (!debug.check_connection()) {
+ debug.close();
+ throw new IOException("Debug port not connected");
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlashUI
+ extends JDialog
+ implements Runnable, ActionListener
+{
+ Container pane;
+ Box box;
+ JLabel serial_label;
+ JLabel serial_value;
+ JLabel file_label;
+ JLabel file_value;
+ JProgressBar pbar;
+ JButton cancel;
+
+ File file;
+ Thread thread;
+ JFrame frame;
+ AltosDevice debug_dongle;
+ AltosFlash flash;
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == cancel) {
+ abort();
+ dispose();
+ } else {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("done"))
+ ;
+ else if (cmd.equals("start")) {
+ setVisible(true);
+ } else {
+ pbar.setValue(e.getID());
+ pbar.setString(cmd);
+ }
+ }
+ }
+
+ public void run() {
+ try {
+ flash = new AltosFlash(file, debug_dongle);
+ flash.addActionListener(this);
+ AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame);
+
+ romconfig_ui.set(flash.romconfig());
+ AltosRomconfig romconfig = romconfig_ui.showDialog();
+
+ if (romconfig != null && romconfig.valid()) {
+ flash.set_romconfig(romconfig);
+ serial_value.setText(String.format("%d",
+ flash.romconfig().serial_number));
+ file_value.setText(file.toString());
+ setVisible(true);
+ flash.flash();
+ flash = null;
+ }
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(frame,
+ "Cannot open image",
+ file.toString(),
+ JOptionPane.ERROR_MESSAGE);
+ } catch (AltosSerialInUseException si) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("Device \"%s\" already in use",
+ debug_dongle.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException e) {
+ JOptionPane.showMessageDialog(frame,
+ e.getMessage(),
+ file.toString(),
+ JOptionPane.ERROR_MESSAGE);
+ } catch (InterruptedException ie) {
+ } finally {
+ abort();
+ }
+ dispose();
+ }
+
+ public void abort() {
+ if (flash != null)
+ flash.abort();
+ }
+
+ public void build_dialog() {
+ GridBagConstraints c;
+ Insets il = new Insets(4,4,4,4);
+ Insets ir = new Insets(4,4,4,4);
+
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ serial_label = new JLabel("Serial:");
+ pane.add(serial_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 1; c.gridy = 0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ serial_value = new JLabel("");
+ pane.add(serial_value, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 0; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ file_label = new JLabel("File:");
+ pane.add(file_label, c);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.gridx = 1; c.gridy = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ file_value = new JLabel("");
+ pane.add(file_value, c);
+
+ pbar = new JProgressBar();
+ pbar.setMinimum(0);
+ pbar.setMaximum(100);
+ pbar.setValue(0);
+ pbar.setString("");
+ pbar.setStringPainted(true);
+ pbar.setPreferredSize(new Dimension(600, 20));
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 2;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ib = new Insets(4,4,4,4);
+ c.insets = ib;
+ pane.add(pbar, c);
+
+ cancel = new JButton("Cancel");
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridx = 0; c.gridy = 3;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ Insets ic = new Insets(4,4,4,4);
+ c.insets = ic;
+ pane.add(cancel, c);
+ cancel.addActionListener(this);
+ pack();
+ setLocationRelativeTo(frame);
+ }
+
+ public AltosFlashUI(JFrame in_frame) {
+ super(in_frame, "Program Altusmetrum Device", false);
+
+ frame = in_frame;
+
+ build_dialog();
+
+ debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.product_any);
+
+ if (debug_dongle == null)
+ return;
+
+ JFileChooser hexfile_chooser = new JFileChooser();
+
+ File firmwaredir = AltosPreferences.firmwaredir();
+ if (firmwaredir != null)
+ hexfile_chooser.setCurrentDirectory(firmwaredir);
+
+ hexfile_chooser.setDialogTitle("Select Flash Image");
+ hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
+ int returnVal = hexfile_chooser.showOpenDialog(frame);
+
+ if (returnVal != JFileChooser.APPROVE_OPTION)
+ return;
+
+ file = hexfile_chooser.getSelectedFile();
+
+ if (file != null)
+ AltosPreferences.set_firmwaredir(file.getParentFile());
+
+ thread = new Thread(this);
+ thread.start();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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;
+
+public interface AltosFlightDisplay {
+ void reset();
+
+ void show(AltosState state, int crc_errors);
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlightInfoTableModel extends AbstractTableModel {
+ final static private String[] columnNames = {"Field", "Value"};
+
+ int rows;
+ int cols;
+ private String[][] data;
+
+ public int getColumnCount() { return cols; }
+ public int getRowCount() { return rows; }
+ public String getColumnName(int col) { return columnNames[col & 1]; }
+
+ public Object getValueAt(int row, int col) {
+ if (row >= rows || col >= cols)
+ return "";
+ return data[row][col];
+ }
+
+ int[] current_row;
+
+ public void reset() {
+ for (int i = 0; i < cols / 2; i++)
+ current_row[i] = 0;
+ }
+
+ public void clear() {
+ reset();
+ for (int c = 0; c < cols; c++)
+ for (int r = 0; r < rows; r++)
+ data[r][c] = "";
+ fireTableDataChanged();
+ }
+
+ public void addRow(int col, String name, String value) {
+ if (current_row[col] < rows) {
+ data[current_row[col]][col * 2] = name;
+ data[current_row[col]][col * 2 + 1] = value;
+ }
+ current_row[col]++;
+ }
+
+ public void finish() {
+ for (int c = 0; c < cols / 2; c++)
+ while (current_row[c] < rows)
+ addRow(c, "", "");
+ fireTableDataChanged();
+ }
+
+ public AltosFlightInfoTableModel (int in_rows, int in_cols) {
+ rows = in_rows;
+ cols = in_cols * 2;
+ data = new String[rows][cols];
+ current_row = new int[in_cols];
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.io.*;
+
+public class AltosFlightReader {
+ String name;
+
+ int serial;
+
+ void init() { }
+
+ AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
+
+ void close(boolean interrupted) { }
+
+ void set_channel(int channel) { }
+
+ void update(AltosState state) throws InterruptedException { }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
+ GridBagLayout layout;
+
+ public class FlightValue {
+ JLabel label;
+ JTextField value;
+
+ void show(AltosState state, int crc_errors) {}
+
+ void reset() {
+ value.setText("");
+ }
+ public FlightValue (GridBagLayout layout, int x, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(5, 5, 5, 5);
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.status_font);
+ label.setHorizontalAlignment(SwingConstants.CENTER);
+ c.gridx = x; c.gridy = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField("");
+ value.setFont(Altos.status_font);
+ value.setHorizontalAlignment(SwingConstants.CENTER);
+ c.gridx = x; c.gridy = 1;
+ layout.setConstraints(value, c);
+ add(value);
+ }
+ }
+
+ class Call extends FlightValue {
+ void show(AltosState state, int crc_errors) {
+ value.setText(state.data.callsign);
+ }
+ public Call (GridBagLayout layout, int x) {
+ super (layout, x, "Callsign");
+ }
+ }
+
+ Call call;
+
+ class Serial extends FlightValue {
+ void show(AltosState state, int crc_errors) {
+ value.setText(String.format("%d", state.data.serial));
+ }
+ public Serial (GridBagLayout layout, int x) {
+ super (layout, x, "Serial");
+ }
+ }
+
+ Serial serial;
+
+ class Flight extends FlightValue {
+ void show(AltosState state, int crc_errors) {
+ value.setText(String.format("%d", state.data.flight));
+ }
+ public Flight (GridBagLayout layout, int x) {
+ super (layout, x, "Flight");
+ }
+ }
+
+ Flight flight;
+
+ class FlightState extends FlightValue {
+ void show(AltosState state, int crc_errors) {
+ value.setText(state.data.state());
+ }
+ public FlightState (GridBagLayout layout, int x) {
+ super (layout, x, "State");
+ }
+ }
+
+ FlightState flight_state;
+
+ class RSSI extends FlightValue {
+ void show(AltosState state, int crc_errors) {
+ value.setText(String.format("%d", state.data.rssi));
+ }
+ public RSSI (GridBagLayout layout, int x) {
+ super (layout, x, "RSSI (dBm)");
+ }
+ }
+
+ RSSI rssi;
+
+ public void reset () {
+ call.reset();
+ serial.reset();
+ flight.reset();
+ flight_state.reset();
+ rssi.reset();
+ }
+
+ public void show (AltosState state, int crc_errors) {
+ call.show(state, crc_errors);
+ serial.show(state, crc_errors);
+ flight.show(state, crc_errors);
+ flight_state.show(state, crc_errors);
+ rssi.show(state, crc_errors);
+ }
+
+ public int height() {
+ Dimension d = layout.preferredLayoutSize(this);
+ return d.height;
+ }
+
+ public AltosFlightStatus() {
+ layout = new GridBagLayout();
+
+ setLayout(layout);
+
+ call = new Call(layout, 0);
+ serial = new Serial(layout, 1);
+ flight = new Flight(layout, 2);
+ flight_state = new FlightState(layout, 3);
+ rssi = new RSSI(layout, 4);
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlightStatusTableModel extends AbstractTableModel {
+ private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
+ private Object[] data = { 0, "idle", 0, 0 };
+
+ public int getColumnCount() { return columnNames.length; }
+ public int getRowCount() { return 2; }
+ public Object getValueAt(int row, int col) {
+ if (row == 0)
+ return columnNames[col];
+ return data[col];
+ }
+
+ public void setValueAt(Object value, int col) {
+ data[col] = value;
+ fireTableCellUpdated(1, col);
+ }
+
+ public void setValueAt(Object value, int row, int col) {
+ setValueAt(value, col);
+ }
+
+ public void set(AltosState state) {
+ setValueAt(String.format("%1.0f", state.height), 0);
+ setValueAt(state.data.state(), 1);
+ setValueAt(state.data.rssi, 2);
+ double speed = state.baro_speed;
+ if (state.ascent)
+ speed = state.speed;
+ setValueAt(String.format("%1.0f", speed), 3);
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
+ String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
+ Object[][] statusData = { { "0", "pad", "-50", "0" } };
+
+ AltosVoice voice;
+ AltosFlightReader reader;
+ AltosDisplayThread thread;
+
+ JTabbedPane pane;
+
+ AltosPad pad;
+ AltosAscent ascent;
+ AltosDescent descent;
+ AltosLanded landed;
+ AltosSiteMap sitemap;
+
+ private AltosFlightStatus flightStatus;
+ private AltosInfoTable flightInfo;
+
+ static final int tab_pad = 1;
+ static final int tab_ascent = 2;
+ static final int tab_descent = 3;
+ static final int tab_landed = 4;
+
+ int cur_tab = 0;
+
+ boolean exit_on_close = false;
+
+ int which_tab(AltosState state) {
+ if (state.state < Altos.ao_flight_boost)
+ return tab_pad;
+ if (state.state <= Altos.ao_flight_coast)
+ return tab_ascent;
+ if (state.state <= Altos.ao_flight_main)
+ return tab_descent;
+ return tab_landed;
+ }
+
+ void stop_display() {
+ if (thread != null && thread.isAlive()) {
+ thread.interrupt();
+ try {
+ thread.join();
+ } catch (InterruptedException ie) {}
+ }
+ thread = null;
+ }
+
+ void disconnect() {
+ stop_display();
+ }
+
+ public void reset() {
+ pad.reset();
+ ascent.reset();
+ descent.reset();
+ landed.reset();
+ flightInfo.clear();
+ sitemap.reset();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ int tab = which_tab(state);
+ pad.show(state, crc_errors);
+ ascent.show(state, crc_errors);
+ descent.show(state, crc_errors);
+ landed.show(state, crc_errors);
+ if (tab != cur_tab) {
+ switch (tab) {
+ case tab_pad:
+ pane.setSelectedComponent(pad);
+ break;
+ case tab_ascent:
+ pane.setSelectedComponent(ascent);
+ break;
+ case tab_descent:
+ pane.setSelectedComponent(descent);
+ break;
+ case tab_landed:
+ pane.setSelectedComponent(landed);
+ }
+ cur_tab = tab;
+ }
+ flightStatus.show(state, crc_errors);
+ flightInfo.show(state, crc_errors);
+ sitemap.show(state, crc_errors);
+ }
+
+ public void set_exit_on_close() {
+ exit_on_close = true;
+ }
+
+ Container bag;
+ JComboBox channels;
+
+ public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) {
+ AltosPreferences.init(this);
+
+ voice = in_voice;
+ reader = in_reader;
+
+ bag = getContentPane();
+ bag.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
+ if (imgURL != null)
+ setIconImage(new ImageIcon(imgURL).getImage());
+
+ setTitle(String.format("AltOS %s", reader.name));
+
+ /* Stick channel selector at top of table for telemetry monitoring */
+ if (serial >= 0) {
+ // Channel menu
+ channels = new AltosChannelMenu(AltosPreferences.channel(serial));
+ channels.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ int channel = channels.getSelectedIndex();
+ reader.set_channel(channel);
+ }
+ });
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.WEST;
+ bag.add (channels, c);
+ }
+
+ /* Flight status is always visible */
+ flightStatus = new AltosFlightStatus();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ bag.add(flightStatus, c);
+
+ /* The rest of the window uses a tabbed pane to
+ * show one of the alternate data views
+ */
+ pane = new JTabbedPane();
+
+ pad = new AltosPad();
+ pane.add("Launch Pad", pad);
+
+ ascent = new AltosAscent();
+ pane.add("Ascent", ascent);
+
+ descent = new AltosDescent();
+ pane.add("Descent", descent);
+
+ landed = new AltosLanded();
+ pane.add("Landed", landed);
+
+ flightInfo = new AltosInfoTable();
+ pane.add("Table", new JScrollPane(flightInfo));
+
+ sitemap = new AltosSiteMap();
+ pane.add("Site Map", sitemap);
+
+ /* Make the tabbed pane use the rest of the window space */
+ c.gridx = 0;
+ c.gridy = 2;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ c.weighty = 1;
+ bag.add(pane, c);
+
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ disconnect();
+ setVisible(false);
+ dispose();
+ if (exit_on_close)
+ System.exit(0);
+ }
+ });
+
+ pack();
+ setVisible(true);
+
+ thread = new AltosDisplayThread(this, voice, this, reader);
+
+ thread.start();
+ }
+
+ public AltosFlightUI (AltosVoice in_voice, AltosFlightReader in_reader) {
+ this(in_voice, in_reader, -1);
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+
+public class AltosGPS {
+ public class AltosGPSSat {
+ int svid;
+ int c_n0;
+ }
+
+ int nsat;
+ boolean locked;
+ boolean connected;
+ boolean date_valid;
+ double lat; /* degrees (+N -S) */
+ double lon; /* degrees (+E -W) */
+ int alt; /* m */
+ int year;
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+
+ int gps_extended; /* has extra data */
+ double ground_speed; /* m/s */
+ int course; /* degrees */
+ double climb_rate; /* m/s */
+ double hdop; /* unitless? */
+ int h_error; /* m */
+ int v_error; /* m */
+
+ AltosGPSSat[] cc_gps_sat; /* tracking data */
+
+ void ParseGPSDate(String date) throws ParseException {
+ String[] ymd = date.split("-");
+ if (ymd.length != 3)
+ throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0);
+ year = AltosParse.parse_int(ymd[0]);
+ month = AltosParse.parse_int(ymd[1]);
+ day = AltosParse.parse_int(ymd[2]);
+ }
+
+ void ParseGPSTime(String time) throws ParseException {
+ String[] hms = time.split(":");
+ if (hms.length != 3)
+ throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0);
+ hour = AltosParse.parse_int(hms[0]);
+ minute = AltosParse.parse_int(hms[1]);
+ second = AltosParse.parse_int(hms[2]);
+ }
+
+ void ClearGPSTime() {
+ year = month = day = 0;
+ hour = minute = second = 0;
+ }
+
+ public AltosGPS(String[] words, int i, int version) throws ParseException {
+ AltosParse.word(words[i++], "GPS");
+ nsat = AltosParse.parse_int(words[i++]);
+ AltosParse.word(words[i++], "sat");
+
+ connected = false;
+ locked = false;
+ lat = lon = 0;
+ alt = 0;
+ ClearGPSTime();
+ if ((words[i]).equals("unlocked")) {
+ connected = true;
+ i++;
+ } else if ((words[i]).equals("not-connected")) {
+ i++;
+ } else if (words.length >= 40) {
+ locked = true;
+ connected = true;
+
+ if (version > 1)
+ ParseGPSDate(words[i++]);
+ else
+ year = month = day = 0;
+ ParseGPSTime(words[i++]);
+ lat = AltosParse.parse_coord(words[i++]);
+ lon = AltosParse.parse_coord(words[i++]);
+ alt = AltosParse.parse_int(words[i++]);
+ if (version > 1 || (i < words.length && !words[i].equals("SAT"))) {
+ ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)"));
+ course = AltosParse.parse_int(words[i++]);
+ climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)"));
+ hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)"));
+ h_error = AltosParse.parse_int(words[i++]);
+ v_error = AltosParse.parse_int(words[i++]);
+ }
+ } else {
+ i++;
+ }
+ if (i < words.length) {
+ AltosParse.word(words[i++], "SAT");
+ int tracking_channels = 0;
+ if (words[i].equals("not-connected"))
+ tracking_channels = 0;
+ else
+ tracking_channels = AltosParse.parse_int(words[i]);
+ i++;
+ cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels];
+ for (int chan = 0; chan < tracking_channels; chan++) {
+ cc_gps_sat[chan] = new AltosGPS.AltosGPSSat();
+ cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]);
+ /* Older versions included SiRF status bits */
+ if (version < 2)
+ i++;
+ cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]);
+ }
+ } else
+ cc_gps_sat = new AltosGPS.AltosGPSSat[0];
+ }
+
+ public void set_latitude(int in_lat) {
+ lat = in_lat / 10.0e7;
+ }
+
+ public void set_longitude(int in_lon) {
+ lon = in_lon / 10.0e7;
+ }
+
+ public void set_time(int hour, int minute, int second) {
+ hour = hour;
+ minute = minute;
+ second = second;
+ }
+
+ public void set_date(int year, int month, int day) {
+ year = year;
+ month = month;
+ day = day;
+ }
+
+ public void set_flags(int flags) {
+ flags = flags;
+ }
+
+ public void set_altitude(int altitude) {
+ altitude = altitude;
+ }
+
+ public void add_sat(int svid, int c_n0) {
+ if (cc_gps_sat == null) {
+ cc_gps_sat = new AltosGPS.AltosGPSSat[1];
+ } else {
+ AltosGPSSat[] new_gps_sat = new AltosGPS.AltosGPSSat[cc_gps_sat.length + 1];
+ for (int i = 0; i < cc_gps_sat.length; i++)
+ new_gps_sat[i] = cc_gps_sat[i];
+ cc_gps_sat = new_gps_sat;
+ }
+ AltosGPS.AltosGPSSat sat = new AltosGPS.AltosGPSSat();
+ sat.svid = svid;
+ sat.c_n0 = c_n0;
+ cc_gps_sat[cc_gps_sat.length - 1] = sat;
+ }
+
+ public AltosGPS() {
+ ClearGPSTime();
+ cc_gps_sat = null;
+ }
+
+ public AltosGPS(AltosGPS old) {
+ nsat = old.nsat;
+ locked = old.locked;
+ connected = old.connected;
+ date_valid = old.date_valid;
+ lat = old.lat; /* degrees (+N -S) */
+ lon = old.lon; /* degrees (+E -W) */
+ alt = old.alt; /* m */
+ year = old.year;
+ month = old.month;
+ day = old.day;
+ hour = old.hour;
+ minute = old.minute;
+ second = old.second;
+
+ gps_extended = old.gps_extended; /* has extra data */
+ ground_speed = old.ground_speed; /* m/s */
+ course = old.course; /* degrees */
+ climb_rate = old.climb_rate; /* m/s */
+ hdop = old.hdop; /* unitless? */
+ h_error = old.h_error; /* m */
+ v_error = old.v_error; /* m */
+
+ if (old.cc_gps_sat != null) {
+ cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length];
+ for (int i = 0; i < old.cc_gps_sat.length; i++) {
+ cc_gps_sat[i] = new AltosGPSSat();
+ cc_gps_sat[i].svid = old.cc_gps_sat[i].svid;
+ cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0;
+ }
+ }
+ }
+}
--- /dev/null
+
+// Copyright (c) 2010 Anthony Towns
+// GPL v2 or later
+
+package altosui;
+
+import java.io.*;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.ChartUtilities;
+
+abstract class AltosGraph {
+ public String filename;
+ public abstract void addData(AltosDataPoint d);
+ public abstract JFreeChart createChart();
+ public void toPNG() throws java.io.IOException { toPNG(300, 500); }
+ public void toPNG(int width, int height)
+ throws java.io.IOException
+ {
+ File pngout = new File(filename);
+ JFreeChart chart = createChart();
+ ChartUtilities.saveChartAsPNG(pngout, chart, width, height);
+ System.out.println("Created " + filename);
+ }
+}
--- /dev/null
+
+// Copyright (c) 2010 Anthony Towns
+// GPL v2 or later
+
+package altosui;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.jfree.chart.ChartUtilities;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.AxisLocation;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.labels.StandardXYToolTipGenerator;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.plot.ValueMarker;
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.TextAnchor;
+
+class AltosGraphTime extends AltosGraph {
+ static interface Element {
+ void attachGraph(AltosGraphTime g);
+ void gotTimeData(double time, AltosDataPoint d);
+ void addToPlot(AltosGraphTime g, XYPlot plot);
+ }
+
+ static class TimeAxis implements Element {
+ private int axis;
+ private Color color;
+ private String label;
+ private AxisLocation locn;
+ private double min_y = Double.NaN;
+
+ public TimeAxis(int axis, String label, Color color, AxisLocation locn)
+ {
+ this.axis = axis;
+ this.color = color;
+ this.label = label;
+ this.locn = locn;
+ }
+
+ public void setLowerBound(double min_y) {
+ this.min_y = min_y;
+ }
+
+ public void attachGraph(AltosGraphTime g) { return; }
+ public void gotTimeData(double time, AltosDataPoint d) { return; }
+
+ public void addToPlot(AltosGraphTime g, XYPlot plot) {
+ NumberAxis numAxis = new NumberAxis(label);
+ if (!Double.isNaN(min_y))
+ numAxis.setLowerBound(min_y);
+ plot.setRangeAxis(axis, numAxis);
+ plot.setRangeAxisLocation(axis, locn);
+ numAxis.setLabelPaint(color);
+ numAxis.setTickLabelPaint(color);
+ numAxis.setAutoRangeIncludesZero(false);
+ }
+ }
+
+ abstract static class TimeSeries implements Element {
+ protected XYSeries series;
+ private String axisName;
+ private Color color;
+
+ public TimeSeries(String axisName, String label, Color color) {
+ this.series = new XYSeries(label);
+ this.axisName = axisName;
+ this.color = color;
+ }
+
+ public void attachGraph(AltosGraphTime g) {
+ g.setAxis(this, axisName, color);
+ }
+ abstract public void gotTimeData(double time, AltosDataPoint d);
+
+ public void addToPlot(AltosGraphTime g, XYPlot plot) {
+ XYSeriesCollection dataset = new XYSeriesCollection();
+ dataset.addSeries(this.series);
+
+ XYItemRenderer renderer = new StandardXYItemRenderer();
+ renderer.setSeriesPaint(0, color);
+
+ int dataNum = g.getDataNum(this);
+ int axisNum = g.getAxisNum(this);
+
+ plot.setDataset(dataNum, dataset);
+ plot.mapDatasetToRangeAxis(dataNum, axisNum);
+ plot.setRenderer(dataNum, renderer);
+ }
+ }
+
+ static class StateMarker implements Element {
+ private double val = Double.NaN;
+ private String name;
+ private int state;
+
+ StateMarker(int state, String name) {
+ this.state = state;
+ this.name = name;
+ }
+
+ public void attachGraph(AltosGraphTime g) { return; }
+ public void gotTimeData(double time, AltosDataPoint d) {
+ if (Double.isNaN(val) || time < val) {
+ if (d.state() == state) {
+ val = time;
+ }
+ }
+ }
+
+ public void addToPlot(AltosGraphTime g, XYPlot plot) {
+ if (Double.isNaN(val))
+ return;
+
+ ValueMarker m = new ValueMarker(val);
+ m.setLabel(name);
+ m.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
+ m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
+ plot.addDomainMarker(m);
+ }
+ }
+
+ private String callsign = null;
+ private Integer serial = null;
+ private Integer flight = null;
+
+ private String title;
+ private ArrayList<Element> elements;
+ private HashMap<String,Integer> axes;
+ private HashMap<Element,Integer> datasets;
+ private ArrayList<Integer> datasetAxis;
+
+ public AltosGraphTime(String title) {
+ this.filename = title.toLowerCase().replaceAll("[^a-z0-9]","_")+".png";
+ this.title = title;
+ this.elements = new ArrayList<Element>();
+ this.axes = new HashMap<String,Integer>();
+ this.datasets = new HashMap<Element,Integer>();
+ this.datasetAxis = new ArrayList<Integer>();
+ }
+
+ public AltosGraphTime addElement(Element e) {
+ e.attachGraph(this);
+ elements.add(e);
+ return this;
+ }
+
+ public void setAxis(Element ds, String axisName, Color color) {
+ Integer axisNum = axes.get(axisName);
+ int dsNum = datasetAxis.size();
+ if (axisNum == null) {
+ axisNum = newAxis(axisName, color);
+ }
+ datasets.put(ds, dsNum);
+ datasetAxis.add(axisNum);
+ }
+
+ public int getAxisNum(Element ds) {
+ return datasetAxis.get( datasets.get(ds) ).intValue();
+ }
+ public int getDataNum(Element ds) {
+ return datasets.get(ds).intValue();
+ }
+
+ private Integer newAxis(String name, Color color) {
+ int cnt = axes.size();
+ AxisLocation locn = AxisLocation.BOTTOM_OR_LEFT;
+ if (cnt > 0) {
+ locn = AxisLocation.TOP_OR_RIGHT;
+ }
+ Integer res = new Integer(cnt);
+ axes.put(name, res);
+ this.addElement(new TimeAxis(cnt, name, color, locn));
+ return res;
+ }
+
+ public void addData(AltosDataPoint d) {
+ double time = d.time();
+ for (Element e : elements) {
+ e.gotTimeData(time, d);
+ }
+ if (callsign == null) callsign = d.callsign();
+ if (serial == null) serial = new Integer(d.serial());
+ if (flight == null) flight = new Integer(d.flight());
+ }
+
+ public JFreeChart createChart() {
+ NumberAxis xAxis = new NumberAxis("Time (s)");
+ xAxis.setAutoRangeIncludesZero(false);
+ XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
+ XYPlot plot = new XYPlot();
+ plot.setDomainAxis(xAxis);
+ plot.setRenderer(renderer);
+ plot.setOrientation(PlotOrientation.VERTICAL);
+
+ if (serial != null && flight != null) {
+ title = serial + "/" + flight + ": " + title;
+ }
+ if (callsign != null) {
+ title = callsign + " - " + title;
+ }
+
+ renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
+ JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
+ plot, true);
+ ChartUtilities.applyCurrentTheme(chart);
+
+ plot.setDomainPannable(true);
+ plot.setRangePannable(true);
+
+ for (Element e : elements) {
+ e.addToPlot(this, plot);
+ }
+
+ return chart;
+ }
+
+ public void toPNG() throws java.io.IOException {
+ if (axes.size() > 1) {
+ toPNG(800, 500);
+ } else {
+ toPNG(300, 500);
+ }
+ }
+}
--- /dev/null
+
+// Copyright (c) 2010 Anthony Towns
+// GPL v2 or later
+
+package altosui;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import javax.swing.JFrame;
+import java.awt.Color;
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.ChartUtilities;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.AxisLocation;
+import org.jfree.ui.ApplicationFrame;
+import org.jfree.ui.RefineryUtilities;
+
+public class AltosGraphUI extends JFrame
+{
+ static final private Color red = new Color(194,31,31);
+ static final private Color green = new Color(31,194,31);
+ static final private Color blue = new Color(31,31,194);
+ static final private Color black = new Color(31,31,31);
+
+ static private class OverallGraphs {
+ AltosGraphTime.Element height =
+ new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ series.add(time, d.height());
+ }
+ };
+
+ AltosGraphTime.Element speed =
+ new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ if (d.state() < Altos.ao_flight_drogue) {
+ series.add(time, d.accel_speed());
+ } else {
+ series.add(time, d.baro_speed());
+ }
+ }
+ };
+
+ AltosGraphTime.Element acceleration =
+ new AltosGraphTime.TimeSeries("Acceleration (m/s\u00B2)",
+ "Axial Acceleration", blue)
+ {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ series.add(time, d.acceleration());
+ }
+ };
+
+ AltosGraphTime.Element temperature =
+ new AltosGraphTime.TimeSeries("Temperature (\u00B0C)",
+ "Board temperature", red)
+ {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ series.add(time, d.temperature());
+ }
+ };
+
+ AltosGraphTime.Element drogue_voltage =
+ new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", blue)
+ {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ series.add(time, d.drogue_voltage());
+ }
+ };
+
+ AltosGraphTime.Element main_voltage =
+ new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", green)
+ {
+ public void gotTimeData(double time, AltosDataPoint d) {
+ series.add(time, d.main_voltage());
+ }
+ };
+
+ AltosGraphTime.Element e_pad = new AltosGraphTime.StateMarker(Altos.ao_flight_pad, "Pad");
+ AltosGraphTime.Element e_boost = new AltosGraphTime.StateMarker(Altos.ao_flight_boost, "Boost");
+ AltosGraphTime.Element e_fast = new AltosGraphTime.StateMarker(Altos.ao_flight_fast, "Fast");
+ AltosGraphTime.Element e_coast = new AltosGraphTime.StateMarker(Altos.ao_flight_coast, "Coast");
+ AltosGraphTime.Element e_drogue = new AltosGraphTime.StateMarker(Altos.ao_flight_drogue, "Drogue");
+ AltosGraphTime.Element e_main = new AltosGraphTime.StateMarker(Altos.ao_flight_main, "Main");
+ AltosGraphTime.Element e_landed = new AltosGraphTime.StateMarker(Altos.ao_flight_landed, "Landed");
+
+ protected AltosGraphTime myAltosGraphTime(String suffix) {
+ return (new AltosGraphTime("Overall " + suffix))
+ .addElement(e_boost)
+ .addElement(e_drogue)
+ .addElement(e_main)
+ .addElement(e_landed);
+ }
+
+ public ArrayList<AltosGraph> graphs() {
+ ArrayList<AltosGraph> graphs = new ArrayList<AltosGraph>();
+
+ graphs.add( myAltosGraphTime("Summary")
+ .addElement(height)
+ .addElement(speed)
+ .addElement(acceleration) );
+
+ graphs.add( myAltosGraphTime("Altitude")
+ .addElement(height) );
+
+ graphs.add( myAltosGraphTime("Speed")
+ .addElement(speed) );
+
+ graphs.add( myAltosGraphTime("Acceleration")
+ .addElement(acceleration) );
+
+ graphs.add( myAltosGraphTime("Temperature")
+ .addElement(temperature) );
+
+ graphs.add( myAltosGraphTime("Continuity")
+ .addElement(drogue_voltage)
+ .addElement(main_voltage) );
+
+ return graphs;
+ }
+ }
+
+ static private class AscentGraphs extends OverallGraphs {
+ protected AltosGraphTime myAltosGraphTime(String suffix) {
+ return (new AltosGraphTime("Ascent " + suffix) {
+ public void addData(AltosDataPoint d) {
+ int state = d.state();
+ if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) {
+ super.addData(d);
+ }
+ }
+ }).addElement(e_boost)
+ .addElement(e_fast)
+ .addElement(e_coast);
+ }
+ }
+
+ static private class DescentGraphs extends OverallGraphs {
+ protected AltosGraphTime myAltosGraphTime(String suffix) {
+ return (new AltosGraphTime("Descent " + suffix) {
+ public void addData(AltosDataPoint d) {
+ int state = d.state();
+ if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) {
+ super.addData(d);
+ }
+ }
+ }).addElement(e_drogue)
+ .addElement(e_main);
+ // ((XYGraph)graph[8]).ymin = new Double(-50);
+ }
+ }
+
+ public AltosGraphUI(AltosRecordIterable records) {
+ super("Altos Graph");
+
+ Iterable<AltosDataPoint> reader = new AltosDataPointReader (records);
+ if (reader == null)
+ return;
+
+ init(reader, 0);
+ }
+
+ public AltosGraphUI(Iterable<AltosDataPoint> data, int which)
+ {
+ super("Altos Graph");
+ init(data, which);
+ }
+
+ private void init(Iterable<AltosDataPoint> data, int which) {
+ AltosGraph graph = createGraph(data, which);
+
+ JFreeChart chart = graph.createChart();
+ ChartPanel chartPanel = new ChartPanel(chart);
+ chartPanel.setMouseWheelEnabled(true);
+ chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
+ setContentPane(chartPanel);
+
+ pack();
+
+ RefineryUtilities.centerFrameOnScreen(this);
+
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ setVisible(true);
+ }
+
+ private static AltosGraph createGraph(Iterable<AltosDataPoint> data,
+ int which)
+ {
+ return createGraphsWhich(data, which).get(0);
+ }
+
+ private static ArrayList<AltosGraph> createGraphs(
+ Iterable<AltosDataPoint> data)
+ {
+ return createGraphsWhich(data, -1);
+ }
+
+ private static ArrayList<AltosGraph> createGraphsWhich(
+ Iterable<AltosDataPoint> data, int which)
+ {
+ ArrayList<AltosGraph> graph = new ArrayList<AltosGraph>();
+ graph.addAll((new OverallGraphs()).graphs());
+ graph.addAll((new AscentGraphs()).graphs());
+ graph.addAll((new DescentGraphs()).graphs());
+
+ if (which > 0) {
+ if (which >= graph.size()) {
+ which = 0;
+ }
+ AltosGraph g = graph.get(which);
+ graph = new ArrayList<AltosGraph>();
+ graph.add(g);
+ }
+
+ for (AltosDataPoint dp : data) {
+ for (AltosGraph g : graph) {
+ g.addData(dp);
+ }
+ }
+
+ return graph;
+ }
+}
+
+/* gnuplot bits...
+ *
+300x400
+
+--------------------------------------------------------
+TOO HARD! :)
+
+"ascent-gps-accuracy.png" "Vertical error margin to apogee - GPS v Baro (m)"
+ 5:($7 < 6 ? $24-$11 : 1/0)
+"descent-gps-accuracy.png" "Vertical error margin during descent - GPS v Baro (m)"
+ 5:($7 < 6 ? 1/0 : $24-$11)
+
+set output "overall-gps-accuracy.png"
+set ylabel "distance above sea level (m)"
+plot "telemetry.csv" using 5:11 with lines ti "baro altitude" axis x1y1, \
+ "telemetry.csv" using 5:24 with lines ti "gps altitude" axis x1y1
+
+set term png tiny size 700,700 enhanced
+set xlabel "m"
+set ylabel "m"
+set polar
+set grid polar
+set rrange[*:*]
+set angles degrees
+
+set output "overall-gps-path.png"
+#:30 with yerrorlines
+plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0) with lines ti "pad", \
+ "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0) with lines ti "boost", \
+ "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0) with lines ti "fast", \
+ "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0) with lines ti "coast", \
+ "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
+ "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
+ "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
+
+set output "ascent-gps-path.png"
+plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0):30 with lines ti "pad", \
+ "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0):20 with lines ti "boost", \
+ "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0):10 with lines ti "fast", \
+ "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0):5 with lines ti "coast"
+
+set output "descent-gps-path.png"
+plot "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
+ "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
+ "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
+
+ */
+
+
--- /dev/null
+/*
+ * 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.Math;
+
+public class AltosGreatCircle {
+ double distance;
+ double bearing;
+
+ double sqr(double a) { return a * a; }
+
+ static final double rad = Math.PI / 180;
+ static final double earth_radius = 6371.2 * 1000; /* in meters */
+
+ static int BEARING_LONG = 0;
+ static int BEARING_SHORT = 1;
+ static int BEARING_VOICE = 2;
+ String bearing_words(int length) {
+ String [][] bearing_string = {
+ {
+ "North", "North North East", "North East", "East North East",
+ "East", "East South East", "South East", "South South East",
+ "South", "South South West", "South West", "West South West",
+ "West", "West North West", "North West", "North North West"
+ }, {
+ "N", "NNE", "NE", "ENE",
+ "E", "ESE", "SE", "SSE",
+ "S", "SSW", "SW", "WSW",
+ "W", "WNW", "NW", "NNW"
+ }, {
+ "north", "nor nor east", "north east", "east nor east",
+ "east", "east sow east", "south east", "sow sow east",
+ "south", "sow sow west", "south west", "west sow west",
+ "west", "west nor west", "north west", "nor nor west "
+ }
+ };
+ return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16];
+ }
+
+ public AltosGreatCircle (double start_lat, double start_lon,
+ double end_lat, double end_lon)
+ {
+ double lat1 = rad * start_lat;
+ double lon1 = rad * -start_lon;
+ double lat2 = rad * end_lat;
+ double lon2 = rad * -end_lon;
+
+ double d_lon = lon2 - lon1;
+
+ /* From http://en.wikipedia.org/wiki/Great-circle_distance */
+ double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) +
+ sqr(Math.cos(lat1) * Math.sin(lat2) -
+ Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon)));
+ double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon);
+ double d = Math.atan2(vdn,vdd);
+ double course;
+
+ if (Math.cos(lat1) < 1e-20) {
+ if (lat1 > 0)
+ course = Math.PI;
+ else
+ course = -Math.PI;
+ } else {
+ if (d < 1e-10)
+ course = 0;
+ else
+ course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) /
+ (Math.sin(d)*Math.cos(lat1)));
+ if (Math.sin(lon2-lon1) > 0)
+ course = 2 * Math.PI-course;
+ }
+ distance = d * earth_radius;
+ bearing = course * 180/Math.PI;
+ }
+
+ public AltosGreatCircle(AltosGPS start, AltosGPS end) {
+ this(start.lat, start.lon, end.lat, end.lon);
+ }
+
+ public AltosGreatCircle() {
+ distance = 0;
+ bearing = 0;
+ }
+}
--- /dev/null
+/*
+ * 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.concurrent.LinkedBlockingQueue;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.Arrays;
+
+class HexFileInputStream extends PushbackInputStream {
+ public int line;
+
+ public HexFileInputStream(FileInputStream o) {
+ super(new BufferedInputStream(o));
+ line = 1;
+ }
+
+ public int read() throws IOException {
+ int c = super.read();
+ if (c == '\n')
+ line++;
+ return c;
+ }
+
+ public void unread(int c) throws IOException {
+ if (c == '\n')
+ line--;
+ if (c != -1)
+ super.unread(c);
+ }
+}
+
+class HexRecord implements Comparable {
+ public int address;
+ public int type;
+ public byte checksum;
+ public byte[] data;
+
+ static final int NORMAL = 0;
+ static final int EOF = 1;
+ static final int EXTENDED_ADDRESS = 2;
+
+ enum read_state {
+ marker,
+ length,
+ address,
+ type,
+ data,
+ checksum,
+ newline,
+ white,
+ done,
+ }
+
+ boolean ishex(int c) {
+ if ('0' <= c && c <= '9')
+ return true;
+ if ('a' <= c && c <= 'f')
+ return true;
+ if ('A' <= c && c <= 'F')
+ return true;
+ return false;
+ }
+
+ boolean isspace(int c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ return true;
+ }
+ return false;
+ }
+
+ int fromhex(int c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+ }
+
+ public byte checksum() {
+ byte got = 0;
+
+ got += data.length;
+ got += (address >> 8) & 0xff;
+ got += (address ) & 0xff;
+ got += type;
+ for (int i = 0; i < data.length; i++)
+ got += data[i];
+ return (byte) (-got);
+ }
+
+ public int compareTo(Object other) {
+ HexRecord o = (HexRecord) other;
+ return address - o.address;
+ }
+
+ public String toString() {
+ return String.format("%04x: %02x (%d)", address, type, data.length);
+ }
+
+ public HexRecord(HexFileInputStream input) throws IOException {
+ read_state state = read_state.marker;
+ int nhexbytes = 0;
+ int hex = 0;
+ int ndata = 0;
+ byte got_checksum;
+
+ while (state != read_state.done) {
+ int c = input.read();
+ if (c < 0 && state != read_state.white)
+ throw new IOException(String.format("%d: Unexpected EOF", input.line));
+ if (c == ' ')
+ continue;
+ switch (state) {
+ case marker:
+ if (c != ':')
+ throw new IOException("Missing ':'");
+ state = read_state.length;
+ nhexbytes = 2;
+ hex = 0;
+ break;
+ case length:
+ case address:
+ case type:
+ case data:
+ case checksum:
+ if(!ishex(c))
+ throw new IOException(String.format("Non-hex char '%c'", c));
+ hex = hex << 4 | fromhex(c);
+ --nhexbytes;
+ if (nhexbytes != 0)
+ break;
+
+ switch (state) {
+ case length:
+ data = new byte[hex];
+ state = read_state.address;
+ nhexbytes = 4;
+ break;
+ case address:
+ address = hex;
+ state = read_state.type;
+ nhexbytes = 2;
+ break;
+ case type:
+ type = hex;
+ if (data.length > 0)
+ state = read_state.data;
+ else
+ state = read_state.checksum;
+ nhexbytes = 2;
+ ndata = 0;
+ break;
+ case data:
+ data[ndata] = (byte) hex;
+ ndata++;
+ nhexbytes = 2;
+ if (ndata == data.length)
+ state = read_state.checksum;
+ break;
+ case checksum:
+ checksum = (byte) hex;
+ state = read_state.newline;
+ break;
+ default:
+ break;
+ }
+ hex = 0;
+ break;
+ case newline:
+ if (c != '\n' && c != '\r')
+ throw new IOException("Missing newline");
+ state = read_state.white;
+ break;
+ case white:
+ if (!isspace(c)) {
+ input.unread(c);
+ state = read_state.done;
+ }
+ break;
+ case done:
+ break;
+ }
+ }
+ got_checksum = checksum();
+ if (got_checksum != checksum)
+ throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n",
+ checksum, got_checksum));
+ }
+}
+
+public class AltosHexfile {
+ public int address;
+ public byte[] data;
+
+ public byte get_byte(int a) {
+ return data[a - address];
+ }
+
+ public AltosHexfile(FileInputStream file) throws IOException {
+ HexFileInputStream input = new HexFileInputStream(file);
+ LinkedList<HexRecord> record_list = new LinkedList<HexRecord>();
+ boolean done = false;
+
+ while (!done) {
+ HexRecord record = new HexRecord(input);
+
+ if (record.type == HexRecord.EOF)
+ done = true;
+ else
+ record_list.add(record);
+ }
+ HexRecord[] records = record_list.toArray(new HexRecord[0]);
+ Arrays.sort(records);
+ if (records.length > 0) {
+ int base = records[0].address;
+ int bound = records[records.length-1].address +
+ records[records.length-1].data.length;
+
+ data = new byte[bound - base];
+ address = base;
+ Arrays.fill(data, (byte) 0xff);
+
+ /* Paint the records into the new array */
+ for (int i = 0; i < records.length; i++) {
+ for (int j = 0; j < records[i].data.length; j++)
+ data[records[i].address - base + j] = records[i].data[j];
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.io.*;
+import java.util.concurrent.*;
+
+public class AltosIgnite {
+ AltosDevice device;
+ AltosSerial serial;
+ boolean remote;
+ boolean serial_started;
+ final static int None = 0;
+ final static int Apogee = 1;
+ final static int Main = 2;
+
+ final static int Unknown = 0;
+ final static int Ready = 1;
+ final static int Active = 2;
+ final static int Open = 3;
+
+ private void start_serial() throws InterruptedException {
+ serial_started = true;
+ if (remote) {
+ serial.set_radio();
+ serial.printf("p\nE 0\n");
+ serial.flush_input();
+ }
+ }
+
+ private void stop_serial() throws InterruptedException {
+ if (!serial_started)
+ return;
+ serial_started = false;
+ if (serial == null)
+ return;
+ if (remote) {
+ serial.printf("~");
+ serial.flush_output();
+ }
+ }
+
+ class string_ref {
+ String value;
+
+ public String get() {
+ return value;
+ }
+ public void set(String i) {
+ value = i;
+ }
+ public string_ref() {
+ value = null;
+ }
+ }
+
+ private boolean get_string(String line, String label, string_ref s) {
+ if (line.startsWith(label)) {
+ String quoted = line.substring(label.length()).trim();
+
+ if (quoted.startsWith("\""))
+ quoted = quoted.substring(1);
+ if (quoted.endsWith("\""))
+ quoted = quoted.substring(0,quoted.length()-1);
+ s.set(quoted);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private int status(String status_name) {
+ if (status_name.equals("unknown"))
+ return Unknown;
+ if (status_name.equals("ready"))
+ return Ready;
+ if (status_name.equals("active"))
+ return Active;
+ if (status_name.equals("open"))
+ return Open;
+ return Unknown;
+ }
+
+ public int status(int igniter) throws InterruptedException, TimeoutException {
+ int status = Unknown;
+ if (serial == null)
+ return status;
+ string_ref status_name = new string_ref();
+ start_serial();
+ serial.printf("t\n");
+ for (;;) {
+ String line = serial.get_reply(5000);
+ if (line == null)
+ throw new TimeoutException();
+ if (get_string(line, "Igniter: drogue Status: ", status_name))
+ if (igniter == Apogee)
+ status = status(status_name.get());
+ if (get_string(line, "Igniter: main Status: ", status_name)) {
+ if (igniter == Main)
+ status = status(status_name.get());
+ break;
+ }
+ }
+ stop_serial();
+ return status;
+ }
+
+ public String status_string(int status) {
+ switch (status) {
+ case Unknown: return "Unknown";
+ case Ready: return "Ready";
+ case Active: return "Active";
+ case Open: return "Open";
+ default: return "Unknown";
+ }
+ }
+
+ public void fire(int igniter) {
+ if (serial == null)
+ return;
+ try {
+ start_serial();
+ switch (igniter) {
+ case Main:
+ serial.printf("i DoIt main\n");
+ break;
+ case Apogee:
+ serial.printf("i DoIt drogue\n");
+ break;
+ }
+ } catch (InterruptedException ie) {
+ } finally {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void close() {
+ try {
+ stop_serial();
+ } catch (InterruptedException ie) {
+ }
+ serial.close();
+ serial = null;
+ }
+
+ public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
+
+ device = in_device;
+ serial = new AltosSerial(device);
+ remote = false;
+
+ if (!device.matchProduct(AltosDevice.product_telemetrum))
+ remote = true;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.*;
+
+public class AltosIgniteUI
+ extends JDialog
+ implements ActionListener
+{
+ AltosDevice device;
+ AltosIgnite ignite;
+ JFrame owner;
+ JLabel label;
+ JRadioButton apogee;
+ JLabel apogee_status_label;
+ JRadioButton main;
+ JLabel main_status_label;
+ JToggleButton arm;
+ JButton fire;
+ javax.swing.Timer timer;
+
+ int apogee_status;
+ int main_status;
+
+ final static int timeout = 1 * 1000;
+
+ int time_remaining;
+ boolean timer_running;
+
+ void set_arm_text() {
+ if (arm.isSelected())
+ arm.setText(String.format("%d", time_remaining));
+ else
+ arm.setText("Arm");
+ }
+
+ void start_timer() {
+ time_remaining = 10;
+ set_arm_text();
+ timer_running = true;
+ }
+
+ void stop_timer() {
+ time_remaining = 0;
+ arm.setSelected(false);
+ arm.setEnabled(false);
+ fire.setEnabled(false);
+ timer_running = false;
+ set_arm_text();
+ }
+
+ void cancel () {
+ apogee.setSelected(false);
+ main.setSelected(false);
+ fire.setEnabled(false);
+ stop_timer();
+ }
+
+ void get_ignite_status() throws InterruptedException, TimeoutException {
+ apogee_status = ignite.status(AltosIgnite.Apogee);
+ main_status = ignite.status(AltosIgnite.Main);
+ }
+
+ void set_ignite_status() throws InterruptedException, TimeoutException {
+ get_ignite_status();
+ apogee_status_label.setText(String.format("\"%s\"", ignite.status_string(apogee_status)));
+ main_status_label.setText(String.format("\"%s\"", ignite.status_string(main_status)));
+ }
+
+ void close() {
+ timer.stop();
+ setVisible(false);
+ ignite.close();
+ }
+
+ void abort() {
+ close();
+ JOptionPane.showMessageDialog(owner,
+ String.format("Connection to \"%s\" failed",
+ device.toShortString()),
+ "Connection Failed",
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ void tick_timer() {
+ if (timer_running) {
+ --time_remaining;
+ if (time_remaining <= 0)
+ cancel();
+ else
+ set_arm_text();
+ }
+ try {
+ set_ignite_status();
+ } catch (InterruptedException ie) {
+ abort();
+ } catch (TimeoutException te) {
+ abort();
+ }
+ }
+
+ void fire() {
+ if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
+ int igniter = AltosIgnite.None;
+ if (apogee.isSelected() && !main.isSelected())
+ igniter = AltosIgnite.Apogee;
+ else if (main.isSelected() && !apogee.isSelected())
+ igniter = AltosIgnite.Main;
+ ignite.fire(igniter);
+ cancel();
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ if (cmd.equals("apogee") || cmd.equals("main")) {
+ stop_timer();
+ }
+
+ if (cmd.equals("apogee") && apogee.isSelected()) {
+ main.setSelected(false);
+ arm.setEnabled(true);
+ }
+ if (cmd.equals("main") && main.isSelected()) {
+ apogee.setSelected(false);
+ arm.setEnabled(true);
+ }
+
+ if (cmd.equals("arm")) {
+ if (arm.isSelected()) {
+ fire.setEnabled(true);
+ start_timer();
+ } else
+ cancel();
+ }
+ if (cmd.equals("fire"))
+ fire();
+ if (cmd.equals("tick"))
+ tick_timer();
+ if (cmd.equals("close")) {
+ close();
+ }
+ }
+
+ /* A window listener to catch closing events and tell the config code */
+ class ConfigListener extends WindowAdapter {
+ AltosIgniteUI ui;
+
+ public ConfigListener(AltosIgniteUI this_ui) {
+ ui = this_ui;
+ }
+
+ public void windowClosing(WindowEvent e) {
+ ui.actionPerformed(new ActionEvent(e.getSource(),
+ ActionEvent.ACTION_PERFORMED,
+ "close"));
+ }
+ }
+
+ private boolean open() {
+ device = AltosDeviceDialog.show(owner, AltosDevice.product_any);
+ if (device != null) {
+ try {
+ ignite = new AltosIgnite(device);
+ return true;
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Cannot open device \"%s\"",
+ device.toShortString()),
+ "Cannot open target device",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (AltosSerialInUseException si) {
+ JOptionPane.showMessageDialog(owner,
+ String.format("Device \"%s\" already in use",
+ device.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ee) {
+ JOptionPane.showMessageDialog(owner,
+ device.toShortString(),
+ ee.getLocalizedMessage(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ return false;
+ }
+
+ public AltosIgniteUI(JFrame in_owner) {
+
+ owner = in_owner;
+ apogee_status = AltosIgnite.Unknown;
+ main_status = AltosIgnite.Unknown;
+
+ if (!open())
+ return;
+
+ Container pane = getContentPane();
+ GridBagConstraints c = new GridBagConstraints();
+ Insets i = new Insets(4,4,4,4);
+
+ timer = new javax.swing.Timer(timeout, this);
+ timer.setActionCommand("tick");
+ timer_running = false;
+ timer.restart();
+
+ owner = in_owner;
+
+ pane.setLayout(new GridBagLayout());
+
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = i;
+ c.weightx = 1;
+ c.weighty = 1;
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 2;
+ c.anchor = GridBagConstraints.CENTER;
+ label = new JLabel ("Fire Igniter");
+ pane.add(label, c);
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ apogee = new JRadioButton ("Apogee");
+ pane.add(apogee, c);
+ apogee.addActionListener(this);
+ apogee.setActionCommand("apogee");
+
+ c.gridx = 1;
+ c.gridy = 1;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ apogee_status_label = new JLabel();
+ pane.add(apogee_status_label, c);
+
+ c.gridx = 0;
+ c.gridy = 2;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ main = new JRadioButton ("Main");
+ pane.add(main, c);
+ main.addActionListener(this);
+ main.setActionCommand("main");
+
+ c.gridx = 1;
+ c.gridy = 2;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.WEST;
+ main_status_label = new JLabel();
+ pane.add(main_status_label, c);
+
+ try {
+ set_ignite_status();
+ } catch (InterruptedException ie) {
+ abort();
+ return;
+ } catch (TimeoutException te) {
+ abort();
+ return;
+ }
+
+ c.gridx = 0;
+ c.gridy = 3;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.CENTER;
+ arm = new JToggleButton ("Arm");
+ pane.add(arm, c);
+ arm.addActionListener(this);
+ arm.setActionCommand("arm");
+ arm.setEnabled(false);
+
+ c.gridx = 1;
+ c.gridy = 3;
+ c.gridwidth = 1;
+ c.anchor = GridBagConstraints.CENTER;
+ fire = new JButton ("Fire");
+ fire.setEnabled(false);
+ pane.add(fire, c);
+ fire.addActionListener(this);
+ fire.setActionCommand("fire");
+
+ pack();
+ setLocationRelativeTo(owner);
+ setVisible(true);
+
+ addWindowListener(new ConfigListener(this));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosInfoTable extends JTable {
+ private AltosFlightInfoTableModel model;
+
+ private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14);
+ private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14);
+
+ static final int info_columns = 3;
+ static final int info_rows = 17;
+
+ int desired_row_height() {
+ FontMetrics infoValueMetrics = getFontMetrics(infoValueFont);
+ return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
+ }
+
+ public AltosInfoTable() {
+ super(new AltosFlightInfoTableModel(info_rows, info_columns));
+ model = (AltosFlightInfoTableModel) getModel();
+ setFont(infoValueFont);
+ setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
+ setShowGrid(true);
+ setRowHeight(desired_row_height());
+ doLayout();
+ }
+
+ public Dimension getPreferredScrollableViewportSize() {
+ return getPreferredSize();
+ }
+
+ void info_reset() {
+ model.reset();
+ }
+
+ void info_add_row(int col, String name, String value) {
+ model.addRow(col, name, value);
+ }
+
+ void info_add_row(int col, String name, String format, Object... parameters) {
+ info_add_row (col, name, String.format(format, parameters));
+ }
+
+ void info_add_deg(int col, String name, double v, int pos, int neg) {
+ int c = pos;
+ if (v < 0) {
+ c = neg;
+ v = -v;
+ }
+ double deg = Math.floor(v);
+ double min = (v - deg) * 60;
+
+ info_add_row(col, name, String.format("%3.0f°%08.5f'", deg, min));
+ }
+
+ void info_finish() {
+ model.finish();
+ }
+
+ public void clear() {
+ model.clear();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ if (state == null)
+ return;
+ info_reset();
+ info_add_row(0, "Rocket state", "%s", state.data.state());
+ info_add_row(0, "Callsign", "%s", state.data.callsign);
+ info_add_row(0, "Rocket serial", "%6d", state.data.serial);
+ info_add_row(0, "Rocket flight", "%6d", state.data.flight);
+
+ info_add_row(0, "RSSI", "%6d dBm", state.data.rssi);
+ info_add_row(0, "CRC Errors", "%6d", crc_errors);
+ info_add_row(0, "Height", "%6.0f m", state.height);
+ info_add_row(0, "Max height", "%6.0f m", state.max_height);
+ info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration);
+ info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration);
+ info_add_row(0, "Speed", "%8.1f m/s", state.ascent ? state.speed : state.baro_speed);
+ info_add_row(0, "Max Speed", "%8.1f m/s", state.max_speed);
+ info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
+ info_add_row(0, "Battery", "%9.2f V", state.battery);
+ info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense);
+ info_add_row(0, "Main", "%9.2f V", state.main_sense);
+ info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude);
+ if (state.gps == null) {
+ info_add_row(1, "GPS", "not available");
+ } else {
+ if (state.gps_ready)
+ info_add_row(1, "GPS state", "%s", "ready");
+ else
+ info_add_row(1, "GPS state", "wait (%d)",
+ state.gps_waiting);
+ if (state.data.gps.locked)
+ info_add_row(1, "GPS", " locked");
+ else if (state.data.gps.connected)
+ info_add_row(1, "GPS", " unlocked");
+ else
+ info_add_row(1, "GPS", " missing");
+ info_add_row(1, "Satellites", "%6d", state.data.gps.nsat);
+ info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
+ info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
+ info_add_row(1, "GPS altitude", "%6d", state.gps.alt);
+ info_add_row(1, "GPS height", "%6.0f", state.gps_height);
+
+ /* The SkyTraq GPS doesn't report these values */
+ if (false) {
+ info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°",
+ state.gps.ground_speed,
+ state.gps.course);
+ info_add_row(1, "GPS climb rate", "%8.1f m/s",
+ state.gps.climb_rate);
+ info_add_row(1, "GPS error", "%6d m(h)%3d m(v)",
+ state.gps.h_error, state.gps.v_error);
+ }
+ info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop);
+
+ if (state.npad > 0) {
+ if (state.from_pad != null) {
+ info_add_row(1, "Distance from pad", "%6d m",
+ (int) (state.from_pad.distance + 0.5));
+ info_add_row(1, "Direction from pad", "%6d°",
+ (int) (state.from_pad.bearing + 0.5));
+ info_add_row(1, "Elevation from pad", "%6d°",
+ (int) (state.elevation + 0.5));
+ info_add_row(1, "Range from pad", "%6d m",
+ (int) (state.range + 0.5));
+ } else {
+ info_add_row(1, "Distance from pad", "unknown");
+ info_add_row(1, "Direction from pad", "unknown");
+ info_add_row(1, "Elevation from pad", "unknown");
+ info_add_row(1, "Range from pad", "unknown");
+ }
+ info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
+ info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
+ info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
+ }
+ info_add_row(1, "GPS date", "%04d-%02d-%02d",
+ state.gps.year,
+ state.gps.month,
+ state.gps.day);
+ info_add_row(1, "GPS time", " %02d:%02d:%02d",
+ state.gps.hour,
+ state.gps.minute,
+ state.gps.second);
+ int nsat_vis = 0;
+ int c;
+
+ if (state.gps.cc_gps_sat == null)
+ info_add_row(2, "Satellites Visible", "%4d", 0);
+ else {
+ info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length);
+ for (c = 0; c < state.gps.cc_gps_sat.length; c++) {
+ info_add_row(2, "Satellite id,C/N0",
+ "%4d, %4d",
+ state.gps.cc_gps_sat[c].svid,
+ state.gps.cc_gps_sat[c].c_n0);
+ }
+ }
+ }
+ info_finish();
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.util.*;
+
+public class AltosKML implements AltosWriter {
+
+ File name;
+ PrintStream out;
+ int state = -1;
+ AltosRecord prev = null;
+
+ static final String[] kml_state_colors = {
+ "FF000000",
+ "FF000000",
+ "FF000000",
+ "FF0000FF",
+ "FF4080FF",
+ "FF00FFFF",
+ "FFFF0000",
+ "FF00FF00",
+ "FF000000",
+ "FFFFFFFF"
+ };
+
+ static final String kml_header_start =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
+ "<Document>\n" +
+ " <name>AO Flight#%d S/N: %03d</name>\n" +
+ " <description>\n";
+ static final String kml_header_end =
+ " </description>\n" +
+ " <open>0</open>\n";
+
+ static final String kml_style_start =
+ " <Style id=\"ao-flightstate-%s\">\n" +
+ " <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
+ " <BalloonStyle>\n" +
+ " <text>\n";
+
+ static final String kml_style_end =
+ " </text>\n" +
+ " </BalloonStyle>\n" +
+ " </Style>\n";
+
+ static final String kml_placemark_start =
+ " <Placemark>\n" +
+ " <name>%s</name>\n" +
+ " <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
+ " <LineString>\n" +
+ " <tessellate>1</tessellate>\n" +
+ " <altitudeMode>absolute</altitudeMode>\n" +
+ " <coordinates>\n";
+
+ static final String kml_coord_fmt =
+ " %12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+
+ static final String kml_placemark_end =
+ " </coordinates>\n" +
+ " </LineString>\n" +
+ " </Placemark>\n";
+
+ static final String kml_footer =
+ "</Document>\n" +
+ "</kml>\n";
+
+ void start (AltosRecord record) {
+ out.printf(kml_header_start, record.flight, record.serial);
+ out.printf("Date: %04d-%02d-%02d\n",
+ record.gps.year, record.gps.month, record.gps.day);
+ out.printf("Time: %2d:%02d:%02d\n",
+ record.gps.hour, record.gps.minute, record.gps.second);
+ out.printf("%s", kml_header_end);
+ }
+
+ boolean started = false;
+
+ void state_start(AltosRecord record) {
+ String state_name = Altos.state_name(record.state);
+ out.printf(kml_style_start, state_name, kml_state_colors[record.state]);
+ out.printf("\tState: %s\n", state_name);
+ out.printf("%s", kml_style_end);
+ out.printf(kml_placemark_start, state_name, state_name);
+ }
+
+ void state_end(AltosRecord record) {
+ out.printf("%s", kml_placemark_end);
+ }
+
+ void coord(AltosRecord record) {
+ AltosGPS gps = record.gps;
+ out.printf(kml_coord_fmt,
+ gps.lon, gps.lat,
+ record.filtered_altitude(), (double) gps.alt,
+ record.time, gps.nsat);
+ }
+
+ void end() {
+ out.printf("%s", kml_footer);
+ }
+
+ public void close() {
+ if (prev != null) {
+ state_end(prev);
+ end();
+ prev = null;
+ }
+ }
+
+ public void write(AltosRecord record) {
+ AltosGPS gps = record.gps;
+
+ if (gps == null)
+ return;
+ if (!started) {
+ start(record);
+ started = true;
+ }
+ if (prev != null &&
+ prev.gps.second == record.gps.second &&
+ prev.gps.minute == record.gps.minute &&
+ prev.gps.hour == record.gps.hour)
+ return;
+ if (record.state != state) {
+ state = record.state;
+ if (prev != null) {
+ coord(record);
+ state_end(prev);
+ }
+ state_start(record);
+ }
+ coord(record);
+ prev = record;
+ }
+
+ public void write(AltosRecordIterable iterable) {
+ for (AltosRecord record : iterable)
+ write(record);
+ }
+
+ public AltosKML(File in_name) throws FileNotFoundException {
+ name = in_name;
+ out = new PrintStream(name);
+ }
+
+ public AltosKML(String in_string) throws FileNotFoundException {
+ this(new File(in_string));
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosLanded extends JComponent implements AltosFlightDisplay {
+ GridBagLayout layout;
+ Font label_font;
+ Font value_font;
+
+ public class LandedValue {
+ JLabel label;
+ JTextField value;
+ void show(AltosState state, int crc_errors) {}
+
+ void reset() {
+ value.setText("");
+ }
+
+ void show(String format, double v) {
+ value.setText(String.format(format, v));
+ }
+
+ public LandedValue (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 0; c.gridy = y;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = 0;
+ c.fill = GridBagConstraints.VERTICAL;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 1; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = 1;
+ c.fill = GridBagConstraints.BOTH;
+ layout.setConstraints(value, c);
+ add(value);
+ }
+ }
+
+ String pos(double p, String pos, String neg) {
+ String h = pos;
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%s %4d° %9.6f", h, deg, min);
+ }
+
+ class Lat extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ value.setText(pos(state.gps.lat,"N", "S"));
+ else
+ value.setText("???");
+ }
+ public Lat (GridBagLayout layout, int y) {
+ super (layout, y, "Latitude");
+ }
+ }
+
+ Lat lat;
+
+ class Lon extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps != null)
+ value.setText(pos(state.gps.lon,"E", "W"));
+ else
+ value.setText("???");
+ }
+ public Lon (GridBagLayout layout, int y) {
+ super (layout, y, "Longitude");
+ }
+ }
+
+ Lon lon;
+
+ class Bearing extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.from_pad != null)
+ show("%3.0f°", state.from_pad.bearing);
+ else
+ value.setText("???");
+ }
+ public Bearing (GridBagLayout layout, int y) {
+ super (layout, y, "Bearing");
+ }
+ }
+
+ Bearing bearing;
+
+ class Distance extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ if (state.from_pad != null)
+ show("%6.0f m", state.from_pad.distance);
+ else
+ value.setText("???");
+ }
+ public Distance (GridBagLayout layout, int y) {
+ super (layout, y, "Distance");
+ }
+ }
+
+ Distance distance;
+
+ class Height extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m", state.max_height);
+ }
+ public Height (GridBagLayout layout, int y) {
+ super (layout, y, "Maximum Height");
+ }
+ }
+
+ Height height;
+
+ class Speed extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m/s", state.max_speed);
+ }
+ public Speed (GridBagLayout layout, int y) {
+ super (layout, y, "Maximum Speed");
+ }
+ }
+
+ Speed speed;
+
+ class Accel extends LandedValue {
+ void show (AltosState state, int crc_errors) {
+ show("%6.0f m/s²", state.max_acceleration);
+ }
+ public Accel (GridBagLayout layout, int y) {
+ super (layout, y, "Maximum Acceleration");
+ }
+ }
+
+ Accel accel;
+
+ public void reset() {
+ lat.reset();
+ lon.reset();
+ bearing.reset();
+ distance.reset();
+ height.reset();
+ speed.reset();
+ accel.reset();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ bearing.show(state, crc_errors);
+ distance.show(state, crc_errors);
+ lat.show(state, crc_errors);
+ lon.show(state, crc_errors);
+ height.show(state, crc_errors);
+ speed.show(state, crc_errors);
+ accel.show(state, crc_errors);
+ }
+
+ public AltosLanded() {
+ layout = new GridBagLayout();
+
+ label_font = new Font("Dialog", Font.PLAIN, 22);
+ value_font = new Font("Monospaced", Font.PLAIN, 22);
+ setLayout(layout);
+
+ /* Elements in descent display */
+ bearing = new Bearing(layout, 0);
+ distance = new Distance(layout, 1);
+ lat = new Lat(layout, 2);
+ lon = new Lon(layout, 3);
+ height = new Height(layout, 4);
+ speed = new Speed(layout, 5);
+ accel = new Accel(layout, 6);
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosLed extends JLabel {
+ ImageIcon on, off;
+
+ ImageIcon create_icon(String path) {
+ java.net.URL imgURL = AltosUI.class.getResource(path);
+ if (imgURL != null)
+ return new ImageIcon(imgURL);
+ System.err.printf("Cannot find icon \"%s\"\n", path);
+ return null;
+ }
+
+ public void set(boolean set) {
+ if (set)
+ setIcon(on);
+ else
+ setIcon(off);
+ }
+
+ public AltosLed(String on_path, String off_path) {
+ on = create_icon(on_path);
+ off = create_icon(off_path);
+ setIcon(off);
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosLights extends JComponent {
+
+ GridBagLayout gridbag;
+
+ AltosLed red, green;
+
+ ImageIcon create_icon(String path, String description) {
+ java.net.URL imgURL = AltosUI.class.getResource(path);
+ if (imgURL != null)
+ return new ImageIcon(imgURL, description);
+ System.err.printf("Cannot find icon \"%s\"\n", path);
+ return null;
+ }
+
+ public void set (boolean on) {
+ if (on) {
+ red.set(false);
+ green.set(true);
+ } else {
+ red.set(true);
+ green.set(false);
+ }
+ }
+
+ public AltosLights() {
+ GridBagConstraints c;
+ gridbag = new GridBagLayout();
+ setLayout(gridbag);
+
+ c = new GridBagConstraints();
+ red = new AltosLed("/redled.png", "/grayled.png");
+ c.gridx = 0; c.gridy = 0;
+ c.insets = new Insets (0, 5, 0, 5);
+ gridbag.setConstraints(red, c);
+ add(red);
+ red.set(true);
+ green = new AltosLed("/greenled.png", "/grayled.png");
+ c.gridx = 1; c.gridy = 0;
+ gridbag.setConstraints(green, c);
+ add(green);
+ green.set(false);
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public class AltosLine {
+ public String line;
+
+ public AltosLine() {
+ line = null;
+ }
+
+ public AltosLine(String s) {
+ line = s;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.io.*;
+import java.lang.*;
+import java.util.*;
+import java.text.ParseException;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/*
+ * This creates a thread to capture telemetry data and write it to
+ * a log file
+ */
+class AltosLog implements Runnable {
+
+ LinkedBlockingQueue<AltosLine> input_queue;
+ LinkedBlockingQueue<String> pending_queue;
+ int serial;
+ int flight;
+ FileWriter log_file;
+ Thread log_thread;
+
+ private void close_log_file() {
+ if (log_file != null) {
+ try {
+ log_file.close();
+ } catch (IOException io) {
+ }
+ log_file = null;
+ }
+ }
+
+ void close() {
+ close_log_file();
+ if (log_thread != null) {
+ log_thread.interrupt();
+ log_thread = null;
+ }
+ }
+
+ boolean open (AltosTelemetry telem) throws IOException {
+ AltosFile a = new AltosFile(telem);
+
+ log_file = new FileWriter(a, true);
+ if (log_file != null) {
+ while (!pending_queue.isEmpty()) {
+ try {
+ String s = pending_queue.take();
+ log_file.write(s);
+ log_file.write('\n');
+ } catch (InterruptedException ie) {
+ }
+ }
+ log_file.flush();
+ }
+ return log_file != null;
+ }
+
+ public void run () {
+ try {
+ for (;;) {
+ AltosLine line = input_queue.take();
+ if (line.line == null)
+ continue;
+ try {
+ AltosTelemetry telem = new AltosTelemetry(line.line);
+ if (telem.serial != serial || telem.flight != flight || log_file == null) {
+ close_log_file();
+ serial = telem.serial;
+ flight = telem.flight;
+ open(telem);
+ }
+ } catch (ParseException pe) {
+ } catch (AltosCRCException ce) {
+ }
+ if (log_file != null) {
+ log_file.write(line.line);
+ log_file.write('\n');
+ log_file.flush();
+ } else
+ pending_queue.put(line.line);
+ }
+ } catch (InterruptedException ie) {
+ } catch (IOException ie) {
+ }
+ close();
+ }
+
+ public AltosLog (AltosSerial s) {
+ pending_queue = new LinkedBlockingQueue<String> ();
+ input_queue = new LinkedBlockingQueue<AltosLine> ();
+ s.add_monitor(input_queue);
+ serial = -1;
+ flight = -1;
+ log_file = null;
+ log_thread = new Thread(this);
+ log_thread.start();
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosPad extends JComponent implements AltosFlightDisplay {
+ GridBagLayout layout;
+
+ public class LaunchStatus {
+ JLabel label;
+ JTextField value;
+ AltosLights lights;
+
+ void show(AltosState state, int crc_errors) {}
+ void reset() {
+ value.setText("");
+ lights.set(false);
+ }
+
+ public LaunchStatus (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.weighty = 1;
+
+ lights = new AltosLights();
+ c.gridx = 0; c.gridy = y;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(lights, c);
+ add(lights);
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 2; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+
+ }
+ }
+
+ public class LaunchValue {
+ JLabel label;
+ JTextField value;
+ void show(AltosState state, int crc_errors) {}
+
+ void reset() {
+ value.setText("");
+ }
+ public LaunchValue (GridBagLayout layout, int y, String text) {
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
+ c.weighty = 1;
+
+ label = new JLabel(text);
+ label.setFont(Altos.label_font);
+ label.setHorizontalAlignment(SwingConstants.LEFT);
+ c.gridx = 1; c.gridy = y;
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.VERTICAL;
+ c.weightx = 0;
+ layout.setConstraints(label, c);
+ add(label);
+
+ value = new JTextField(Altos.text_width);
+ value.setFont(Altos.value_font);
+ value.setHorizontalAlignment(SwingConstants.RIGHT);
+ c.gridx = 2; c.gridy = y;
+ c.anchor = GridBagConstraints.EAST;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ layout.setConstraints(value, c);
+ add(value);
+ }
+ }
+
+ class Battery extends LaunchStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.battery));
+ lights.set(state.battery > 3.7);
+ }
+ public Battery (GridBagLayout layout, int y) {
+ super(layout, y, "Battery Voltage");
+ }
+ }
+
+ Battery battery;
+
+ class Apogee extends LaunchStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.drogue_sense));
+ lights.set(state.drogue_sense > 3.2);
+ }
+ public Apogee (GridBagLayout layout, int y) {
+ super(layout, y, "Apogee Igniter Voltage");
+ }
+ }
+
+ Apogee apogee;
+
+ class Main extends LaunchStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.2f V", state.main_sense));
+ lights.set(state.main_sense > 3.2);
+ }
+ public Main (GridBagLayout layout, int y) {
+ super(layout, y, "Main Igniter Voltage");
+ }
+ }
+
+ Main main;
+
+ class GPSLocked extends LaunchStatus {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4d sats", state.gps.nsat));
+ lights.set(state.gps.locked);
+ }
+ public GPSLocked (GridBagLayout layout, int y) {
+ super (layout, y, "GPS Locked");
+ }
+ }
+
+ GPSLocked gps_locked;
+
+ class GPSReady extends LaunchStatus {
+ void show (AltosState state, int crc_errors) {
+ if (state.gps_ready)
+ value.setText("Ready");
+ else
+ value.setText(String.format("Waiting %d", state.gps_waiting));
+ lights.set(state.gps_ready);
+ }
+ public GPSReady (GridBagLayout layout, int y) {
+ super (layout, y, "GPS Ready");
+ }
+ }
+
+ GPSReady gps_ready;
+
+ String pos(double p, String pos, String neg) {
+ String h = pos;
+ if (p < 0) {
+ h = neg;
+ p = -p;
+ }
+ int deg = (int) Math.floor(p);
+ double min = (p - Math.floor(p)) * 60.0;
+ return String.format("%s %4d° %9.6f", h, deg, min);
+ }
+
+ class PadLat extends LaunchValue {
+ void show (AltosState state, int crc_errors) {
+ value.setText(pos(state.pad_lat,"N", "S"));
+ }
+ public PadLat (GridBagLayout layout, int y) {
+ super (layout, y, "Pad Latitude");
+ }
+ }
+
+ PadLat pad_lat;
+
+ class PadLon extends LaunchValue {
+ void show (AltosState state, int crc_errors) {
+ value.setText(pos(state.pad_lon,"E", "W"));
+ }
+ public PadLon (GridBagLayout layout, int y) {
+ super (layout, y, "Pad Longitude");
+ }
+ }
+
+ PadLon pad_lon;
+
+ class PadAlt extends LaunchValue {
+ void show (AltosState state, int crc_errors) {
+ value.setText(String.format("%4.0f m", state.pad_alt));
+ }
+ public PadAlt (GridBagLayout layout, int y) {
+ super (layout, y, "Pad Altitude");
+ }
+ }
+
+ PadAlt pad_alt;
+
+ public void reset() {
+ battery.reset();
+ apogee.reset();
+ main.reset();
+ gps_locked.reset();
+ gps_ready.reset();
+ pad_lat.reset();
+ pad_lon.reset();
+ pad_alt.reset();
+ }
+
+ public void show(AltosState state, int crc_errors) {
+ battery.show(state, crc_errors);
+ apogee.show(state, crc_errors);
+ main.show(state, crc_errors);
+ gps_locked.show(state, crc_errors);
+ gps_ready.show(state, crc_errors);
+ pad_lat.show(state, crc_errors);
+ pad_lon.show(state, crc_errors);
+ pad_alt.show(state, crc_errors);
+ }
+
+ public AltosPad() {
+ layout = new GridBagLayout();
+
+ setLayout(layout);
+
+ /* Elements in pad display:
+ *
+ * Battery voltage
+ * Igniter continuity
+ * GPS lock status
+ * GPS ready status
+ * GPS location
+ * Pad altitude
+ * RSSI
+ */
+ battery = new Battery(layout, 0);
+ apogee = new Apogee(layout, 1);
+ main = new Main(layout, 2);
+ gps_locked = new GPSLocked(layout, 3);
+ gps_ready = new GPSReady(layout, 4);
+ pad_lat = new PadLat(layout, 5);
+ pad_lon = new PadLon(layout, 6);
+ pad_alt = new PadAlt(layout, 7);
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.lang.*;
+
+public class AltosParse {
+ static boolean isdigit(char c) {
+ return '0' <= c && c <= '9';
+ }
+
+ static int parse_int(String v) throws ParseException {
+ try {
+ return Altos.fromdec(v);
+ } catch (NumberFormatException e) {
+ throw new ParseException("error parsing int " + v, 0);
+ }
+ }
+
+ static int parse_hex(String v) throws ParseException {
+ try {
+ return Altos.fromhex(v);
+ } catch (NumberFormatException e) {
+ throw new ParseException("error parsing hex " + v, 0);
+ }
+ }
+
+ static double parse_double(String v) throws ParseException {
+ try {
+ return Double.parseDouble(v);
+ } catch (NumberFormatException e) {
+ throw new ParseException("error parsing double " + v, 0);
+ }
+ }
+
+ static double parse_coord(String coord) throws ParseException {
+ String[] dsf = coord.split("\\D+");
+
+ if (dsf.length != 3) {
+ throw new ParseException("error parsing coord " + coord, 0);
+ }
+ int deg = parse_int(dsf[0]);
+ int min = parse_int(dsf[1]);
+ int frac = parse_int(dsf[2]);
+
+ double r = deg + (min + frac / 10000.0) / 60.0;
+ if (coord.endsWith("S") || coord.endsWith("W"))
+ r = -r;
+ return r;
+ }
+
+ static String strip_suffix(String v, String suffix) {
+ if (v.endsWith(suffix))
+ return v.substring(0, v.length() - suffix.length());
+ return v;
+ }
+
+ static void word(String v, String m) throws ParseException {
+ if (!v.equals(m)) {
+ throw new ParseException("error matching '" + v + "' '" + m + "'", 0);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.awt.Component;
+import javax.swing.*;
+import javax.swing.filechooser.FileSystemView;
+
+class AltosPreferences {
+ static Preferences preferences;
+
+ /* logdir preference name */
+ final static String logdirPreference = "LOGDIR";
+
+ /* channel preference name */
+ final static String channelPreferenceFormat = "CHANNEL-%d";
+
+ /* voice preference name */
+ final static String voicePreference = "VOICE";
+
+ /* callsign preference name */
+ final static String callsignPreference = "CALLSIGN";
+
+ /* firmware directory preference name */
+ final static String firmwaredirPreference = "FIRMWARE";
+
+ /* Default logdir is ~/TeleMetrum */
+ final static String logdirName = "TeleMetrum";
+
+ /* UI Component to pop dialogs up */
+ static Component component;
+
+ /* Log directory */
+ static File logdir;
+
+ /* Channel (map serial to channel) */
+ static Hashtable<Integer, Integer> channels;
+
+ /* Voice preference */
+ static boolean voice;
+
+ /* Callsign preference */
+ static String callsign;
+
+ /* Firmware directory */
+ static File firmwaredir;
+
+ public static void init(Component ui) {
+ preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
+
+ component = ui;
+
+ /* Initialize logdir from preferences */
+ String logdir_string = preferences.get(logdirPreference, null);
+ if (logdir_string != null)
+ logdir = new File(logdir_string);
+ else {
+ /* Use the file system view default directory */
+ logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName);
+ if (!logdir.exists())
+ logdir.mkdirs();
+ }
+
+ channels = new Hashtable<Integer,Integer>();
+
+ voice = preferences.getBoolean(voicePreference, true);
+
+ callsign = preferences.get(callsignPreference,"N0CALL");
+
+ String firmwaredir_string = preferences.get(firmwaredirPreference, null);
+ if (firmwaredir_string != null)
+ firmwaredir = new File(firmwaredir_string);
+ else
+ firmwaredir = null;
+ }
+
+ static void flush_preferences() {
+ try {
+ preferences.flush();
+ } catch (BackingStoreException ee) {
+ JOptionPane.showMessageDialog(component,
+ preferences.absolutePath(),
+ "Cannot save prefernces",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ public static void set_logdir(File new_logdir) {
+ logdir = new_logdir;
+ synchronized (preferences) {
+ preferences.put(logdirPreference, logdir.getPath());
+ flush_preferences();
+ }
+ }
+
+ private static boolean check_dir(File dir) {
+ if (!dir.exists()) {
+ if (!dir.mkdirs()) {
+ JOptionPane.showMessageDialog(component,
+ dir.getName(),
+ "Cannot create directory",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ } else if (!dir.isDirectory()) {
+ JOptionPane.showMessageDialog(component,
+ dir.getName(),
+ "Is not a directory",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ return true;
+ }
+
+ /* Configure the log directory. This is where all telemetry and eeprom files
+ * will be written to, and where replay will look for telemetry files
+ */
+ public static void ConfigureLog() {
+ JFileChooser logdir_chooser = new JFileChooser(logdir.getParentFile());
+
+ logdir_chooser.setDialogTitle("Configure Data Logging Directory");
+ logdir_chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+ if (logdir_chooser.showDialog(component, "Select Directory") == JFileChooser.APPROVE_OPTION) {
+ File dir = logdir_chooser.getSelectedFile();
+ if (check_dir(dir))
+ set_logdir(dir);
+ }
+ }
+
+ public static File logdir() {
+ return logdir;
+ }
+
+ public static void set_channel(int serial, int new_channel) {
+ channels.put(serial, new_channel);
+ synchronized (preferences) {
+ preferences.putInt(String.format(channelPreferenceFormat, serial), new_channel);
+ flush_preferences();
+ }
+ }
+
+ public static int channel(int serial) {
+ if (channels.containsKey(serial))
+ return channels.get(serial);
+ int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0);
+ channels.put(serial, channel);
+ return channel;
+ }
+
+ public static void set_voice(boolean new_voice) {
+ voice = new_voice;
+ synchronized (preferences) {
+ preferences.putBoolean(voicePreference, voice);
+ flush_preferences();
+ }
+ }
+
+ public static boolean voice() {
+ return voice;
+ }
+
+ public static void set_callsign(String new_callsign) {
+ callsign = new_callsign;
+ synchronized(preferences) {
+ preferences.put(callsignPreference, callsign);
+ flush_preferences();
+ }
+ }
+
+ public static String callsign() {
+ return callsign;
+ }
+
+ public static void set_firmwaredir(File new_firmwaredir) {
+ firmwaredir = new_firmwaredir;
+ synchronized (preferences) {
+ preferences.put(firmwaredirPreference, firmwaredir.getPath());
+ flush_preferences();
+ }
+ }
+
+ public static File firmwaredir() {
+ return firmwaredir;
+ }
+}
--- /dev/null
+/*
+ * 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.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosReader {
+ public AltosRecord read() throws IOException, ParseException { return null; }
+ public void close() { }
+ public void write_comments(PrintStream out) { }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.util.HashMap;
+import java.io.*;
+
+public class AltosRecord {
+ int version;
+ String callsign;
+ int serial;
+ int flight;
+ int rssi;
+ int status;
+ int state;
+ int tick;
+ int accel;
+ int pres;
+ int temp;
+ int batt;
+ int drogue;
+ int main;
+ int flight_accel;
+ int ground_accel;
+ int flight_vel;
+ int flight_pres;
+ int ground_pres;
+ int accel_plus_g;
+ int accel_minus_g;
+ AltosGPS gps;
+
+ double time; /* seconds since boost */
+
+ /*
+ * Values for our MP3H6115A pressure sensor
+ *
+ * From the data sheet:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ *
+ * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
+ * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
+ */
+
+ static final double counts_per_kPa = 27 * 2047 / 3300;
+ static final double counts_at_101_3kPa = 1674.0;
+
+ static double
+ barometer_to_pressure(double count)
+ {
+ return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
+ }
+
+ public double raw_pressure() {
+ return barometer_to_pressure(pres);
+ }
+
+ public double filtered_pressure() {
+ return barometer_to_pressure(flight_pres);
+ }
+
+ public double ground_pressure() {
+ return barometer_to_pressure(ground_pres);
+ }
+
+ public double filtered_altitude() {
+ return AltosConvert.pressure_to_altitude(filtered_pressure());
+ }
+
+ public double raw_altitude() {
+ return AltosConvert.pressure_to_altitude(raw_pressure());
+ }
+
+ public double ground_altitude() {
+ return AltosConvert.pressure_to_altitude(ground_pressure());
+ }
+
+ public double filtered_height() {
+ return filtered_altitude() - ground_altitude();
+ }
+
+ public double raw_height() {
+ return raw_altitude() - ground_altitude();
+ }
+
+ public double battery_voltage() {
+ return AltosConvert.cc_battery_to_voltage(batt);
+ }
+
+ public double main_voltage() {
+ return AltosConvert.cc_ignitor_to_voltage(main);
+ }
+
+ public double drogue_voltage() {
+ return AltosConvert.cc_ignitor_to_voltage(drogue);
+ }
+
+ /* Value for the CC1111 built-in temperature sensor
+ * Output voltage at 0°C = 0.755V
+ * Coefficient = 0.00247V/°C
+ * Reference voltage = 1.25V
+ *
+ * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
+ * = (value - 19791.268) / 32768 * 1.25 / 0.00247
+ */
+
+ static double
+ thermometer_to_temperature(double thermo)
+ {
+ return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
+ }
+
+ public double temperature() {
+ return thermometer_to_temperature(temp);
+ }
+
+ double accel_counts_per_mss() {
+ double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
+
+ return counts_per_g / 9.80665;
+ }
+ public double acceleration() {
+ return (ground_accel - accel) / accel_counts_per_mss();
+ }
+
+ public double accel_speed() {
+ double speed = flight_vel / (accel_counts_per_mss() * 100.0);
+ return speed;
+ }
+
+ public String state() {
+ return Altos.state_name(state);
+ }
+
+ public static String gets(FileInputStream s) throws IOException {
+ int c;
+ String line = "";
+
+ while ((c = s.read()) != -1) {
+ if (c == '\r')
+ continue;
+ if (c == '\n') {
+ return line;
+ }
+ line = line + (char) c;
+ }
+ return null;
+ }
+
+ public AltosRecord(AltosRecord old) {
+ version = old.version;
+ callsign = old.callsign;
+ serial = old.serial;
+ flight = old.flight;
+ rssi = old.rssi;
+ status = old.status;
+ state = old.state;
+ tick = old.tick;
+ accel = old.accel;
+ pres = old.pres;
+ temp = old.temp;
+ batt = old.batt;
+ drogue = old.drogue;
+ main = old.main;
+ flight_accel = old.flight_accel;
+ ground_accel = old.ground_accel;
+ flight_vel = old.flight_vel;
+ flight_pres = old.flight_pres;
+ ground_pres = old.ground_pres;
+ accel_plus_g = old.accel_plus_g;
+ accel_minus_g = old.accel_minus_g;
+ gps = new AltosGPS(old.gps);
+ }
+
+ public AltosRecord() {
+ version = 0;
+ callsign = "N0CALL";
+ serial = 0;
+ flight = 0;
+ rssi = 0;
+ status = 0;
+ state = Altos.ao_flight_startup;
+ tick = 0;
+ accel = 0;
+ pres = 0;
+ temp = 0;
+ batt = 0;
+ drogue = 0;
+ main = 0;
+ flight_accel = 0;
+ ground_accel = 0;
+ flight_vel = 0;
+ flight_pres = 0;
+ ground_pres = 0;
+ accel_plus_g = 0;
+ accel_minus_g = 0;
+ gps = new AltosGPS();
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public abstract class AltosRecordIterable implements Iterable<AltosRecord> {
+ public abstract Iterator<AltosRecord> iterator();
+ public void write_comments(PrintStream out) { }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/*
+ * Open an existing telemetry file and replay it in realtime
+ */
+
+public class AltosReplayReader extends AltosFlightReader {
+ Iterator<AltosRecord> iterator;
+
+ public AltosRecord read() {
+ if (iterator.hasNext())
+ return iterator.next();
+ return null;
+ }
+
+ public void close (boolean interrupted) {
+ }
+
+ void update(AltosState state) throws InterruptedException {
+ /* Make it run in realtime after the rocket leaves the pad */
+ if (state.state > Altos.ao_flight_pad)
+ Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
+ }
+
+ public AltosReplayReader(Iterator<AltosRecord> in_iterator, String in_name) {
+ iterator = in_iterator;
+ name = in_name;
+ }
+}
--- /dev/null
+/*
+ * 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.io.*;
+
+public class AltosRomconfig {
+ public boolean valid;
+ public int version;
+ public int check;
+ public int serial_number;
+ public int radio_calibration;
+
+ static int get_int(byte[] bytes, int start, int len) {
+ int v = 0;
+ int o = 0;
+ while (len > 0) {
+ v = v | ((((int) bytes[start]) & 0xff) << o);
+ start++;
+ len--;
+ o += 8;
+ }
+ return v;
+ }
+
+ static void put_int(int value, byte[] bytes, int start, int len) {
+ while (len > 0) {
+ bytes[start] = (byte) (value & 0xff);
+ start++;
+ len--;
+ value >>= 8;
+ }
+ }
+
+ static void put_string(String value, byte[] bytes, int start) {
+ for (int i = 0; i < value.length(); i++)
+ bytes[start + i] = (byte) value.charAt(i);
+ }
+
+ static final int AO_USB_DESC_STRING = 3;
+
+ static void put_usb_serial(int value, byte[] bytes, int start) {
+ int offset = start + 0xa;
+ int string_num = 0;
+
+ while (offset < bytes.length && bytes[offset] != 0) {
+ if (bytes[offset + 1] == AO_USB_DESC_STRING) {
+ ++string_num;
+ if (string_num == 4)
+ break;
+ }
+ offset += ((int) bytes[offset]) & 0xff;
+ }
+ if (offset >= bytes.length || bytes[offset] == 0)
+ return;
+ int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
+ String fmt = String.format("%%0%dd", len);
+
+ String s = String.format(fmt, value);
+ if (s.length() != len) {
+ System.out.printf("weird usb length issue %s isn't %d\n",
+ s, len);
+ return;
+ }
+ for (int i = 0; i < len; i++) {
+ bytes[offset + 2 + i*2] = (byte) s.charAt(i);
+ bytes[offset + 2 + i*2+1] = 0;
+ }
+ }
+
+ public AltosRomconfig(byte[] bytes, int offset) {
+ version = get_int(bytes, offset + 0, 2);
+ check = get_int(bytes, offset + 2, 2);
+ if (check == (~version & 0xffff)) {
+ switch (version) {
+ case 2:
+ case 1:
+ serial_number = get_int(bytes, offset + 4, 2);
+ radio_calibration = get_int(bytes, offset + 6, 4);
+ valid = true;
+ break;
+ }
+ }
+ }
+
+ public AltosRomconfig(AltosHexfile hexfile) {
+ this(hexfile.data, 0xa0 - hexfile.address);
+ }
+
+ public void write(byte[] bytes, int offset) throws IOException {
+ if (!valid)
+ throw new IOException("rom configuration invalid");
+
+ if (offset < 0 || bytes.length < offset + 10)
+ throw new IOException("image cannot contain rom config");
+
+ AltosRomconfig existing = new AltosRomconfig(bytes, offset);
+ if (!existing.valid)
+ throw new IOException("image does not contain existing rom config");
+
+ switch (existing.version) {
+ case 2:
+ put_usb_serial(serial_number, bytes, offset);
+ case 1:
+ put_int(serial_number, bytes, offset + 4, 2);
+ put_int(radio_calibration, bytes, offset + 6, 4);
+ break;
+ }
+ }
+
+ public void write (AltosHexfile hexfile) throws IOException {
+ write(hexfile.data, 0xa0 - hexfile.address);
+ AltosRomconfig check = new AltosRomconfig(hexfile);
+ if (!check.valid())
+ throw new IOException("writing new rom config failed\n");
+ }
+
+ public AltosRomconfig(int in_serial_number, int in_radio_calibration) {
+ valid = true;
+ version = 1;
+ check = (~version & 0xffff);
+ serial_number = in_serial_number;
+ radio_calibration = in_radio_calibration;
+ }
+
+ public boolean valid() {
+ return valid && serial_number != 0;
+ }
+
+ public AltosRomconfig() {
+ valid = false;
+ }
+}
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+
+public class AltosRomconfigUI
+ extends JDialog
+ implements ActionListener
+{
+ Container pane;
+ Box box;
+ JLabel serial_label;
+ JLabel radio_calibration_label;
+
+ JFrame owner;
+ JTextField serial_value;
+ JTextField radio_calibration_value;
+
+ JButton ok;
+ JButton cancel;
+
+ /* Build the UI using a grid bag */
+ public AltosRomconfigUI(JFrame in_owner) {
+ super (in_owner, "Configure TeleMetrum Rom Values", true);
+
+ owner = in_owner;
+ GridBagConstraints c;
+
+ Insets il = new Insets(4,4,4,4);
+ Insets ir = new Insets(4,4,4,4);
+
+ pane = getContentPane();
+ pane.setLayout(new GridBagLayout());
+
+ /* Serial */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 0;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ serial_label = new JLabel("Serial:");
+ pane.add(serial_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 3; c.gridy = 0;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ serial_value = new JTextField("0");
+ pane.add(serial_value, c);
+
+ /* Radio calibration value */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 1;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = il;
+ c.ipady = 5;
+ radio_calibration_label = new JLabel("Radio Calibration:");
+ pane.add(radio_calibration_label, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 3; c.gridy = 1;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1;
+ c.anchor = GridBagConstraints.LINE_START;
+ c.insets = ir;
+ c.ipady = 5;
+ radio_calibration_value = new JTextField("1186611");
+ pane.add(radio_calibration_value, c);
+
+ /* Buttons */
+ c = new GridBagConstraints();
+ c.gridx = 0; c.gridy = 2;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = il;
+ ok = new JButton("OK");
+ pane.add(ok, c);
+ ok.addActionListener(this);
+ ok.setActionCommand("ok");
+
+ c = new GridBagConstraints();
+ c.gridx = 3; c.gridy = 2;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = il;
+ cancel = new JButton("Cancel");
+ pane.add(cancel, c);
+ cancel.addActionListener(this);
+ cancel.setActionCommand("cancel");
+
+ pack();
+ setLocationRelativeTo(owner);
+ }
+
+ boolean selected;
+
+ /* Listen for events from our buttons */
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+
+ if (cmd.equals("ok")) {
+ AltosRomconfig romconfig = romconfig();
+ if (romconfig == null || !romconfig.valid()) {
+ JOptionPane.showMessageDialog(this,
+ "Invalid serial number or radio calibration value",
+ "Invalid rom configuration",
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ selected = true;
+ }
+ setVisible(false);
+ }
+
+ int serial() {
+ return Integer.parseInt(serial_value.getText());
+ }
+
+ void set_serial(int serial) {
+ serial_value.setText(String.format("%d", serial));
+ }
+
+ int radio_calibration() {
+ return Integer.parseInt(radio_calibration_value.getText());
+ }
+
+ void set_radio_calibration(int calibration) {
+ radio_calibration_value.setText(String.format("%d", calibration));
+ }
+
+ public void set(AltosRomconfig config) {
+ if (config != null && config.valid()) {
+ set_serial(config.serial_number);
+ set_radio_calibration(config.radio_calibration);
+ }
+ }
+
+ AltosRomconfig romconfig() {
+ try {
+ return new AltosRomconfig(serial(), radio_calibration());
+ } catch (NumberFormatException ne) {
+ return null;
+ }
+ }
+
+ public AltosRomconfig showDialog() {
+ setVisible(true);
+ if (selected)
+ return romconfig();
+ return null;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ * Deal with TeleDongle on a serial port
+ */
+
+package altosui;
+
+import java.lang.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+
+import libaltosJNI.*;
+
+/*
+ * 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.
+ */
+
+public class AltosSerial implements Runnable {
+
+ static List<String> devices_opened = Collections.synchronizedList(new LinkedList<String>());
+
+ AltosDevice device;
+ SWIGTYPE_p_altos_file altos;
+ LinkedList<LinkedBlockingQueue<AltosLine>> monitors;
+ LinkedBlockingQueue<AltosLine> reply_queue;
+ Thread input_thread;
+ String line;
+ byte[] line_bytes;
+ int line_count;
+ boolean monitor_mode;
+
+ public void run () {
+ int c;
+
+ try {
+ for (;;) {
+ c = libaltos.altos_getchar(altos, 0);
+ if (Thread.interrupted())
+ break;
+ if (c == libaltosConstants.LIBALTOS_ERROR) {
+ for (int e = 0; e < monitors.size(); e++) {
+ LinkedBlockingQueue<AltosLine> q = monitors.get(e);
+ q.put(new AltosLine());
+ }
+ reply_queue.put (new AltosLine());
+ break;
+ }
+ if (c == libaltosConstants.LIBALTOS_TIMEOUT)
+ continue;
+ if (c == '\r')
+ continue;
+ synchronized(this) {
+ if (c == '\n') {
+ if (line_count != 0) {
+ try {
+ line = new String(line_bytes, 0, line_count, "UTF-8");
+ } catch (UnsupportedEncodingException ue) {
+ line = "";
+ for (int i = 0; i < line_count; i++)
+ line = line + line_bytes[i];
+ }
+ if (line.startsWith("VERSION") || line.startsWith("CRC")) {
+ for (int e = 0; e < monitors.size(); e++) {
+ LinkedBlockingQueue<AltosLine> q = monitors.get(e);
+ q.put(new AltosLine (line));
+ }
+ } else {
+// System.out.printf("GOT: %s\n", line);
+ reply_queue.put(new AltosLine (line));
+ }
+ line_count = 0;
+ line = "";
+ }
+ } 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 void flush_output() {
+ if (altos != null)
+ libaltos.altos_flush(altos);
+ }
+
+ public void flush_input() {
+ flush_output();
+ boolean got_some;
+ do {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ }
+ got_some = !reply_queue.isEmpty();
+ synchronized(this) {
+ if (!"VERSION".startsWith(line) &&
+ !line.startsWith("VERSION"))
+ line = "";
+ reply_queue.clear();
+ }
+ } while (got_some);
+ }
+
+ public String get_reply() throws InterruptedException {
+ flush_output();
+ AltosLine line = reply_queue.take();
+ return line.line;
+ }
+
+ public String get_reply(int timeout) throws InterruptedException {
+ flush_output();
+ AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS);
+ if (line == null)
+ return null;
+ return line.line;
+ }
+
+ public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+ set_monitor(true);
+ monitors.add(q);
+ }
+
+ public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
+ monitors.remove(q);
+ if (monitors.isEmpty())
+ set_monitor(false);
+ }
+
+ public void close() {
+ if (altos != null) {
+ libaltos.altos_close(altos);
+ }
+ if (input_thread != null) {
+ try {
+ input_thread.interrupt();
+ input_thread.join();
+ } catch (InterruptedException e) {
+ }
+ input_thread = null;
+ }
+ if (altos != null) {
+ libaltos.altos_free(altos);
+ altos = null;
+ }
+ synchronized (devices_opened) {
+ devices_opened.remove(device.getPath());
+ }
+ }
+
+ public void putc(char c) {
+ if (altos != null)
+ libaltos.altos_putchar(altos, c);
+ }
+
+ public void print(String data) {
+// System.out.printf("\"%s\" ", data);
+ for (int i = 0; i < data.length(); i++)
+ putc(data.charAt(i));
+ }
+
+ public void printf(String format, Object ... arguments) {
+ print(String.format(format, arguments));
+ }
+
+ private void open() throws FileNotFoundException, AltosSerialInUseException {
+ synchronized (devices_opened) {
+ if (devices_opened.contains(device.getPath()))
+ throw new AltosSerialInUseException(device);
+ devices_opened.add(device.getPath());
+ }
+ altos = libaltos.altos_open(device);
+ if (altos == null) {
+ close();
+ throw new FileNotFoundException(device.toShortString());
+ }
+ input_thread = new Thread(this);
+ input_thread.start();
+ print("~\nE 0\n");
+ set_monitor(false);
+ flush_output();
+ }
+
+ public void set_radio() {
+ set_channel(AltosPreferences.channel(device.getSerial()));
+ set_callsign(AltosPreferences.callsign());
+ }
+
+ public void set_channel(int channel) {
+ if (altos != null) {
+ if (monitor_mode)
+ printf("m 0\nc r %d\nm 1\n", channel);
+ else
+ printf("c r %d\n", channel);
+ flush_output();
+ }
+ }
+
+ void set_monitor(boolean monitor) {
+ monitor_mode = monitor;
+ if (altos != null) {
+ if (monitor)
+ printf("m 1\n");
+ else
+ printf("m 0\n");
+ flush_output();
+ }
+ }
+
+ public void set_callsign(String callsign) {
+ if (altos != null) {
+ printf ("c c %s\n", callsign);
+ flush_output();
+ }
+ }
+
+ public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
+ device = in_device;
+ line = "";
+ monitor_mode = false;
+ monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();
+ reply_queue = new LinkedBlockingQueue<AltosLine> ();
+ open();
+ }
+}
--- /dev/null
+/*
+ * 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 libaltosJNI.*;
+
+public class AltosSerialInUseException extends Exception {
+ public altos_device device;
+
+ public AltosSerialInUseException (altos_device in_device) {
+ device = in_device;
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public interface AltosSerialMonitor {
+ void data(String data);
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+import javax.imageio.ImageIO;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.lang.Math;
+import java.awt.geom.Point2D;
+import java.awt.geom.Line2D;
+
+public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
+ // preferred vertical step in a tile in naut. miles
+ // will actually choose a step size between x and 2x, where this
+ // is 1.5x
+ static final double tile_size_nmi = 0.75;
+
+ static final int px_size = 512;
+
+ static final int MAX_TILE_DELTA = 100;
+
+ private static Point2D.Double translatePoint(Point2D.Double p,
+ Point2D.Double d)
+ {
+ return new Point2D.Double(p.x + d.x, p.y + d.y);
+ }
+
+ static class LatLng {
+ public double lat, lng;
+ public LatLng(double lat, double lng) {
+ this.lat = lat;
+ this.lng = lng;
+ }
+ }
+
+ // based on google js
+ // http://maps.gstatic.com/intl/en_us/mapfiles/api-3/2/10/main.js
+ // search for fromLatLngToPoint and fromPointToLatLng
+ private static Point2D.Double pt(LatLng latlng, int zoom) {
+ double scale_x = 256/360.0 * Math.pow(2, zoom);
+ double scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
+ return pt(latlng, scale_x, scale_y);
+ }
+
+ private static Point2D.Double pt(LatLng latlng,
+ double scale_x, double scale_y)
+ {
+ Point2D.Double res = new Point2D.Double();
+ double e;
+
+ res.x = latlng.lng * scale_x;
+
+ e = Math.sin(Math.toRadians(latlng.lat));
+ e = Math.max(e,-(1-1.0E-15));
+ e = Math.min(e, 1-1.0E-15 );
+
+ res.y = 0.5*Math.log((1+e)/(1-e))*-scale_y;
+ return res;
+ }
+
+ static private LatLng latlng(Point2D.Double pt,
+ double scale_x, double scale_y)
+ {
+ double lat, lng;
+ double rads;
+
+ lng = pt.x/scale_x;
+ rads = 2 * Math.atan(Math.exp(-pt.y/scale_y));
+ lat = Math.toDegrees(rads - Math.PI/2);
+
+ return new LatLng(lat,lng);
+ }
+
+ int zoom;
+ double scale_x, scale_y;
+
+ private Point2D.Double pt(double lat, double lng) {
+ return pt(new LatLng(lat, lng), scale_x, scale_y);
+ }
+
+ private LatLng latlng(double x, double y) {
+ return latlng(new Point2D.Double(x,y), scale_x, scale_y);
+ }
+ private LatLng latlng(Point2D.Double pt) {
+ return latlng(pt, scale_x, scale_y);
+ }
+
+ HashMap<Point,AltosSiteMapTile> mapTiles = new HashMap<Point,AltosSiteMapTile>();
+ Point2D.Double centre;
+
+ private Point2D.Double tileCoordOffset(Point p) {
+ return new Point2D.Double(centre.x - p.x*px_size,
+ centre.y - p.y * px_size);
+ }
+
+ private Point tileOffset(Point2D.Double p) {
+ return new Point((int)Math.floor((centre.x+p.x)/px_size),
+ (int)Math.floor((centre.y+p.y)/px_size));
+ }
+
+ private Point2D.Double getBaseLocation(double lat, double lng) {
+ Point2D.Double locn, north_step;
+
+ zoom = 2;
+ // stupid loop structure to please Java's control flow analysis
+ do {
+ zoom++;
+ scale_x = 256/360.0 * Math.pow(2, zoom);
+ scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
+ locn = pt(lat, lng);
+ north_step = pt(lat+tile_size_nmi*4/3/60.0, lng);
+ if (locn.y - north_step.y > px_size)
+ break;
+ } while (zoom < 22);
+ locn.x = -px_size * Math.floor(locn.x/px_size);
+ locn.y = -px_size * Math.floor(locn.y/px_size);
+ return locn;
+ }
+
+ public void reset() {
+ // nothing
+ }
+
+ private void bgLoadMap(final AltosSiteMapTile tile,
+ final File pngfile, final String pngurl)
+ {
+ //System.out.printf("Loading/fetching map %s\n", pngfile);
+ Thread thread = new Thread() {
+ public void run() {
+ ImageIcon res;
+ res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl);
+ if (res != null) {
+ tile.loadMap(res);
+ } else {
+ System.out.printf("# Failed to fetch file %s\n", pngfile);
+ System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl);
+ }
+ }
+ };
+ thread.start();
+ }
+
+ public static void prefetchMaps(double lat, double lng, int w, int h) {
+ AltosPreferences.init(null);
+
+ AltosSiteMap asm = new AltosSiteMap(true);
+ asm.centre = asm.getBaseLocation(lat, lng);
+
+ Point2D.Double p = new Point2D.Double();
+ Point2D.Double p2;
+ int dx = -w/2, dy = -h/2;
+ for (int y = dy; y < h+dy; y++) {
+ for (int x = dx; x < w+dx; x++) {
+ LatLng map_latlng = asm.latlng(
+ -asm.centre.x + x*px_size + px_size/2,
+ -asm.centre.y + y*px_size + px_size/2);
+ File pngfile = asm.MapFile(map_latlng.lat, map_latlng.lng);
+ String pngurl = asm.MapURL(map_latlng.lat, map_latlng.lng);
+ if (pngfile.exists()) {
+ System.out.printf("Already have %s\n", pngfile);
+ } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) {
+ System.out.printf("Fetched map %s\n", pngfile);
+ } else {
+ System.out.printf("# Failed to fetch file %s\n", pngfile);
+ System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl);
+ }
+ }
+ }
+ }
+
+ private void initMap(AltosSiteMapTile tile, Point offset) {
+ Point2D.Double coord = tileCoordOffset(offset);
+
+ LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y);
+
+ File pngfile = MapFile(map_latlng.lat, map_latlng.lng);
+ String pngurl = MapURL(map_latlng.lat, map_latlng.lng);
+ bgLoadMap(tile, pngfile, pngurl);
+ }
+
+ private void initMaps(double lat, double lng) {
+ centre = getBaseLocation(lat, lng);
+
+ for (Point k : mapTiles.keySet()) {
+ initMap(mapTiles.get(k), k);
+ }
+ }
+
+ private File MapFile(double lat, double lng) {
+ char chlat = lat < 0 ? 'S' : 'N';
+ char chlng = lng < 0 ? 'E' : 'W';
+ if (lat < 0) lat = -lat;
+ if (lng < 0) lng = -lng;
+ return new File(AltosPreferences.logdir(),
+ String.format("map-%c%.6f,%c%.6f-%d.png",
+ chlat, lat, chlng, lng, zoom));
+ }
+
+ private String MapURL(double lat, double lng) {
+ return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=hybrid&format=png32", lat, lng, zoom, px_size, px_size);
+ }
+
+ boolean initialised = false;
+ Point2D.Double last_pt = null;
+ int last_state = -1;
+ public void show(final AltosState state, final int crc_errors) {
+ // if insufficient gps data, nothing to update
+ if (state.gps == null)
+ return;
+ if (state.pad_lat == 0 && state.pad_lon == 0)
+ return;
+ if (!state.gps.locked) {
+ if (state.gps.nsat < 4)
+ return;
+ }
+
+ if (!initialised) {
+ initMaps(state.pad_lat, state.pad_lon);
+ initialised = true;
+ }
+
+ final Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
+ if (last_pt == pt && last_state == state.state)
+ return;
+
+ if (last_pt == null) {
+ last_pt = pt;
+ }
+ boolean in_any = false;
+ for (Point offset : mapTiles.keySet()) {
+ AltosSiteMapTile tile = mapTiles.get(offset);
+ Point2D.Double ref, lref;
+ ref = translatePoint(pt, tileCoordOffset(offset));
+ lref = translatePoint(last_pt, tileCoordOffset(offset));
+ tile.show(state, crc_errors, lref, ref);
+ if (0 <= ref.x && ref.x < px_size)
+ if (0 <= ref.y && ref.y < px_size)
+ in_any = true;
+ }
+
+ Point offset = tileOffset(pt);
+ if (!in_any) {
+ Point2D.Double ref, lref;
+ ref = translatePoint(pt, tileCoordOffset(offset));
+ lref = translatePoint(last_pt, tileCoordOffset(offset));
+
+ AltosSiteMapTile tile = createTile(offset);
+ tile.show(state, crc_errors, lref, ref);
+ initMap(tile, offset);
+ finishTileLater(tile, offset);
+ }
+
+ scrollRocketToVisible(pt);
+
+ if (offset != tileOffset(last_pt)) {
+ ensureTilesAround(offset);
+ }
+
+ last_pt = pt;
+ last_state = state.state;
+ }
+
+ private AltosSiteMapTile createTile(Point offset) {
+ AltosSiteMapTile tile = new AltosSiteMapTile(px_size);
+ mapTiles.put(offset, tile);
+ return tile;
+ }
+ private void finishTileLater(final AltosSiteMapTile tile,
+ final Point offset)
+ {
+ SwingUtilities.invokeLater( new Runnable() {
+ public void run() {
+ addTileAt(tile, offset);
+ }
+ } );
+ }
+
+ private void ensureTilesAround(Point base_offset) {
+ for (int x = -1; x <= 1; x++) {
+ for (int y = -1; y <= 1; y++) {
+ Point offset = new Point(base_offset.x + x, base_offset.y + y);
+ if (mapTiles.containsKey(offset))
+ continue;
+ AltosSiteMapTile tile = createTile(offset);
+ initMap(tile, offset);
+ finishTileLater(tile, offset);
+ }
+ }
+ }
+
+ private Point topleft = new Point(0,0);
+ private void scrollRocketToVisible(Point2D.Double pt) {
+ Rectangle r = comp.getVisibleRect();
+ Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft));
+ int dx = (int)copt.x - r.width/2 - r.x;
+ int dy = (int)copt.y - r.height/2 - r.y;
+ if (Math.abs(dx) > r.width/4 || Math.abs(dy) > r.height/4) {
+ r.x += dx;
+ r.y += dy;
+ comp.scrollRectToVisible(r);
+ }
+ }
+
+ private void addTileAt(AltosSiteMapTile tile, Point offset) {
+ if (Math.abs(offset.x) >= MAX_TILE_DELTA ||
+ Math.abs(offset.y) >= MAX_TILE_DELTA)
+ {
+ System.out.printf("Rocket too far away from pad (tile %d,%d)\n",
+ offset.x, offset.y);
+ return;
+ }
+
+ boolean review = false;
+ Rectangle r = comp.getVisibleRect();
+ if (offset.x < topleft.x) {
+ r.x += (topleft.x - offset.x) * px_size;
+ topleft.x = offset.x;
+ review = true;
+ }
+ if (offset.y < topleft.y) {
+ r.y += (topleft.y - offset.y) * px_size;
+ topleft.y = offset.y;
+ review = true;
+ }
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.BOTH;
+ // put some space between the map tiles, debugging only
+ // c.insets = new Insets(5, 5, 5, 5);
+
+ c.gridx = offset.x + MAX_TILE_DELTA;
+ c.gridy = offset.y + MAX_TILE_DELTA;
+ layout.setConstraints(tile, c);
+
+ comp.add(tile);
+ if (review) {
+ comp.scrollRectToVisible(r);
+ }
+ }
+
+ private AltosSiteMap(boolean knowWhatYouAreDoing) {
+ if (!knowWhatYouAreDoing) {
+ throw new RuntimeException("Arggh.");
+ }
+ }
+
+ JComponent comp = new JComponent() { };
+ private GridBagLayout layout = new GridBagLayout();
+
+ public AltosSiteMap() {
+ GrabNDrag scroller = new GrabNDrag(comp);
+
+ comp.setLayout(layout);
+
+ for (int x = -1; x <= 1; x++) {
+ for (int y = -1; y <= 1; y++) {
+ Point offset = new Point(x, y);
+ AltosSiteMapTile t = createTile(offset);
+ addTileAt(t, offset);
+ }
+ }
+ setViewportView(comp);
+ setPreferredSize(new Dimension(500,200));
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.imageio.ImageIO;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.net.URL;
+import java.net.URLConnection;
+
+public class AltosSiteMapCache extends JLabel {
+ public static boolean fetchMap(File file, String url) {
+ URL u;
+
+ try {
+ u = new URL(url);
+ } catch (java.net.MalformedURLException e) {
+ return false;
+ }
+
+ byte[] data;
+ try {
+ URLConnection uc = u.openConnection();
+ int contentLength = uc.getContentLength();
+ InputStream in = new BufferedInputStream(uc.getInputStream());
+ int bytesRead = 0;
+ int offset = 0;
+ data = new byte[contentLength];
+ while (offset < contentLength) {
+ bytesRead = in.read(data, offset, data.length - offset);
+ if (bytesRead == -1)
+ break;
+ offset += bytesRead;
+ }
+ in.close();
+
+ if (offset != contentLength) {
+ return false;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+
+ try {
+ FileOutputStream out = new FileOutputStream(file);
+ out.write(data);
+ out.flush();
+ out.close();
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ if (file.exists()) {
+ file.delete();
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public static ImageIcon fetchAndLoadMap(File pngfile, String url) {
+ if (!pngfile.exists()) {
+ if (!fetchMap(pngfile, url)) {
+ return null;
+ }
+ }
+ return loadMap(pngfile, url);
+ }
+
+ public static ImageIcon loadMap(File pngfile, String url) {
+ if (!pngfile.exists()) {
+ return null;
+ }
+
+ try {
+ return new ImageIcon(ImageIO.read(pngfile));
+ } catch (IOException e) {
+ System.out.printf("# IO error trying to load %s\n", pngfile);
+ return null;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.imageio.ImageIO;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.lang.Math;
+import java.awt.geom.Point2D;
+import java.awt.geom.Line2D;
+
+public class AltosSiteMapTile extends JLayeredPane {
+ JLabel mapLabel;
+ JLabel draw;
+ Graphics2D g2d;
+
+ public void loadMap(ImageIcon icn) {
+ mapLabel.setIcon(icn);
+ }
+
+ static Color stateColors[] = {
+ Color.WHITE, // startup
+ Color.WHITE, // idle
+ Color.WHITE, // pad
+ Color.RED, // boost
+ Color.PINK, // fast
+ Color.YELLOW, // coast
+ Color.CYAN, // drogue
+ Color.BLUE, // main
+ Color.BLACK // landed
+ };
+
+ private boolean drawn_landed_circle = false;
+ private boolean drawn_boost_circle = false;
+ public synchronized void show(AltosState state, int crc_errors,
+ Point2D.Double last_pt, Point2D.Double pt)
+ {
+ if (0 <= state.state && state.state < stateColors.length) {
+ g2d.setColor(stateColors[state.state]);
+ }
+ g2d.draw(new Line2D.Double(last_pt, pt));
+
+ if (state.state == 3 && !drawn_boost_circle) {
+ drawn_boost_circle = true;
+ g2d.setColor(Color.RED);
+ g2d.drawOval((int)last_pt.x-5, (int)last_pt.y-5, 10, 10);
+ g2d.drawOval((int)last_pt.x-20, (int)last_pt.y-20, 40, 40);
+ g2d.drawOval((int)last_pt.x-35, (int)last_pt.y-35, 70, 70);
+ }
+ if (state.state == 8 && !drawn_landed_circle) {
+ drawn_landed_circle = true;
+ g2d.setColor(Color.BLACK);
+ g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10);
+ g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40);
+ g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70);
+ }
+
+ repaint();
+ }
+
+ public static Graphics2D fillLabel(JLabel l, Color c, int px_size) {
+ BufferedImage img = new BufferedImage(px_size, px_size,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = img.createGraphics();
+ g.setColor(c);
+ g.fillRect(0, 0, px_size, px_size);
+ l.setIcon(new ImageIcon(img));
+ return g;
+ }
+
+ public AltosSiteMapTile(int px_size) {
+ setPreferredSize(new Dimension(px_size, px_size));
+
+ mapLabel = new JLabel();
+ fillLabel(mapLabel, Color.GRAY, px_size);
+ mapLabel.setOpaque(true);
+ mapLabel.setBounds(0, 0, px_size, px_size);
+ add(mapLabel, new Integer(0));
+
+ draw = new JLabel();
+ g2d = fillLabel(draw, new Color(127, 127, 127, 0), px_size);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ draw.setBounds(0, 0, px_size, px_size);
+ draw.setOpaque(false);
+
+ add(draw, new Integer(1));
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ * Track flight state from telemetry or eeprom data stream
+ */
+
+package altosui;
+
+public class AltosState {
+ AltosRecord data;
+
+ /* derived data */
+
+ long report_time;
+
+ double time_change;
+ int tick;
+
+ int state;
+ boolean landed;
+ boolean ascent; /* going up? */
+
+ double ground_altitude;
+ double height;
+ double speed;
+ double acceleration;
+ double battery;
+ double temperature;
+ double main_sense;
+ double drogue_sense;
+ double baro_speed;
+
+ double max_height;
+ double max_acceleration;
+ double max_speed;
+
+ AltosGPS gps;
+
+ double pad_lat;
+ double pad_lon;
+ double pad_alt;
+
+ static final int MIN_PAD_SAMPLES = 10;
+
+ int npad;
+ int ngps;
+ int gps_waiting;
+ boolean gps_ready;
+
+ AltosGreatCircle from_pad;
+ double elevation; /* from pad */
+ double range; /* total distance */
+
+ double gps_height;
+
+ int speak_tick;
+ double speak_altitude;
+
+
+ void init (AltosRecord cur, AltosState prev_state) {
+ int i;
+ AltosRecord prev;
+
+ data = cur;
+
+ ground_altitude = data.ground_altitude();
+ height = data.filtered_altitude() - ground_altitude;
+
+ report_time = System.currentTimeMillis();
+
+ acceleration = data.acceleration();
+ speed = data.accel_speed();
+ temperature = data.temperature();
+ drogue_sense = data.drogue_voltage();
+ main_sense = data.main_voltage();
+ battery = data.battery_voltage();
+ tick = data.tick;
+ state = data.state;
+
+ if (prev_state != null) {
+
+ /* Preserve any existing gps data */
+ npad = prev_state.npad;
+ ngps = prev_state.ngps;
+ gps = prev_state.gps;
+ pad_lat = prev_state.pad_lat;
+ pad_lon = prev_state.pad_lon;
+ pad_alt = prev_state.pad_alt;
+ max_height = prev_state.max_height;
+ max_acceleration = prev_state.max_acceleration;
+ max_speed = prev_state.max_speed;
+
+ /* make sure the clock is monotonic */
+ while (tick < prev_state.tick)
+ tick += 65536;
+
+ time_change = (tick - prev_state.tick) / 100.0;
+
+ /* compute barometric speed */
+
+ double height_change = height - prev_state.height;
+ if (time_change > 0)
+ baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;
+ else
+ baro_speed = prev_state.baro_speed;
+ } else {
+ npad = 0;
+ ngps = 0;
+ gps = null;
+ baro_speed = 0;
+ time_change = 0;
+ }
+
+ if (state == Altos.ao_flight_pad) {
+
+ /* Track consecutive 'good' gps reports, waiting for 10 of them */
+ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4)
+ npad++;
+ else
+ npad = 0;
+
+ /* Average GPS data while on the pad */
+ if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
+ if (ngps > 1) {
+ /* filter pad position */
+ pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0;
+ pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0;
+ pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0;
+ } else {
+ pad_lat = data.gps.lat;
+ pad_lon = data.gps.lon;
+ pad_alt = data.gps.alt;
+ }
+ ngps++;
+ }
+ }
+
+ gps_waiting = MIN_PAD_SAMPLES - npad;
+ if (gps_waiting < 0)
+ gps_waiting = 0;
+
+ gps_ready = gps_waiting == 0;
+
+ ascent = (Altos.ao_flight_boost <= state &&
+ state <= Altos.ao_flight_coast);
+
+ /* Only look at accelerometer data on the way up */
+ if (ascent && acceleration > max_acceleration)
+ max_acceleration = acceleration;
+ if (ascent && speed > max_speed)
+ max_speed = speed;
+
+ if (height > max_height)
+ max_height = height;
+ if (data.gps != null) {
+ if (gps == null || !gps.locked || data.gps.locked)
+ gps = data.gps;
+ if (ngps > 0 && gps.locked) {
+ from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon);
+ }
+ }
+ elevation = 0;
+ range = -1;
+ if (ngps > 0) {
+ gps_height = gps.alt - pad_alt;
+ if (from_pad != null) {
+ elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI;
+ range = Math.sqrt(height * height + from_pad.distance * from_pad.distance);
+ }
+ } else {
+ gps_height = 0;
+ }
+ }
+
+ public AltosState(AltosRecord cur) {
+ init(cur, null);
+ }
+
+ public AltosState (AltosRecord cur, AltosState prev) {
+ init(cur, prev);
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.util.HashMap;
+
+/*
+ * Telemetry data contents
+ */
+
+
+/*
+ * The telemetry data stream is a bit of a mess at present, with no consistent
+ * formatting. In particular, the GPS data is formatted for viewing instead of parsing.
+ * However, the key feature is that every telemetry line contains all of the information
+ * necessary to describe the current rocket state, including the calibration values
+ * for accelerometer and barometer.
+ *
+ * GPS unlocked:
+ *
+ * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \
+ * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \
+ * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30
+ *
+ * GPS locked:
+ *
+ * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \
+ * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \
+ * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
+ * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
+ * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
+ * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
+ */
+
+public class AltosTelemetry extends AltosRecord {
+ public AltosTelemetry(String line) throws ParseException, AltosCRCException {
+ String[] words = line.split("\\s+");
+ int i = 0;
+
+ if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+ i += 2;
+ AltosParse.word(words[i++], "RSSI");
+ rssi = AltosParse.parse_int(words[i++]);
+ throw new AltosCRCException(rssi);
+ }
+ if (words[i].equals("CALL")) {
+ version = 0;
+ } else {
+ AltosParse.word (words[i++], "VERSION");
+ version = AltosParse.parse_int(words[i++]);
+ }
+
+ AltosParse.word (words[i++], "CALL");
+ callsign = words[i++];
+
+ AltosParse.word (words[i++], "SERIAL");
+ serial = AltosParse.parse_int(words[i++]);
+
+ if (version >= 2) {
+ AltosParse.word (words[i++], "FLIGHT");
+ flight = AltosParse.parse_int(words[i++]);
+ } else
+ flight = 0;
+
+ AltosParse.word(words[i++], "RSSI");
+ rssi = AltosParse.parse_int(words[i++]);
+
+ /* Older telemetry data had mis-computed RSSI value */
+ if (version <= 2)
+ rssi = (rssi + 74) / 2 - 74;
+
+ AltosParse.word(words[i++], "STATUS");
+ status = AltosParse.parse_hex(words[i++]);
+
+ AltosParse.word(words[i++], "STATE");
+ state = Altos.state(words[i++]);
+
+ tick = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "a:");
+ accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "p:");
+ pres = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "t:");
+ temp = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "v:");
+ batt = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "d:");
+ drogue = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "m:");
+ main = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fa:");
+ flight_accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "ga:");
+ ground_accel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fv:");
+ flight_vel = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "fp:");
+ flight_pres = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "gp:");
+ ground_pres = AltosParse.parse_int(words[i++]);
+
+ if (version >= 1) {
+ AltosParse.word(words[i++], "a+:");
+ accel_plus_g = AltosParse.parse_int(words[i++]);
+
+ AltosParse.word(words[i++], "a-:");
+ accel_minus_g = AltosParse.parse_int(words[i++]);
+ } else {
+ accel_plus_g = ground_accel;
+ accel_minus_g = ground_accel + 530;
+ }
+
+ gps = new AltosGPS(words, i, version);
+ }
+}
--- /dev/null
+/*
+ * 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.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosTelemetryIterable extends AltosRecordIterable {
+ LinkedList<AltosRecord> records;
+
+ public Iterator<AltosRecord> iterator () {
+ return records.iterator();
+ }
+
+ public AltosTelemetryIterable (FileInputStream input) {
+ boolean saw_boost = false;
+ int current_tick = 0;
+ int boost_tick = 0;
+
+ records = new LinkedList<AltosRecord> ();
+
+ try {
+ for (;;) {
+ String line = AltosRecord.gets(input);
+ if (line == null) {
+ break;
+ }
+ try {
+ AltosTelemetry record = new AltosTelemetry(line);
+ if (record == null)
+ break;
+ if (records.isEmpty()) {
+ current_tick = record.tick;
+ } else {
+ int tick = record.tick | (current_tick & ~ 0xffff);
+ if (tick < current_tick - 0x1000)
+ tick += 0x10000;
+ current_tick = tick;
+ record.tick = current_tick;
+ }
+ if (!saw_boost && record.state >= Altos.ao_flight_boost)
+ {
+ saw_boost = true;
+ boost_tick = record.tick;
+ }
+ records.add(record);
+ } catch (ParseException pe) {
+ System.out.printf("parse exception %s\n", pe.getMessage());
+ } catch (AltosCRCException ce) {
+ System.out.printf("crc error\n");
+ }
+ }
+ } catch (IOException io) {
+ System.out.printf("io exception\n");
+ }
+
+ /* adjust all tick counts to be relative to boost time */
+ for (AltosRecord r : this)
+ r.time = (r.tick - boost_tick) / 100.0;
+
+ try {
+ input.close();
+ } catch (IOException ie) {
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.io.*;
+import java.util.concurrent.*;
+
+class AltosTelemetryReader extends AltosFlightReader {
+ AltosDevice device;
+ AltosSerial serial;
+ AltosLog log;
+
+ LinkedBlockingQueue<AltosLine> telem;
+
+ AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException {
+ AltosLine l = telem.take();
+ if (l.line == null)
+ throw new IOException("IO error");
+ return new AltosTelemetry(l.line);
+ }
+
+ void close(boolean interrupted) {
+ serial.remove_monitor(telem);
+ log.close();
+ serial.close();
+ }
+
+ void set_channel(int channel) {
+ serial.set_channel(channel);
+ AltosPreferences.set_channel(device.getSerial(), channel);
+ }
+
+ public AltosTelemetryReader (AltosDevice in_device)
+ throws FileNotFoundException, AltosSerialInUseException, IOException {
+ device = in_device;
+ serial = new AltosSerial(device);
+ log = new AltosLog(serial);
+ name = device.toShortString();
+
+ telem = new LinkedBlockingQueue<AltosLine>();
+ serial.set_radio();
+ serial.add_monitor(telem);
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleName</key>
+ <string>altosui</string>
+ <key>CFBundleVersion</key>
+ <string>100.0</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <string>true</string>
+ <key>CFBundleExecutable</key>
+ <string>JavaApplicationStub</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleGetInfoString</key>
+ <string>AltOS UI version 0.7</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleIconFile</key>
+ <string>AltosUIIcon.icns</string>
+ <key>Java</key>
+ <dict>
+ <key>MainClass</key>
+ <string>altosui.AltosUI</string>
+ <key>JVMVersion</key>
+ <string>1.5+</string>
+ <key>ClassPath</key>
+ <array>
+ <string>$JAVAROOT/altosui.jar</string>
+ <string>$JAVAROOT/freetts.jar</string>
+ </array>
+ </dict>
+</dict>
+</plist>
--- /dev/null
+/*
+ * 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.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.prefs.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import libaltosJNI.*;
+
+public class AltosUI extends JFrame {
+ public AltosVoice voice = new AltosVoice();
+
+ public static boolean load_library(Frame frame) {
+ if (!AltosDevice.load_library()) {
+ JOptionPane.showMessageDialog(frame,
+ String.format("No AltOS library in \"%s\"",
+ System.getProperty("java.library.path","<undefined>")),
+ "Cannot load device access library",
+ JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ return true;
+ }
+
+ void telemetry_window(AltosDevice device) {
+ try {
+ AltosFlightReader reader = new AltosTelemetryReader(device);
+ if (reader != null)
+ new AltosFlightUI(voice, reader, device.getSerial());
+ } catch (FileNotFoundException ee) {
+ JOptionPane.showMessageDialog(AltosUI.this,
+ String.format("Cannot open device \"%s\"",
+ device.toShortString()),
+ "Cannot open target device",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (AltosSerialInUseException si) {
+ JOptionPane.showMessageDialog(AltosUI.this,
+ String.format("Device \"%s\" already in use",
+ device.toShortString()),
+ "Device in use",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (IOException ee) {
+ JOptionPane.showMessageDialog(AltosUI.this,
+ device.toShortString(),
+ "Unkonwn I/O error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ Container pane;
+ GridBagLayout gridbag;
+
+ JButton addButton(int x, int y, String label) {
+ GridBagConstraints c;
+ JButton b;
+
+ c = new GridBagConstraints();
+ c.gridx = x; c.gridy = y;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1;
+ c.weighty = 1;
+ b = new JButton(label);
+
+ Dimension ps = b.getPreferredSize();
+
+ gridbag.setConstraints(b, c);
+ add(b, c);
+ return b;
+ }
+
+ public AltosUI() {
+
+ load_library(null);
+
+ java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
+ if (imgURL != null)
+ setIconImage(new ImageIcon(imgURL).getImage());
+
+ AltosPreferences.init(this);
+
+ pane = getContentPane();
+ gridbag = new GridBagLayout();
+ pane.setLayout(gridbag);
+
+ JButton b;
+
+ b = addButton(0, 0, "Monitor Flight");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ConnectToDevice();
+ }
+ });
+ b = addButton(1, 0, "Save Flight Data");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SaveFlightData();
+ }
+ });
+ b = addButton(2, 0, "Replay Flight");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Replay();
+ }
+ });
+ b = addButton(3, 0, "Graph Data");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ GraphData();
+ }
+ });
+ b = addButton(4, 0, "Export Data");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ExportData();
+ }
+ });
+ b = addButton(0, 1, "Configure TeleMetrum");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ConfigureTeleMetrum();
+ }
+ });
+
+ b = addButton(1, 1, "Configure AltosUI");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ConfigureAltosUI();
+ }
+ });
+
+ b = addButton(2, 1, "Flash Image");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ FlashImage();
+ }
+ });
+
+ b = addButton(3, 1, "Fire Igniter");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ FireIgniter();
+ }
+ });
+
+ b = addButton(4, 1, "Quit");
+ b.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.exit(0);
+ }
+ });
+
+ setTitle("AltOS");
+
+ pane.doLayout();
+ pane.validate();
+
+ doLayout();
+ validate();
+
+ setVisible(true);
+
+ Insets i = getInsets();
+ Dimension ps = rootPane.getPreferredSize();
+ ps.width += i.left + i.right;
+ ps.height += i.top + i.bottom;
+ setPreferredSize(ps);
+ setSize(ps);
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+ }
+
+ private void ConnectToDevice() {
+ AltosDevice device = AltosDeviceDialog.show(AltosUI.this,
+ AltosDevice.product_basestation);
+
+ if (device != null)
+ telemetry_window(device);
+ }
+
+ void ConfigureCallsign() {
+ String result;
+ result = JOptionPane.showInputDialog(AltosUI.this,
+ "Configure Callsign",
+ AltosPreferences.callsign());
+ if (result != null)
+ AltosPreferences.set_callsign(result);
+ }
+
+ void ConfigureTeleMetrum() {
+ new AltosConfig(AltosUI.this);
+ }
+
+ void FlashImage() {
+ new AltosFlashUI(AltosUI.this);
+ }
+
+ void FireIgniter() {
+ new AltosIgniteUI(AltosUI.this);
+ }
+
+ /*
+ * Replay a flight from telemetry data
+ */
+ private void Replay() {
+ AltosDataChooser chooser = new AltosDataChooser(
+ AltosUI.this);
+
+ AltosRecordIterable iterable = chooser.runDialog();
+ if (iterable != null) {
+ AltosFlightReader reader = new AltosReplayReader(iterable.iterator(),
+ chooser.filename());
+ new AltosFlightUI(voice, reader);
+ }
+ }
+
+ /* Connect to TeleMetrum, either directly or through
+ * a TeleDongle over the packet link
+ */
+ private void SaveFlightData() {
+ new AltosEepromDownload(AltosUI.this);
+ }
+
+ /* Load a flight log file and write out a CSV file containing
+ * all of the data in standard units
+ */
+
+ private void ExportData() {
+ AltosDataChooser chooser;
+ chooser = new AltosDataChooser(this);
+ AltosRecordIterable record_reader = chooser.runDialog();
+ if (record_reader == null)
+ return;
+ new AltosCSVUI(AltosUI.this, record_reader, chooser.file());
+ }
+
+ /* Load a flight log CSV file and display a pretty graph.
+ */
+
+ private void GraphData() {
+ AltosDataChooser chooser;
+ chooser = new AltosDataChooser(this);
+ AltosRecordIterable record_reader = chooser.runDialog();
+ if (record_reader == null)
+ return;
+ new AltosGraphUI(record_reader);
+ }
+
+ private void ConfigureAltosUI() {
+ new AltosConfigureUI(AltosUI.this, voice);
+ }
+
+ static AltosRecordIterable open_logfile(String filename) {
+ File file = new File (filename);
+ try {
+ FileInputStream in;
+
+ in = new FileInputStream(file);
+ if (filename.endsWith("eeprom"))
+ return new AltosEepromIterable(in);
+ else
+ return new AltosTelemetryIterable(in);
+ } catch (FileNotFoundException fe) {
+ System.out.printf("Cannot open '%s'\n", filename);
+ return null;
+ }
+ }
+
+ static AltosWriter open_csv(String filename) {
+ File file = new File (filename);
+ try {
+ return new AltosCSV(file);
+ } catch (FileNotFoundException fe) {
+ System.out.printf("Cannot open '%s'\n", filename);
+ return null;
+ }
+ }
+
+ static AltosWriter open_kml(String filename) {
+ File file = new File (filename);
+ try {
+ return new AltosKML(file);
+ } catch (FileNotFoundException fe) {
+ System.out.printf("Cannot open '%s'\n", filename);
+ return null;
+ }
+ }
+
+ static final int process_csv = 1;
+ static final int process_kml = 2;
+
+ static void process_file(String input, int process) {
+ AltosRecordIterable iterable = open_logfile(input);
+ if (iterable == null)
+ return;
+ if (process == 0)
+ process = process_csv;
+ if ((process & process_csv) != 0) {
+ String output = Altos.replace_extension(input,".csv");
+ System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+ if (input.equals(output)) {
+ System.out.printf("Not processing '%s'\n", input);
+ } else {
+ AltosWriter writer = open_csv(output);
+ if (writer != null) {
+ writer.write(iterable);
+ writer.close();
+ }
+ }
+ }
+ if ((process & process_kml) != 0) {
+ String output = Altos.replace_extension(input,".kml");
+ System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+ if (input.equals(output)) {
+ System.out.printf("Not processing '%s'\n", input);
+ } else {
+ AltosWriter writer = open_kml(output);
+ if (writer == null)
+ return;
+ writer.write(iterable);
+ writer.close();
+ }
+ }
+ }
+
+ public static void main(final String[] args) {
+ int process = 0;
+ /* Handle batch-mode */
+ if (args.length == 1 && args[0].equals("--help")) {
+ System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
+ System.out.printf(" Options:\n");
+ System.out.printf(" --fetchmaps <lat> <lon>\tpre-fetch maps for site map view\n");
+ System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
+ System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n");
+ System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n");
+ } else if (args.length == 3 && args[0].equals("--fetchmaps")) {
+ double lat = Double.parseDouble(args[1]);
+ double lon = Double.parseDouble(args[2]);
+ AltosSiteMap.prefetchMaps(lat, lon, 5, 5);
+ } else if (args.length == 2 && args[0].equals("--replay")) {
+ String filename = args[1];
+ FileInputStream in;
+ try {
+ in = new FileInputStream(filename);
+ } catch (Exception e) {
+ System.out.printf("Failed to open file '%s'\n", filename);
+ return;
+ }
+ AltosRecordIterable recs;
+ AltosReplayReader reader;
+ if (filename.endsWith("eeprom")) {
+ recs = new AltosEepromIterable(in);
+ } else {
+ recs = new AltosTelemetryIterable(in);
+ }
+ reader = new AltosReplayReader(recs.iterator(), filename);
+ AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader);
+ flight_ui.set_exit_on_close();
+ return;
+ } else if (args.length > 0) {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("--kml"))
+ process |= process_kml;
+ else if (args[i].equals("--csv"))
+ process |= process_csv;
+ else
+ process_file(args[i], process);
+ }
+ } else {
+ AltosUI altosui = new AltosUI();
+ altosui.setVisible(true);
+
+ AltosDevice[] devices = AltosDevice.list(AltosDevice.product_basestation);
+ for (int i = 0; i < devices.length; i++)
+ altosui.telemetry_window(devices[i]);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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 com.sun.speech.freetts.Voice;
+import com.sun.speech.freetts.VoiceManager;
+import com.sun.speech.freetts.audio.JavaClipAudioPlayer;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosVoice implements Runnable {
+ VoiceManager voice_manager;
+ Voice voice;
+ LinkedBlockingQueue<String> phrases;
+ Thread thread;
+ boolean busy;
+
+ final static String voice_name = "kevin16";
+
+ public void run() {
+ try {
+ for (;;) {
+ String s = phrases.take();
+ voice.speak(s);
+ synchronized(this) {
+ if (phrases.isEmpty()) {
+ busy = false;
+ notifyAll();
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public synchronized void drain() throws InterruptedException {
+ while (busy)
+ wait();
+ }
+
+ public void speak_always(String s) {
+ try {
+ if (voice != null) {
+ synchronized(this) {
+ busy = true;
+ phrases.put(s);
+ }
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public void speak(String s) {
+ if (AltosPreferences.voice())
+ speak_always(s);
+ }
+
+ public void speak(String format, Object... parameters) {
+ speak(String.format(format, parameters));
+ }
+
+ public AltosVoice () {
+ busy = false;
+ voice_manager = VoiceManager.getInstance();
+ voice = voice_manager.getVoice(voice_name);
+ if (voice != null) {
+ voice.allocate();
+ phrases = new LinkedBlockingQueue<String> ();
+ thread = new Thread(this);
+ thread.start();
+ } else {
+ System.out.printf("Voice manager failed to open %s\n", voice_name);
+ Voice[] voices = voice_manager.getVoices();
+ System.out.printf("Available voices:\n");
+ for (int i = 0; i < voices.length; i++) {
+ System.out.println(" " + voices[i].getName()
+ + " (" + voices[i].getDomain() + " domain)");
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.text.*;
+import java.util.*;
+
+public interface AltosWriter {
+
+ public void write(AltosRecord record);
+
+ public void write(AltosRecordIterable iterable);
+
+ public void close();
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * 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.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+import javax.imageio.ImageIO;
+import javax.swing.table.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+class GrabNDrag extends MouseInputAdapter {
+ private JComponent scroll;
+ private Point startPt = new Point();
+
+ public GrabNDrag(JComponent scroll) {
+ this.scroll = scroll;
+ scroll.addMouseMotionListener(this);
+ scroll.addMouseListener(this);
+ scroll.setAutoscrolls(true);
+ }
+
+ public void mousePressed(MouseEvent e) {
+ startPt.setLocation(e.getPoint());
+ }
+ public void mouseDragged(MouseEvent e) {
+ int xd = e.getX() - startPt.x;
+ int yd = e.getY() - startPt.y;
+
+ Rectangle r = scroll.getVisibleRect();
+ r.x -= xd;
+ r.y -= yd;
+ scroll.scrollRectToVisible(r);
+ }
+}
--- /dev/null
+#\r
+# InstDrv Example, (c) 2003 Jan Kiszka (Jan Kiszka@web.de)\r
+#\r
+\r
+Name "InstDrv.dll test"\r
+\r
+OutFile "InstDrv-Test.exe"\r
+\r
+ShowInstDetails show\r
+\r
+ComponentText "InstDrv Plugin Usage Example"\r
+\r
+Page components\r
+Page instfiles\r
+\r
+Section "Install a Driver" InstDriver\r
+ InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
+ Pop $0\r
+ DetailPrint "InitDriverSetup: $0"\r
+\r
+ InstDrv::DeleteOemInfFiles /NOUNLOAD\r
+ Pop $0\r
+ DetailPrint "DeleteOemInfFiles: $0"\r
+ StrCmp $0 "00000000" PrintInfNames ContInst1\r
+\r
+ PrintInfNames:\r
+ Pop $0\r
+ DetailPrint "Deleted $0"\r
+ Pop $0\r
+ DetailPrint "Deleted $0"\r
+\r
+ ContInst1:\r
+ InstDrv::CreateDevice /NOUNLOAD\r
+ Pop $0\r
+ DetailPrint "CreateDevice: $0"\r
+\r
+ SetOutPath $TEMP\r
+ File "ircomm2k.inf"\r
+ File "ircomm2k.sys"\r
+\r
+ InstDrv::InstallDriver /NOUNLOAD "$TEMP\ircomm2k.inf"\r
+ Pop $0\r
+ DetailPrint "InstallDriver: $0"\r
+ StrCmp $0 "00000000" PrintReboot ContInst2\r
+\r
+ PrintReboot:\r
+ Pop $0\r
+ DetailPrint "Reboot: $0"\r
+\r
+ ContInst2:\r
+ InstDrv::CountDevices\r
+ Pop $0\r
+ DetailPrint "CountDevices: $0"\r
+SectionEnd\r
+\r
+Section "Uninstall the driver again" UninstDriver\r
+ InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
+ Pop $0\r
+ DetailPrint "InitDriverSetup: $0"\r
+\r
+ InstDrv::DeleteOemInfFiles /NOUNLOAD\r
+ Pop $0\r
+ DetailPrint "DeleteOemInfFiles: $0"\r
+ StrCmp $0 "00000000" PrintInfNames ContUninst1\r
+\r
+ PrintInfNames:\r
+ Pop $0\r
+ DetailPrint "Deleted $0"\r
+ Pop $0\r
+ DetailPrint "Deleted $0"\r
+\r
+ ContUninst1:\r
+ InstDrv::RemoveAllDevices\r
+ Pop $0\r
+ DetailPrint "RemoveAllDevices: $0"\r
+ StrCmp $0 "00000000" PrintReboot ContUninst2\r
+\r
+ PrintReboot:\r
+ Pop $0\r
+ DetailPrint "Reboot: $0"\r
+\r
+ ContUninst2:\r
+ Delete "$SYSDIR\system32\ircomm2k.sys"\r
+SectionEnd
\ No newline at end of file
--- /dev/null
+/*\r
+\r
+InstDrv.dll - Installs or Removes Device Drivers\r
+\r
+Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
+\r
+This software is provided 'as-is', without any express or implied\r
+warranty. In no event will the authors be held liable for any damages\r
+arising from the use of this software.\r
+\r
+Permission is granted to anyone to use this software for any purpose,\r
+including commercial applications, and to alter it and redistribute\r
+it freely, subject to the following restrictions:\r
+\r
+1. The origin of this software must not be misrepresented; \r
+ you must not claim that you wrote the original software.\r
+ If you use this software in a product, an acknowledgment in the\r
+ product documentation would be appreciated but is not required.\r
+2. Altered versions must be plainly marked as such,\r
+ and must not be misrepresented as being the original software.\r
+3. This notice may not be removed or altered from any distribution.\r
+\r
+*/\r
+\r
+\r
+#include <windows.h>\r
+#include <setupapi.h>\r
+#include <newdev.h>\r
+#include "../exdll/exdll.h"\r
+\r
+\r
+char paramBuf[1024];\r
+GUID devClass;\r
+char hwIdBuf[1024];\r
+int initialized = 0;\r
+\r
+\r
+\r
+void* memset(void* dst, int val, unsigned int len)\r
+{\r
+ while (len-- > 0)\r
+ *((char *)dst)++ = val;\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+void* memcpy(void* dst, const void* src, unsigned int len)\r
+{\r
+ while (len-- > 0)\r
+ *((char *)dst)++ = *((char *)src)++;\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+int HexCharToInt(char c)\r
+{\r
+ if ((c >= '0') && (c <= '9'))\r
+ return c - '0';\r
+ else if ((c >= 'a') && (c <= 'f'))\r
+ return c - 'a' + 10;\r
+ else if ((c >= 'A') && (c <= 'F'))\r
+ return c - 'A' + 10;\r
+ else\r
+ return -1;\r
+}\r
+\r
+\r
+\r
+BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)\r
+{\r
+ int i, val;\r
+\r
+\r
+ for (i = width - 4; i >= 0; i -= 4)\r
+ {\r
+ val = HexCharToInt(*str++);\r
+ if (val < 0)\r
+ return FALSE;\r
+ *(unsigned int *)valBuf += val << i;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+\r
+BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)\r
+{\r
+ int i;\r
+\r
+\r
+ memset(pGuid, 0, sizeof(GUID));\r
+\r
+ if (*guidStr++ != '{')\r
+ return FALSE;\r
+\r
+ if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))\r
+ return FALSE;\r
+ guidStr += 8;\r
+\r
+ if (*guidStr++ != '-')\r
+ return FALSE;\r
+\r
+ if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))\r
+ return FALSE;\r
+ guidStr += 4;\r
+\r
+ if (*guidStr++ != '-')\r
+ return FALSE;\r
+\r
+ if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))\r
+ return FALSE;\r
+ guidStr += 4;\r
+\r
+ if (*guidStr++ != '-')\r
+ return FALSE;\r
+\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
+ return FALSE;\r
+ guidStr += 2;\r
+ }\r
+\r
+ if (*guidStr++ != '-')\r
+ return FALSE;\r
+\r
+ for (i = 2; i < 8; i++)\r
+ {\r
+ if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
+ return FALSE;\r
+ guidStr += 2;\r
+ }\r
+\r
+ if (*guidStr++ != '}')\r
+ return FALSE;\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+\r
+DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)\r
+{\r
+ DWORD buffersize = 0;\r
+ LPTSTR buffer = NULL;\r
+ DWORD dataType;\r
+ DWORD result;\r
+\r
+\r
+ while (1)\r
+ {\r
+ if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))\r
+ {\r
+ result = GetLastError();\r
+ break;\r
+ }\r
+\r
+ GetDeviceRegistryProperty:\r
+ if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,\r
+ &dataType, (PBYTE)buffer, buffersize,\r
+ &buffersize))\r
+ {\r
+ result = GetLastError();\r
+\r
+ if (result == ERROR_INSUFFICIENT_BUFFER)\r
+ {\r
+ if (buffer != NULL)\r
+ LocalFree(buffer);\r
+\r
+ buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);\r
+\r
+ if (buffer == NULL)\r
+ break;\r
+\r
+ goto GetDeviceRegistryProperty;\r
+ }\r
+ else if (result == ERROR_INVALID_DATA)\r
+ continue; // ignore invalid entries\r
+ else\r
+ break; // break on other errors\r
+ }\r
+\r
+ if (lstrcmpi(buffer, hwIdBuf) == 0)\r
+ {\r
+ result = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (buffer != NULL)\r
+ LocalFree(buffer);\r
+\r
+ return result;\r
+}\r
+\r
+\r
+\r
+DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,\r
+ HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,\r
+ DWORD *pIndex, DWORD flags)\r
+{\r
+ DWORD result;\r
+\r
+\r
+ *pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);\r
+ if (*pDevInfoSet == INVALID_HANDLE_VALUE)\r
+ return GetLastError();\r
+\r
+ pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);\r
+ *pIndex = 0;\r
+\r
+ result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);\r
+\r
+ if (result != 0)\r
+ SetupDiDestroyDeviceInfoList(*pDevInfoSet);\r
+\r
+ return result;\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::InitDriverSetup devClass drvHWID\r
+ *\r
+ * devClass - GUID of the driver's device setup class\r
+ * drvHWID - Hardware ID of the supported device\r
+ *\r
+ * Return:\r
+ * result - error message, empty on success\r
+ */\r
+void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ EXDLL_INIT();\r
+\r
+ /* convert class GUID */\r
+ popstring(paramBuf);\r
+\r
+ if (!StringToGUID(paramBuf, &devClass))\r
+ {\r
+ popstring(paramBuf);\r
+ pushstring("Invalid GUID!");\r
+ return;\r
+ }\r
+\r
+ /* get hardware ID */\r
+ memset(hwIdBuf, 0, sizeof(hwIdBuf));\r
+ popstring(hwIdBuf);\r
+\r
+ initialized = 1;\r
+ pushstring("");\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::CountDevices\r
+ *\r
+ * Return:\r
+ * result - Number of installed devices the driver supports\r
+ */\r
+void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ HDEVINFO devInfoSet;\r
+ SP_DEVINFO_DATA devInfoData;\r
+ int count = 0;\r
+ char countBuf[16];\r
+ DWORD index;\r
+ DWORD result;\r
+\r
+\r
+ EXDLL_INIT();\r
+\r
+ if (!initialized)\r
+ {\r
+ pushstring("Fatal error!");\r
+ return;\r
+ }\r
+\r
+ result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,\r
+ &index, DIGCF_PRESENT);\r
+ if (result != 0)\r
+ {\r
+ pushstring("0");\r
+ return;\r
+ }\r
+\r
+ do\r
+ {\r
+ count++;\r
+ } while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);\r
+\r
+ SetupDiDestroyDeviceInfoList(devInfoSet);\r
+\r
+ wsprintf(countBuf, "%d", count);\r
+ pushstring(countBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::CreateDevice\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ */\r
+void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ HDEVINFO devInfoSet;\r
+ SP_DEVINFO_DATA devInfoData;\r
+ DWORD result = 0;\r
+ char resultBuf[16];\r
+\r
+\r
+ EXDLL_INIT();\r
+\r
+ if (!initialized)\r
+ {\r
+ pushstring("Fatal error!");\r
+ return;\r
+ }\r
+\r
+ devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);\r
+ if (devInfoSet == INVALID_HANDLE_VALUE)\r
+ {\r
+ wsprintf(resultBuf, "%08X", GetLastError());\r
+ pushstring(resultBuf);\r
+ return;\r
+ }\r
+\r
+ devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r
+ if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,\r
+ hwndParent, DICD_GENERATE_ID, &devInfoData))\r
+ {\r
+ result = GetLastError();\r
+ goto InstallCleanup;\r
+ }\r
+\r
+ if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,\r
+ hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR))) \r
+ {\r
+ result = GetLastError();\r
+ goto InstallCleanup;\r
+ }\r
+\r
+ if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))\r
+ result = GetLastError();\r
+\r
+ InstallCleanup:\r
+ SetupDiDestroyDeviceInfoList(devInfoSet);\r
+\r
+ wsprintf(resultBuf, "%08X", result);\r
+ pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::InstallDriver infPath\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ * reboot - non-zero if reboot is required\r
+ */\r
+void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ char resultBuf[16];\r
+ BOOL reboot;\r
+\r
+\r
+ EXDLL_INIT();\r
+ popstring(paramBuf);\r
+\r
+ if (!initialized)\r
+ {\r
+ pushstring("Fatal error!");\r
+ return;\r
+ }\r
+\r
+ if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,\r
+ INSTALLFLAG_FORCE, &reboot))\r
+ {\r
+ wsprintf(resultBuf, "%08X", GetLastError());\r
+ pushstring(resultBuf);\r
+ }\r
+ else\r
+ {\r
+ wsprintf(resultBuf, "%d", reboot);\r
+ pushstring(resultBuf);\r
+ pushstring("00000000");\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::DeleteOemInfFiles\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ * oeminf - Path of the deleted devices setup file (oemXX.inf)\r
+ * oempnf - Path of the deleted devices setup file (oemXX.pnf)\r
+ */\r
+void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ HDEVINFO devInfo;\r
+ SP_DEVINFO_DATA devInfoData;\r
+ SP_DRVINFO_DATA drvInfoData;\r
+ SP_DRVINFO_DETAIL_DATA drvInfoDetail;\r
+ DWORD index;\r
+ DWORD result;\r
+ char resultBuf[16];\r
+\r
+\r
+ if (!initialized)\r
+ {\r
+ pushstring("Fatal error!");\r
+ return;\r
+ }\r
+\r
+ result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
+ if (result != 0)\r
+ goto Cleanup1;\r
+\r
+ if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup2;\r
+ }\r
+\r
+ drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);\r
+ drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);\r
+\r
+ if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup3;\r
+ }\r
+\r
+ if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,\r
+ &drvInfoDetail, sizeof(drvInfoDetail), NULL))\r
+ {\r
+ result = GetLastError();\r
+\r
+ if (result != ERROR_INSUFFICIENT_BUFFER)\r
+ goto Cleanup3;\r
+\r
+ result = 0;\r
+ }\r
+\r
+ pushstring(drvInfoDetail.InfFileName);\r
+ if (!DeleteFile(drvInfoDetail.InfFileName))\r
+ result = GetLastError();\r
+ else\r
+ {\r
+ index = lstrlen(drvInfoDetail.InfFileName);\r
+ if (index > 3)\r
+ {\r
+ lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");\r
+ pushstring(drvInfoDetail.InfFileName);\r
+ if (!DeleteFile(drvInfoDetail.InfFileName))\r
+ result = GetLastError();\r
+ }\r
+ }\r
+\r
+ Cleanup3:\r
+ SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);\r
+\r
+ Cleanup2:\r
+ SetupDiDestroyDeviceInfoList(devInfo);\r
+\r
+ Cleanup1:\r
+ wsprintf(resultBuf, "%08X", result);\r
+ pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::RemoveAllDevices\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ * reboot - non-zero if reboot is required\r
+ */\r
+void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ HDEVINFO devInfo;\r
+ SP_DEVINFO_DATA devInfoData;\r
+ DWORD index;\r
+ DWORD result;\r
+ char resultBuf[16];\r
+ BOOL reboot = FALSE;\r
+ SP_DEVINSTALL_PARAMS instParams;\r
+\r
+\r
+ EXDLL_INIT();\r
+\r
+ if (!initialized)\r
+ {\r
+ pushstring("Fatal error!");\r
+ return;\r
+ }\r
+\r
+ result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
+ if (result != 0)\r
+ goto Cleanup1;\r
+\r
+ do\r
+ {\r
+ if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))\r
+ {\r
+ result = GetLastError();\r
+ break;\r
+ }\r
+\r
+ instParams.cbSize = sizeof(instParams);\r
+ if (!reboot &&\r
+ SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&\r
+ ((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))\r
+ {\r
+ reboot = TRUE;\r
+ }\r
+\r
+ result = FindNextDevice(devInfo, &devInfoData, &index);\r
+ } while (result == 0);\r
+\r
+ SetupDiDestroyDeviceInfoList(devInfo);\r
+\r
+ Cleanup1:\r
+ if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))\r
+ {\r
+ wsprintf(resultBuf, "%d", reboot);\r
+ pushstring(resultBuf);\r
+ pushstring("00000000");\r
+ }\r
+ else\r
+ {\r
+ wsprintf(resultBuf, "%08X", result);\r
+ pushstring(resultBuf);\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::StartSystemService serviceName\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ */\r
+void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ SC_HANDLE managerHndl;\r
+ SC_HANDLE svcHndl;\r
+ SERVICE_STATUS svcStatus;\r
+ DWORD oldCheckPoint;\r
+ DWORD result;\r
+ char resultBuf[16];\r
+\r
+\r
+ EXDLL_INIT();\r
+ popstring(paramBuf);\r
+\r
+ managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
+ if (managerHndl == NULL)\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup1;\r
+ }\r
+\r
+ svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);\r
+ if (svcHndl == NULL)\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup2;\r
+ }\r
+\r
+ if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup3;\r
+ }\r
+\r
+ while (svcStatus.dwCurrentState == SERVICE_START_PENDING)\r
+ {\r
+ oldCheckPoint = svcStatus.dwCheckPoint;\r
+\r
+ Sleep(svcStatus.dwWaitHint);\r
+\r
+ if (!QueryServiceStatus(svcHndl, &svcStatus))\r
+ {\r
+ result = GetLastError();\r
+ break;\r
+ }\r
+\r
+ if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
+ {\r
+ if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&\r
+ (svcStatus.dwWin32ExitCode != 0))\r
+ result = svcStatus.dwWin32ExitCode;\r
+ else\r
+ result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
+ }\r
+ }\r
+\r
+ if (svcStatus.dwCurrentState == SERVICE_RUNNING)\r
+ result = 0;\r
+\r
+ Cleanup3:\r
+ CloseServiceHandle(svcHndl);\r
+\r
+ Cleanup2:\r
+ CloseServiceHandle(managerHndl);\r
+\r
+ Cleanup1:\r
+ wsprintf(resultBuf, "%08X", result);\r
+ pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+/*\r
+ * InstDrv::StopSystemService serviceName\r
+ *\r
+ * Return:\r
+ * result - Windows error code\r
+ */\r
+void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
+{\r
+ SC_HANDLE managerHndl;\r
+ SC_HANDLE svcHndl;\r
+ SERVICE_STATUS svcStatus;\r
+ DWORD oldCheckPoint;\r
+ DWORD result;\r
+ char resultBuf[16];\r
+\r
+\r
+ EXDLL_INIT();\r
+ popstring(paramBuf);\r
+\r
+ managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
+ if (managerHndl == NULL)\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup1;\r
+ }\r
+\r
+ svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);\r
+ if (svcHndl == NULL)\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup2;\r
+ }\r
+\r
+ if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))\r
+ {\r
+ result = GetLastError();\r
+ goto Cleanup3;\r
+ }\r
+\r
+ while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)\r
+ {\r
+ oldCheckPoint = svcStatus.dwCheckPoint;\r
+\r
+ Sleep(svcStatus.dwWaitHint);\r
+\r
+ if (!QueryServiceStatus(svcHndl, &svcStatus))\r
+ {\r
+ result = GetLastError();\r
+ break;\r
+ }\r
+\r
+ if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
+ {\r
+ result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (svcStatus.dwCurrentState == SERVICE_STOPPED)\r
+ result = 0;\r
+\r
+ Cleanup3:\r
+ CloseServiceHandle(svcHndl);\r
+\r
+ Cleanup2:\r
+ CloseServiceHandle(managerHndl);\r
+\r
+ Cleanup1:\r
+ wsprintf(resultBuf, "%08X", result);\r
+ pushstring(resultBuf);\r
+}\r
+\r
+\r
+\r
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)\r
+{\r
+ return TRUE;\r
+}\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="InstDrv" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** NICHT BEARBEITEN **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=InstDrv - Win32 Debug\r
+!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE\r
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "InstDrv.mak".\r
+!MESSAGE \r
+!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben\r
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "InstDrv.mak" CFG="InstDrv - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Für die Konfiguration stehen zur Auswahl:\r
+!MESSAGE \r
+!MESSAGE "InstDrv - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "InstDrv - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "InstDrv - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 1\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O1 /I "C:\Programme\WINDDK\3790\inc\ddk\w2k" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /FD /c\r
+# SUBTRACT CPP /YX\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x407 /d "NDEBUG"\r
+# ADD RSC /l 0x407 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib setupapi.lib newdev.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"../../Plugins/InstDrv.dll" /libpath:"C:\Programme\WINDDK\3790\lib\w2k\i386" /opt:nowin98\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF "$(CFG)" == "InstDrv - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x407 /d "_DEBUG"\r
+# ADD RSC /l 0x407 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /debug /machine:I386 /pdbtype:sept\r
+# SUBTRACT LINK32 /nodefaultlib\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "InstDrv - Win32 Release"\r
+# Name "InstDrv - Win32 Debug"\r
+# Begin Group "Quellcodedateien"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\InstDrv.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header-Dateien"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# End Group\r
+# Begin Group "Ressourcendateien"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN!\r
+\r
+###############################################################################\r
+\r
+Project: "InstDrv"=.\InstDrv.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
--- /dev/null
+InstDrv.dll version 0.2 - Installs or Removes Device Drivers\r
+------------------------------------------------------------\r
+\r
+\r
+The plugin helps you to create NSIS scripts for installing device drivers or\r
+removing them again. It can count installed device instances, create new ones\r
+or delete all supported device. InstDrv works on Windows 2000 or later.\r
+\r
+\r
+\r
+InstDrv::InitDriverSetup devClass drvHWID\r
+Return: result\r
+\r
+To start processing a driver, first call this function. devClass is the GUID\r
+of the device class the driver supports, drvHWID is the device hardware ID. If\r
+you don't know what these terms mean, you may want to take a look at the\r
+Windows DDK. This function returns an empty string on success, otherwise an\r
+error message.\r
+\r
+InitDriverSetup has to be called every time after the plugin dll has been\r
+(re-)loaded, or if you want to switch to a different driver.\r
+\r
+\r
+\r
+InstDrv::CountDevices\r
+Return: number\r
+\r
+This call returns the number of installed and supported devices of the driver.\r
+\r
+\r
+\r
+InstDrv::CreateDevice\r
+Return: result\r
+\r
+To create a new deviced node which the driver has to support, use this\r
+function. You may even call it multiple times for more than one instance. The\r
+return value is the Windows error code (in hex). Use CreateDevice before\r
+installing or updating the driver itself.\r
+\r
+\r
+\r
+InstDrv::InstallDriver infPath\r
+Return: result\r
+ reboot\r
+\r
+InstallDriver installs or updates a device driver as specified in the .inf\r
+setup script. It returns a Windows error code (in hex) and, on success, a flag\r
+signalling if a system reboot is required.\r
+\r
+\r
+\r
+InstDrv::DeleteOemInfFiles\r
+Return: result\r
+ oeminf\r
+ oempnf\r
+\r
+DeleteOemInfFiles tries to clean up the Windows inf directory by deleting the\r
+oemXX.inf and oemXX.pnf files associated with the drivers. It returns a\r
+Windows error code (in hex) and, on success, the names of the deleted files.\r
+This functions requires that at least one device instance is still present.\r
+So, call it before you remove the devices itself. You should also call it\r
+before updating a driver. This avoids that the inf directory gets slowly\r
+messed up with useless old setup scripts (which does NOT really accelerate\r
+Windows). The error code which comes up when no device is installed is\r
+"00000103".\r
+\r
+\r
+\r
+InstDrv::RemoveAllDevices\r
+Return: result\r
+ reboot\r
+\r
+This functions deletes all devices instances the driver supported. It returns\r
+a Windows error code (in hex) and, on success, a flag signalling if the system\r
+needs to be rebooted. You additionally have to remove the driver binaries from\r
+the system paths.\r
+\r
+\r
+\r
+InstDrv::StartSystemService serviceName\r
+Return: result\r
+\r
+Call this function to start the provided system service. The function blocks\r
+until the service is started or the system reported a timeout. The return value\r
+is the Windows error code (in hex).\r
+\r
+\r
+\r
+InstDrv::StopSystemService serviceName\r
+Return: result\r
+\r
+This function tries to stop the provided system service. It blocks until the\r
+service has been shut down or the system reported a timeout. The return value\r
+is the Windows error code (in hex).\r
+\r
+\r
+\r
+Example.nsi\r
+\r
+The example script installs or removes the virtual COM port driver of IrCOMM2k\r
+(2.0.0-alpha8, see www.ircomm2k.de/english). The driver and its setup script\r
+are only included for demonstration purposes, they do not work without the\r
+rest of IrCOMM2k (but they also do not cause any harm).\r
+\r
+\r
+\r
+Building the Source Code\r
+\r
+To build the plugin from the source code, some include files and libraries\r
+which come with the Windows DDK are required.\r
+\r
+\r
+\r
+History\r
+\r
+ 0.2 - fixed bug when calling InitDriverSetup the second time\r
+ - added StartSystemService and StopSystemService\r
+\r
+ 0.1 - first release\r
+\r
+\r
+\r
+License\r
+\r
+Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
+\r
+This software is provided 'as-is', without any express or implied\r
+warranty. In no event will the authors be held liable for any damages\r
+arising from the use of this software.\r
+\r
+Permission is granted to anyone to use this software for any purpose,\r
+including commercial applications, and to alter it and redistribute\r
+it freely, subject to the following restrictions:\r
+\r
+1. The origin of this software must not be misrepresented; \r
+ you must not claim that you wrote the original software.\r
+ If you use this software in a product, an acknowledgment in the\r
+ product documentation would be appreciated but is not required.\r
+2. Altered versions must be plainly marked as such,\r
+ and must not be misrepresented as being the original software.\r
+3. This notice may not be removed or altered from any distribution.\r
--- /dev/null
+; IrCOMM2k.inf\r
+;\r
+; Installation file for the Virtual Infrared-COM-Port\r
+;\r
+; (c) Copyright 2001, 2002 Jan Kiszka \r
+;\r
+\r
+[Version]\r
+Signature="$Windows NT$"\r
+Provider=%JK%\r
+Class=Ports\r
+ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318}\r
+;DriverVer=03/26/2002,1.2.1.0\r
+\r
+[DestinationDirs]\r
+IrCOMM2k.Copy2Drivers = 12\r
+IrCOMM2k.Copy2Winnt = 10\r
+IrCOMM2k.Copy2System32 = 11\r
+IrCOMM2k.Copy2Help = 18\r
+\r
+\r
+;\r
+; Driver information\r
+;\r
+\r
+[Manufacturer]\r
+%JK% = JK.Mfg\r
+\r
+[JK.Mfg]\r
+%JK.DeviceDescIrCOMM% = IrCOMM2k_inst,IrCOMM2k\r
+\r
+\r
+;\r
+; General installation section\r
+;\r
+\r
+[IrCOMM2k_inst]\r
+CopyFiles = IrCOMM2k.Copy2Drivers ;,IrCOMM2k.Copy2System32,IrCOMM2k.Copy2Help,IrCOMM2k.Copy2Winnt\r
+;AddReg = IrCOMM2k_inst_AddReg\r
+\r
+\r
+;\r
+; File sections\r
+;\r
+\r
+[IrCOMM2k.Copy2Drivers]\r
+ircomm2k.sys,,,2\r
+\r
+;[IrCOMM2k.Copy2System32]\r
+;ircomm2k.exe,,,2\r
+;ircomm2k.dll,,,2\r
+\r
+;[IrCOMM2k.Copy2Help]\r
+;ircomm2k.hlp,,,2\r
+\r
+;[IrCOMM2k.Copy2Winnt]\r
+;IrCOMM2k-Setup.exe,Setup.exe,,2\r
+\r
+\r
+;\r
+; Service Installation\r
+;\r
+\r
+[IrCOMM2k_inst.Services]\r
+AddService = IrCOMM2k,0x00000002,IrCOMM2k_DriverService_Inst,IrCOMM2k_DriverEventLog_Inst\r
+;AddService = IrCOMM2kSvc,,IrCOMM2k_Service_Inst\r
+\r
+[IrCOMM2k_DriverService_Inst]\r
+DisplayName = %IrCOMM2k.DrvName%\r
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER\r
+StartType = 3 ; SERVICE_DEMAND_START\r
+ErrorControl = 0 ; SERVICE_ERROR_IGNORE\r
+ServiceBinary = %12%\ircomm2k.sys\r
+\r
+;[IrCOMM2k_Service_Inst]\r
+;DisplayName = %IrCOMM2k.SvcName%\r
+;Description = %IrCOMM2k.SvcDesc%\r
+;ServiceType = 0x00000120 ; SERVICE_WIN32_SHARE_PROCESS, SERVICE_INTERACTIVE_PROCESS\r
+;StartType = 2 ; SERVICE_AUTO_START\r
+;ErrorControl = 0 ; SERVICE_ERROR_IGNORE\r
+;ServiceBinary = %11%\ircomm2k.exe\r
+;Dependencies = IrCOMM2k\r
+;AddReg = IrCOMM2kSvcAddReg\r
+\r
+\r
+[IrCOMM2k_inst.nt.HW]\r
+AddReg=IrCOMM2kHwAddReg\r
+\r
+[IrCOMM2kHwAddReg]\r
+HKR,,PortSubClass,REG_BINARY,0x00000001\r
+;HKR,,TimeoutScaling,REG_DWORD,0x00000001\r
+;HKR,,StatusLines,REG_DWORD,0x00000000\r
+\r
+;[IrCOMM2k_inst_AddReg]\r
+;HKR,,EnumPropPages32,,"ircomm2k.dll,IrCOMM2kPropPageProvider"\r
+;HKLM,%UNINSTALL_KEY%,DisplayIcon,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
+;HKLM,%UNINSTALL_KEY%,DisplayName,,"IrCOMM2k 1.2.1 "\r
+;HKLM,%UNINSTALL_KEY%,DisplayVersion,,"1.2.1"\r
+;HKLM,%UNINSTALL_KEY%,HelpLink,,"http://www.ircomm2k.de"\r
+;HKLM,%UNINSTALL_KEY%,Publisher,,%JK%\r
+;HKLM,%UNINSTALL_KEY%,UninstallString,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
+\r
+;[IrCOMM2kSvcAddReg]\r
+;HKR,Parameters,ActiveConnectOnly,REG_DWORD,0x00000000\r
+\r
+\r
+[IrCOMM2k_DriverEventLog_Inst]\r
+AddReg = IrCOMM2k_DriverEventLog_AddReg\r
+\r
+[IrCOMM2k_DriverEventLog_AddReg]\r
+HKR,,EventMessageFile,REG_EXPAND_SZ,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\ircomm2k.sys"\r
+HKR,,TypesSupported,REG_DWORD,7\r
+\r
+\r
+[Strings]\r
+\r
+;\r
+; Non-Localizable Strings\r
+;\r
+\r
+REG_SZ = 0x00000000\r
+REG_MULTI_SZ = 0x00010000\r
+REG_EXPAND_SZ = 0x00020000\r
+REG_BINARY = 0x00000001\r
+REG_DWORD = 0x00010001\r
+SERVICEROOT = "System\CurrentControlSet\Services"\r
+UNINSTALL_KEY = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IrCOMM2k"\r
+\r
+;\r
+; Localizable Strings\r
+;\r
+\r
+JK = "Jan Kiszka"\r
+JK.DeviceDescIrCOMM = "Virtueller Infrarot-Kommunikationsanschluss"\r
+IrCOMM2k.DrvName = "Virtueller Infrarot-Kommunikationsanschluss"\r
+;IrCOMM2k.SvcName = "Virtueller Infrarot-Kommunikationsanschluß, Dienstprogramm"\r
+;IrCOMM2k.SvcDesc = "Bildet über Infarot einen Kommunikationsanschluß nach."\r
--- /dev/null
+.SUFFIXES: .java .class
+
+CLASSPATH=classes:./*:/usr/share/java/*
+CLASSFILES=\
+ Altos.class \
+ AltosChannelMenu.class \
+ AltosConfig.class \
+ AltosConfigUI.class \
+ AltosConvert.class \
+ AltosCRCException.class \
+ AltosCSV.class \
+ AltosCSVUI.class \
+ AltosDebug.class \
+ AltosEepromDownload.class \
+ AltosEepromMonitor.class \
+ AltosEepromReader.class \
+ AltosEepromRecord.class \
+ AltosFile.class \
+ AltosFlash.class \
+ AltosFlashUI.class \
+ AltosFlightInfoTableModel.class \
+ AltosFlightStatusTableModel.class \
+ AltosGPS.class \
+ AltosGreatCircle.class \
+ AltosHexfile.class \
+ AltosLine.class \
+ AltosInfoTable.class \
+ AltosLog.class \
+ AltosLogfileChooser.class \
+ AltosParse.class \
+ AltosPreferences.class \
+ AltosReader.class \
+ AltosRecord.class \
+ AltosSerialMonitor.class \
+ AltosSerial.class \
+ AltosState.class \
+ AltosStatusTable.class \
+ AltosTelemetry.class \
+ AltosTelemetryReader.class \
+ AltosUI.class \
+ AltosDevice.class \
+ AltosDeviceDialog.class \
+ AltosRomconfig.class \
+ AltosRomconfigUI.class \
+ AltosVoice.class
+
+JAVA_ICON=../../icon/altus-metrum-16x16.jpg
+WINDOWS_ICON=../../icon/altus-metrum.ico
+
+# where altosui.jar gets installed
+ALTOSLIB=/usr/share/java
+
+# where freetts.jar is to be found
+FREETTSLIB=/usr/share/java
+
+# all of the freetts files
+FREETTSJAR= \
+ $(FREETTSLIB)/cmudict04.jar \
+ $(FREETTSLIB)/cmulex.jar \
+ $(FREETTSLIB)/cmu_time_awb.jar \
+ $(FREETTSLIB)/cmutimelex.jar \
+ $(FREETTSLIB)/cmu_us_kal.jar \
+ $(FREETTSLIB)/en_us.jar \
+ $(FREETTSLIB)/freetts.jar
+
+# The current hex files
+HEXLIB=../../src
+HEXFILES = \
+ $(HEXLIB)/telemetrum-v1.0.ihx \
+ $(HEXLIB)/teledongle-v0.2.ihx
+
+JAVAFLAGS=-Xlint:unchecked -Xlint:deprecation
+
+ALTOSUIJAR = altosui.jar
+FATJAR = fat/altosui.jar
+
+OS:=$(shell uname)
+
+LINUX_APP=altosui
+
+DARWIN_ZIP=Altos-Mac.zip
+
+WINDOWS_EXE=Altos-Windows.exe
+
+LINUX_TGZ=Altos-Linux.tgz
+
+all: altosui.jar $(LINUX_APP)
+fat: altosui.jar $(LINUX_APP) $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
+
+$(CLASSFILES):
+
+.java.class:
+ javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
+
+altosui.jar: classes/images classes/altosui classes/libaltosJNI $(CLASSFILES) Manifest.txt
+ cd ./classes && jar cfm ../$@ altosui/Manifest.txt images/* altosui/*.class libaltosJNI/*.class
+
+Manifest.txt: Makefile $(CLASSFILES)
+ echo 'Main-Class: altosui.AltosUI' > $@
+ echo "Class-Path: $(FREETTSLIB)/freetts.jar" >> $@
+
+classes/altosui:
+ mkdir -p classes
+ ln -sf .. classes/altosui
+
+classes/libaltosJNI:
+ mkdir -p classes
+ ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI
+
+classes/images:
+ mkdir -p classes/images
+ ln -sf ../../$(JAVA_ICON) classes/images
+
+altosui:
+ echo "#!/bin/sh" > $@
+ echo "exec java -Djava.library.path=/usr/lib/altos -jar /usr/share/java/altosui.jar" >> $@
+ chmod +x ./altosui
+
+fat/altosui:
+ echo "#!/bin/sh" > $@
+ echo 'ME=`which "$0"`' >> $@
+ echo 'DIR=`dirname "$ME"`' >> $@
+ echo 'exec java -Djava.library.path="$$DIR" -jar "$$DIR"/altosui.jar' >> $@
+ chmod +x $@
+
+fat/altosui.jar: $(CLASSFILES) $(JAVA_ICON) fat/classes/Manifest.txt
+ mkdir -p fat/classes
+ test -L fat/classes/altosui || ln -sf ../.. fat/classes/altosui
+ mkdir -p fat/classes/images
+ cp $(JAVA_ICON) fat/classes/images
+ test -L fat/classes/libaltosJNI || ln -sf ../../../libaltos/libaltosJNI fat/classes/libaltosJNI
+ cd ./fat/classes && jar cfm ../../$@ Manifest.txt images/* altosui/*.class libaltosJNI/*.class
+
+fat/classes/Manifest.txt: $(CLASSFILES) Makefile
+ mkdir -p fat/classes
+ echo 'Main-Class: altosui.AltosUI' > $@
+ echo "Class-Path: freetts.jar" >> $@
+
+install: altosui.jar altosui
+ install -m 0644 altosui.jar $(DESTDIR)/usr/share/java/altosui.jar
+ install -m 0644 altosui.1 $(DESTDIR)/usr/share/man/man1/altosui.1
+ install altosui $(DESTDIR)/usr/bin/altosui
+
+clean:
+ rm -f *.class altosui.jar
+ rm -f AltosUI.app/Contents/Resources/Java/*
+ rm -rf classes
+ rm -rf windows linux
+
+distclean: clean
+ rm -f $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
+ rm -rf darwin fat
+
+FAT_FILES=$(FATJAR) $(FREETTSJAR) $(HEXFILES)
+
+LINUX_FILES=$(FAT_FILES) ../libaltos/libaltos.so fat/altosui
+$(LINUX_TGZ): $(LINUX_FILES)
+ rm -f $@
+ mkdir -p linux/AltOS
+ rm -f linux/AltOS/*
+ cp $(LINUX_FILES) linux/AltOS
+ cd linux && tar czf ../$@ AltOS
+
+DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) ../libaltos/libaltos.dylib
+DARWIN_EXTRA=$(HEXFILES)
+DARWIN_FILES=$(DARWIN_RESOURCES) $(DARWIN_EXTRA)
+
+$(DARWIN_ZIP): $(DARWIN_FILES)
+ rm -f $@
+ cp -a AltosUI.app darwin/
+ mkdir -p darwin/AltosUI.app/Contents/Resources/Java
+ cp $(DARWIN_RESOURCES) darwin/AltosUI.app/Contents/Resources/Java
+ mkdir -p darwin/AltOS
+ cp $(DARWIN_EXTRA) darwin/AltOS
+ cd darwin && zip -r ../$@ AltosUI.app AltOS
+
+WINDOWS_FILES = $(FAT_FILES) ../libaltos/altos.dll ../../telemetrum.inf $(WINDOWS_ICON)
+
+$(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi
+ rm -f $@
+ mkdir -p windows/AltOS
+ rm -f windows/AltOS/*
+ cp $(WINDOWS_FILES) windows/AltOS
+ makensis altos-windows.nsi
--- /dev/null
+SUBDIRS=libaltos
+JAVAROOT=classes
+AM_JAVACFLAGS=-encoding UTF-8
+
+man_MANS=altosui.1
+
+altoslibdir=$(libdir)/altos
+
+CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:libaltos:$(FREETTS)/*:/usr/share/java/*"
+
+bin_SCRIPTS=altosui
+
+altosui_JAVA = \
+ GrabNDrag.java \
+ AltosAscent.java \
+ AltosChannelMenu.java \
+ AltosConfig.java \
+ AltosConfigUI.java \
+ AltosConfigureUI.java \
+ AltosConvert.java \
+ AltosCRCException.java \
+ AltosCSV.java \
+ AltosCSVUI.java \
+ AltosDebug.java \
+ AltosDescent.java \
+ AltosDeviceDialog.java \
+ AltosDevice.java \
+ AltosDisplayThread.java \
+ AltosEepromDownload.java \
+ AltosEepromMonitor.java \
+ AltosEepromIterable.java \
+ AltosEepromRecord.java \
+ AltosFile.java \
+ AltosFlash.java \
+ AltosFlashUI.java \
+ AltosFlightDisplay.java \
+ AltosFlightInfoTableModel.java \
+ AltosFlightReader.java \
+ AltosFlightStatus.java \
+ AltosFlightUI.java \
+ AltosGPS.java \
+ AltosGreatCircle.java \
+ AltosHexfile.java \
+ Altos.java \
+ AltosIgnite.java \
+ AltosIgniteUI.java \
+ AltosInfoTable.java \
+ AltosKML.java \
+ AltosLanded.java \
+ AltosLed.java \
+ AltosLights.java \
+ AltosLine.java \
+ AltosLog.java \
+ AltosPad.java \
+ AltosParse.java \
+ AltosPreferences.java \
+ AltosReader.java \
+ AltosRecord.java \
+ AltosRecordIterable.java \
+ AltosTelemetryReader.java \
+ AltosReplayReader.java \
+ AltosRomconfig.java \
+ AltosRomconfigUI.java \
+ AltosSerial.java \
+ AltosSerialInUseException.java \
+ AltosSerialMonitor.java \
+ AltosSiteMap.java \
+ AltosSiteMapCache.java \
+ AltosSiteMapTile.java \
+ AltosState.java \
+ AltosTelemetry.java \
+ AltosTelemetryIterable.java \
+ AltosUI.java \
+ AltosWriter.java \
+ AltosDataPointReader.java \
+ AltosDataPoint.java \
+ AltosGraph.java \
+ AltosGraphTime.java \
+ AltosGraphUI.java \
+ AltosDataChooser.java \
+ AltosVoice.java
+
+JFREECHART_CLASS= \
+ jfreechart.jar
+
+JCOMMON_CLASS=\
+ jcommon.jar
+
+FREETTS_CLASS= \
+ cmudict04.jar \
+ cmulex.jar \
+ cmu_time_awb.jar \
+ cmutimelex.jar \
+ cmu_us_kal.jar \
+ en_us.jar \
+ freetts.jar
+
+LIBALTOS= \
+ libaltos.so \
+ libaltos.dylib \
+ altos.dll
+
+JAR=altosui.jar
+
+FATJAR=altosui-fat.jar
+
+# Icons
+ICONDIR=$(top_srcdir)/icon
+
+JAVA_ICON=$(ICONDIR)/altus-metrum-16x16.jpg
+
+ICONS= $(ICONDIR)/redled.png $(ICONDIR)/redoff.png \
+ $(ICONDIR)/greenled.png $(ICONDIR)/greenoff.png \
+ $(ICONDIR)/grayled.png $(ICONDIR)/grayoff.png
+
+# icon base names for jar
+ICONJAR= -C $(ICONDIR) altus-metrum-16x16.jpg \
+ -C $(ICONDIR) redled.png -C $(ICONDIR) redoff.png \
+ -C $(ICONDIR) greenled.png -C $(ICONDIR) greenoff.png \
+ -C $(ICONDIR) grayon.png -C $(ICONDIR) grayled.png
+
+WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico
+
+# Firmware
+FIRMWARE_TD=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx
+FIRMWARE_TM=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx
+FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TD)
+
+# Distribution targets
+LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2
+MACOSX_DIST=Altos-Mac-$(VERSION).zip
+WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe
+
+FAT_FILES=$(FATJAR) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
+
+LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE)
+LINUX_EXTRA=altosui-fat
+
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib
+MACOSX_EXTRA=$(FIRMWARE)
+
+WINDOWS_FILES=$(FAT_FILES) altos.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
+
+all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb
+
+clean-local:
+ -rm -rf classes $(JAR) $(FATJAR) \
+ $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(FREETTS_CLASS) \
+ $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \
+ altosui altosui-test altosui-jdb macosx linux
+
+if FATINSTALL
+
+FATTARGET=$(FATDIR)/$(VERSION)
+
+LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
+MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
+WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+
+fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
+
+$(LINUX_DIST_TARGET): $(LINUX_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(MACOSX_DIST_TARGET): $(MACOSX_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+$(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
+ mkdir -p $(FATTARGET)
+ cp -p $< $@
+
+else
+fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST)
+endif
+
+
+altosuidir=$(datadir)/java
+
+install-altosuiJAVA: altosui.jar
+ @$(NORMAL_INSTALL)
+ test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)"
+ echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/altosui.jar'"; \
+ $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)"
+
+classes/altosui:
+ mkdir -p classes/altosui
+
+$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON)
+ jar cfm $@ Manifest.txt \
+ $(ICONJAR) \
+ -C classes altosui \
+ -C libaltos libaltosJNI
+
+$(FATJAR): classaltosui.stamp Manifest-fat.txt $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON)
+ jar cfm $@ Manifest-fat.txt \
+ $(ICONJAR) \
+ -C classes altosui \
+ -C libaltos libaltosJNI
+
+Manifest.txt: Makefile
+ echo 'Main-Class: altosui.AltosUI' > $@
+ echo "Class-Path: $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@
+
+Manifest-fat.txt:
+ echo 'Main-Class: altosui.AltosUI' > $@
+ echo "Class-Path: freetts.jar jfreechart.jar jcommon.jar" >> $@
+
+altosui: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@
+ chmod +x $@
+
+altosui-test: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" -jar altosui.jar "$$@"' >> $@
+ chmod +x $@
+
+altosui-jdb: Makefile
+ echo "#!/bin/sh" > $@
+ echo 'exec jdb -classpath "classes:libaltos:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="libaltos/.libs" altosui/AltosUI "$$@"' >> $@
+ chmod +x $@
+
+libaltos.so:
+ -rm -f "$@"
+ $(LN_S) libaltos/.libs/"$@" .
+
+libaltos.dylib:
+ -rm -f "$@"
+ $(LN_S) libaltos/"$@" .
+
+altos.dll:
+ -rm -f "$@"
+ $(LN_S) libaltos/"$@" .
+
+$(FREETTS_CLASS):
+ -rm -f "$@"
+ $(LN_S) "$(FREETTS)"/"$@" .
+
+$(JFREECHART_CLASS):
+ -rm -f "$@"
+ $(LN_S) "$(JFREECHART)"/"$@" .
+
+$(JCOMMON_CLASS):
+ -rm -f "$@"
+ $(LN_S) "$(JCOMMON)"/"$@" .
+
+$(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
+ -rm -f $@
+ -rm -rf linux
+ mkdir -p linux/AltOS
+ cp -p $(LINUX_FILES) linux/AltOS
+ cp -p altosui-fat linux/AltOS/altosui
+ chmod +x linux/AltOS/altosui
+ tar cjf $@ -C linux AltOS
+
+$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA)
+ -rm -f $@
+ -rm -rf macosx
+ mkdir macosx
+ cp -a AltosUI.app macosx/
+ mkdir -p macosx/AltOS macosx/AltosUI.app/Contents/Resources/Java
+ cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
+ cp -p $(FREETTS_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
+ cp -p $(JFREECHART_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
+ cp -p $(MACOSX_EXTRA) macosx/AltOS
+ cd macosx && zip -r ../$@ AltosUI.app AltOS
+
+$(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi
+ -rm -f $@
+ makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi
--- /dev/null
+!addplugindir Instdrv/NSIS/Plugins
+
+Name "Altus Metrum Installer"
+
+; Default install directory
+InstallDir "$PROGRAMFILES\AltusMetrum"
+
+; Tell the installer where to re-install a new version
+InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir"
+
+LicenseText "GNU General Public License Version 2"
+LicenseData "../../COPYING"
+
+; Need admin privs for Vista or Win7
+RequestExecutionLevel admin
+
+ShowInstDetails Show
+
+ComponentText "Altus Metrum Software and Driver Installer"
+
+; Pages to present
+
+Page license
+Page components
+Page directory
+Page instfiles
+
+UninstPage uninstConfirm
+UninstPage instfiles
+
+; And the stuff to install
+
+Section "Install Driver" InstDriver
+ InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum"
+ Pop $0
+ DetailPrint "InitDriverSetup: $0"
+
+ InstDrv::DeleteOemInfFiles /NOUNLOAD
+ InstDrv::CreateDevice /NOUNLOAD
+ SetOutPath $TEMP
+ File "../../telemetrum.inf"
+ InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf"
+
+ SetOutPath $INSTDIR
+ File "../../telemetrum.inf"
+SectionEnd
+
+Section "AltosUI Application"
+ SetOutPath $INSTDIR
+
+ File "altosui-fat.jar"
+ File "cmudict04.jar"
+ File "cmulex.jar"
+ File "cmu_time_awb.jar"
+ File "cmutimelex.jar"
+ File "cmu_us_kal.jar"
+ File "en_us.jar"
+ File "freetts.jar"
+
+ File "*.dll"
+
+ File "../../icon/*.ico"
+
+ CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico"
+SectionEnd
+
+Section "AltosUI Desktop Shortcut"
+ CreateShortCut "$DESKTOP\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico"
+SectionEnd
+
+Section "TeleMetrum and TeleDongle Firmware"
+
+ SetOutPath $INSTDIR
+
+ File "../../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx"
+ File "../../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
+
+SectionEnd
+
+Section "Uninstaller"
+
+ ; Deal with the uninstaller
+
+ SetOutPath $INSTDIR
+
+ ; Write the install path to the registry
+ WriteRegStr HKLM SOFTWARE\AltusMetrum "Install_Dir" "$INSTDIR"
+
+ ; Write the uninstall keys for windows
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "DisplayName" "Altus Metrum"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "UninstallString" '"$INSTDIR\uninstall.exe"'
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoModify" "1"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoRepair" "1"
+
+ WriteUninstaller "uninstall.exe"
+SectionEnd
+
+Section "Uninstall"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum"
+ DeleteRegKey HKLM "Software\AltusMetrum"
+
+ Delete "$INSTDIR\*.*"
+ RMDir "$INSTDIR"
+
+ ; Remove devices
+ InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum"
+ InstDrv::DeleteOemInfFiles /NOUNLOAD
+ InstDrv::RemoveAllDevices
+
+ ; Remove shortcuts, if any
+ Delete "$SMPROGRAMS\AltusMetrum.lnk"
+ Delete "$DESKTOP\AltusMetrum.lnk"
+SectionEnd
--- /dev/null
+#!/bin/sh
+me=`which "$0"`
+dir=`dirname "$me"`
+exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/altosui-fat.jar "$@"
--- /dev/null
+.\"
+.\" Copyright © 2010 Bdale Garbee <bdale@gag.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; 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
+.\" 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.
+.\"
+.\"
+.TH ALTOSUI 1 "altosui" ""
+.SH NAME
+altosui \- Rocket flight monitor
+.SH SYNOPSIS
+.B "altosui"
+.SH DESCRIPTION
+.I altosui
+connects to a TeleDongle or TeleMetrum device through a USB serial device.
+It provides a menu-oriented
+user interface to monitor, record and review rocket flight data.
+.SH USAGE
+When connected to a TeleDongle device, altosui turns on the radio
+receiver and listens for telemetry packets. It displays the received
+telemetry data, and reports flight status via voice synthesis. All
+received telemetry information is recorded to a file.
+.P
+When connected to a TeleMetrum device, altosui can be used to configure the
+TeleMetrum, and to downloads the eeprom data and store it in a file.
+.P
+A number of other menu options exist, including the ability to export flight
+data in different formats.
+.SH FILES
+All data log files are recorded into a user-specified directory
+(default ~/TeleMetrum). Files are named using the current date, the serial
+number of the reporting device, the flight number recorded in the data
+and either '.telem' for telemetry data or '.eeprom' for eeprom data.
+.SH AUTHOR
+Keith Packard
--- /dev/null
+*.so
+*.lo
+*.la
+*.java
+*.class
+.libs/
+classlibaltos.stamp
+libaltos_wrap.c
+libaltosJNI
+cjnitest
+libaltos.swig
+swig_bindings/
--- /dev/null
+OS:=$(shell uname)
+
+#
+# Linux
+#
+ifeq ($(OS),Linux)
+
+JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include
+
+OS_LIB_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS)
+
+OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
+
+OS_LDFLAGS=
+
+LIBNAME=libaltos.so
+EXEEXT=
+endif
+
+#
+# Darwin (Mac OS X)
+#
+ifeq ($(OS),Darwin)
+
+OS_LIB_CFLAGS=\
+ -DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 \
+ --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
+OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
+
+OS_LDFLAGS =\
+ -framework IOKit -framework CoreFoundation
+
+LIBNAME=libaltos.dylib
+EXEEXT=
+
+endif
+
+#
+# Windows
+#
+ifneq (,$(findstring MINGW,$(OS)))
+
+CC=gcc
+
+OS_LIB_CFLAGS = -DWINDOWS -mconsole -DBUILD_DLL
+OS_APP_CFLAGS = -DWINDOWS -mconsole
+
+OS_LDFLAGS = -lgdi32 -luser32 -lcfgmgr32 -lsetupapi -lole32 \
+ -ladvapi32 -lcomctl32 -mconsole -Wl,--add-stdcall-alias
+
+LIBNAME=altos.dll
+
+EXEEXT=.exe
+
+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
+
+CJNITEST=cjnitest$(EXEEXT)
+
+all: $(LIBNAME) $(CJNITEST) $(CLASSFILES)
+
+.java.class:
+ javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
+
+CFLAGS=$(OS_LIB_CFLAGS) -O -I.
+
+LDFLAGS=$(OS_LDFLAGS)
+
+HEADERS=libaltos.h
+SRCS = libaltos.c $(SWIG_WRAP)
+OBJS = $(SRCS:%.c=%.o)
+LIBS = $(DARWIN_LIBS)
+
+$(CJNITEST): cjnitest.c $(LIBNAME)
+ $(CC) -o $@ $(OS_APP_CFLAGS) cjnitest.c $(LIBNAME) $(LIBS) $(LDFLAGS)
+
+$(LIBNAME): $(OBJS)
+ $(CC) -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
+
+clean:
+ rm -f $(CLASSFILES) $(OBJS) $(LIBNAME) $(CJNITEST) cjnitest.o
+ rm -rf swig_bindings libaltosJNI
+
+distclean: clean
+
+$(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)
+
+ifeq ($(OS),Linux)
+install: $(LIBNAME)
+ install -c $(LIBNAME) $(DESTDIR)/usr/lib/altos/$(LIBNAME)
+
+endif
+
+.NOTPARALLEL:
--- /dev/null
+JAVAC=javac
+AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
+AM_JAVACFLAGS=-encoding UTF-8
+
+altoslibdir=$(libdir)/altos
+
+altoslib_LTLIBRARIES=libaltos.la
+
+libaltos_la_LDFLAGS = -version-info 1:0:1
+
+libaltos_la_SOURCES=\
+ libaltos.c \
+ libaltos_wrap.c
+
+noinst_PROGRAMS=cjnitest
+
+cjnitest_LDADD=libaltos.la
+
+LIBS=
+
+HFILES=libaltos.h
+
+SWIG_FILE=libaltos.swig
+
+CLASSDIR=libaltosJNI
+
+$(SWIG_FILE): libaltos.i0 $(HFILES)
+ sed 's;//%;%;' libaltos.i0 $(HFILES) > $(SWIG_FILE)
+
+all-local: classlibaltos.stamp
+
+libaltos_wrap.c: classlibaltos.stamp
+
+classlibaltos.stamp: $(SWIG_FILE)
+ swig -java -package libaltosJNI $(SWIG_FILE)
+ mkdir -p libaltosJNI
+ $(JAVAC) -d . $(AM_JAVACFLAGS) $(JAVACFLAGS) *.java && \
+ touch classlibaltos.stamp
+
+clean-local:
+ -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c
--- /dev/null
+#include <stdio.h>
+#include "libaltos.h"
+
+static void
+altos_puts(struct altos_file *file, char *string)
+{
+ char c;
+
+ while ((c = *string++))
+ altos_putchar(file, c);
+}
+
+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;
+
+ printf ("%04x:%04x %-20s %4d %s\n", device.vendor, device.product,
+ device.name, device.serial, device.path);
+
+ file = altos_open(&device);
+ if (!file) {
+ printf("altos_open failed\n");
+ continue;
+ }
+ altos_puts(file,"v\nc s\n");
+ altos_flush(file);
+ while ((c = altos_getchar(file, 100)) >= 0) {
+ putchar (c);
+ }
+ if (c != LIBALTOS_TIMEOUT)
+ printf ("getchar returns %d\n", c);
+ altos_close(file);
+ }
+ altos_list_finish(list);
+ altos_fini();
+}
--- /dev/null
+/*
+ * 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>
+
+#define USE_POLL
+
+PUBLIC int
+altos_init(void)
+{
+ return LIBALTOS_SUCCESS;
+}
+
+PUBLIC void
+altos_fini(void)
+{
+}
+
+#ifdef DARWIN
+
+#undef USE_POLL
+
+/* 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
+
+/*
+ * Scan for Altus Metrum devices by looking through /sys
+ */
+
+#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_name;
+ 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_name = 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_name);
+ /* 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;
+};
+
+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 (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) {
+ 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->name, dev->product_name);
+ device->vendor = dev->idVendor;
+ device->product = dev->idProduct;
+ 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;
+}
+
+static int
+get_number(io_object_t object, CFStringRef entry, int *result)
+{
+ CFTypeRef entry_as_number;
+ Boolean got_number;
+
+ entry_as_number = IORegistryEntrySearchCFProperty (object,
+ kIOServicePlane,
+ entry,
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively);
+ if (entry_as_number) {
+ got_number = CFNumberGetValue(entry_as_number,
+ kCFNumberIntType,
+ result);
+ if (got_number)
+ return 1;
+ }
+ return 0;
+}
+
+struct altos_list *
+altos_list_start(void)
+{
+ struct altos_list *list = calloc (sizeof (struct altos_list), 1);
+ CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
+ io_iterator_t tdIterator;
+ io_object_t tdObject;
+ kern_return_t ret;
+ int i;
+
+ ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
+ if (ret != kIOReturnSuccess)
+ return NULL;
+ 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_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
+ !get_number (object, CFSTR(kUSBProductID), &device->product))
+ continue;
+ if (device->vendor != 0xfffe)
+ continue;
+ if (device->product < 0x000a || 0x0013 < device->product)
+ continue;
+ if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
+ get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
+ 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;
+#ifdef USE_POLL
+ int pipe[2];
+#else
+ int out_fd;
+#endif
+ unsigned char out_data[USB_BUF_SIZE];
+ int out_used;
+ unsigned char in_data[USB_BUF_SIZE];
+ int in_used;
+ int in_read;
+};
+
+PUBLIC 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;
+ }
+#ifdef USE_POLL
+ pipe(file->pipe);
+#else
+ file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
+ if (file->out_fd < 0) {
+ perror(device->path);
+ close(file->fd);
+ free(file);
+ return NULL;
+ }
+#endif
+ ret = tcgetattr(file->fd, &term);
+ if (ret < 0) {
+ perror("tcgetattr");
+ close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
+ free(file);
+ return NULL;
+ }
+ cfmakeraw(&term);
+#ifdef USE_POLL
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+#else
+ term.c_cc[VMIN] = 0;
+ term.c_cc[VTIME] = 1;
+#endif
+ ret = tcsetattr(file->fd, TCSAFLUSH, &term);
+ if (ret < 0) {
+ perror("tcsetattr");
+ close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
+ free(file);
+ return NULL;
+ }
+ return file;
+}
+
+PUBLIC void
+altos_close(struct altos_file *file)
+{
+ if (file->fd != -1) {
+ int fd = file->fd;
+ file->fd = -1;
+#ifdef USE_POLL
+ write(file->pipe[1], "\r", 1);
+#else
+ close(file->out_fd);
+ file->out_fd = -1;
+#endif
+ close(fd);
+ }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+ altos_close(file);
+ free(file);
+}
+
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+ if (file->out_used && 0) {
+ printf ("flush \"");
+ fwrite(file->out_data, 1, file->out_used, stdout);
+ printf ("\"\n");
+ }
+ while (file->out_used) {
+ int ret;
+
+ if (file->fd < 0)
+ return -EBADF;
+#ifdef USE_POLL
+ ret = write (file->fd, file->out_data, file->out_used);
+#else
+ ret = write (file->out_fd, file->out_data, file->out_used);
+#endif
+ if (ret < 0)
+ return -errno;
+ if (ret) {
+ memmove(file->out_data, file->out_data + ret,
+ file->out_used - ret);
+ file->out_used -= ret;
+ }
+ }
+ return 0;
+}
+
+PUBLIC 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;
+ ret = 0;
+ if (file->out_used == USB_BUF_SIZE)
+ ret = altos_flush(file);
+ return 0;
+}
+
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
+static int
+altos_fill(struct altos_file *file, int timeout)
+{
+ int ret;
+#ifdef USE_POLL
+ struct pollfd fd[2];
+#endif
+
+ if (timeout == 0)
+ timeout = -1;
+ while (file->in_read == file->in_used) {
+ if (file->fd < 0)
+ return LIBALTOS_ERROR;
+#ifdef USE_POLL
+ fd[0].fd = file->fd;
+ fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
+ fd[1].fd = file->pipe[0];
+ fd[1].events = POLLIN;
+ ret = poll(fd, 2, timeout);
+ if (ret < 0) {
+ perror("altos_getchar");
+ return LIBALTOS_ERROR;
+ }
+ if (ret == 0)
+ return LIBALTOS_TIMEOUT;
+
+ if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
+ return LIBALTOS_ERROR;
+ if (fd[0].revents & POLLIN)
+#endif
+ {
+ ret = read(file->fd, file->in_data, USB_BUF_SIZE);
+ if (ret < 0) {
+ perror("altos_getchar");
+ return LIBALTOS_ERROR;
+ }
+ file->in_read = 0;
+ file->in_used = ret;
+#ifndef USE_POLL
+ if (ret == 0 && timeout > 0)
+ return LIBALTOS_TIMEOUT;
+#endif
+ }
+ }
+ if (file->in_used && 0) {
+ printf ("fill \"");
+ fwrite(file->in_data, 1, file->in_used, stdout);
+ printf ("\"\n");
+ }
+ return 0;
+}
+
+PUBLIC int
+altos_getchar(struct altos_file *file, int timeout)
+{
+ int ret;
+ while (file->in_read == file->in_used) {
+ if (file->fd < 0)
+ return LIBALTOS_ERROR;
+ ret = altos_fill(file, timeout);
+ if (ret)
+ return ret;
+ }
+ return file->in_data[file->in_read++];
+}
+
+#endif /* POSIX_TTY */
+
+#ifdef WINDOWS
+
+#include <stdlib.h>
+#include <windows.h>
+#include <setupapi.h>
+
+struct altos_list {
+ HDEVINFO dev_info;
+ int index;
+};
+
+#define USB_BUF_SIZE 64
+
+struct altos_file {
+ HANDLE handle;
+ unsigned char out_data[USB_BUF_SIZE];
+ int out_used;
+ unsigned char in_data[USB_BUF_SIZE];
+ int in_used;
+ int in_read;
+ OVERLAPPED ov_read;
+ BOOL pend_read;
+ OVERLAPPED ov_write;
+};
+
+PUBLIC struct altos_list *
+altos_list_start(void)
+{
+ struct altos_list *list = calloc(1, sizeof (struct altos_list));
+
+ if (!list)
+ return NULL;
+ list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
+ DIGCF_ALLCLASSES|DIGCF_PRESENT);
+ if (list->dev_info == INVALID_HANDLE_VALUE) {
+ printf("SetupDiGetClassDevs failed %d\n", GetLastError());
+ free(list);
+ return NULL;
+ }
+ list->index = 0;
+ return list;
+}
+
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+ SP_DEVINFO_DATA dev_info_data;
+ char port[128];
+ DWORD port_len;
+ char friendlyname[256];
+ char symbolic[256];
+ DWORD symbolic_len;
+ HKEY dev_key;
+ int vid, pid;
+ int serial;
+ HRESULT result;
+ DWORD friendlyname_type;
+ DWORD friendlyname_len;
+
+ dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
+ while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
+ &dev_info_data))
+ {
+ list->index++;
+
+ dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
+ DICS_FLAG_GLOBAL, 0, DIREG_DEV,
+ KEY_READ);
+ if (dev_key == INVALID_HANDLE_VALUE) {
+ printf("cannot open device registry key\n");
+ continue;
+ }
+
+ /* Fetch symbolic name for this device and parse out
+ * the vid/pid/serial info */
+ symbolic_len = sizeof(symbolic);
+ result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
+ symbolic, &symbolic_len);
+ if (result != 0) {
+ printf("cannot find SymbolicName value\n");
+ RegCloseKey(dev_key);
+ continue;
+ }
+ vid = pid = serial = 0;
+ sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1,
+ "%04X", &vid);
+ sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
+ "%04X", &pid);
+ sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
+ "%d", &serial);
+ if (!USB_IS_ALTUSMETRUM(vid, pid)) {
+ RegCloseKey(dev_key);
+ continue;
+ }
+
+ /* Fetch the com port name */
+ port_len = sizeof (port);
+ result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
+ port, &port_len);
+ RegCloseKey(dev_key);
+ if (result != 0) {
+ printf("failed to get PortName\n");
+ continue;
+ }
+
+ /* Fetch the device description which is the device name,
+ * with firmware that has unique USB ids */
+ friendlyname_len = sizeof (friendlyname);
+ if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
+ &dev_info_data,
+ SPDRP_FRIENDLYNAME,
+ &friendlyname_type,
+ (BYTE *)friendlyname,
+ sizeof(friendlyname),
+ &friendlyname_len))
+ {
+ printf("Failed to get friendlyname\n");
+ continue;
+ }
+ device->vendor = vid;
+ device->product = pid;
+ device->serial = serial;
+ strcpy(device->name, friendlyname);
+
+ strcpy(device->path, port);
+ return 1;
+ }
+ result = GetLastError();
+ if (result != ERROR_NO_MORE_ITEMS)
+ printf ("SetupDiEnumDeviceInfo failed error %d\n", result);
+ return 0;
+}
+
+PUBLIC void
+altos_list_finish(struct altos_list *list)
+{
+ SetupDiDestroyDeviceInfoList(list->dev_info);
+ free(list);
+}
+
+static int
+altos_queue_read(struct altos_file *file)
+{
+ DWORD got;
+ if (file->pend_read)
+ return LIBALTOS_SUCCESS;
+
+ if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
+ if (GetLastError() != ERROR_IO_PENDING)
+ return LIBALTOS_ERROR;
+ file->pend_read = TRUE;
+ } else {
+ file->pend_read = FALSE;
+ file->in_read = 0;
+ file->in_used = got;
+ }
+ return LIBALTOS_SUCCESS;
+}
+
+static int
+altos_wait_read(struct altos_file *file, int timeout)
+{
+ DWORD ret;
+ DWORD got;
+
+ if (!file->pend_read)
+ return LIBALTOS_SUCCESS;
+
+ if (!timeout)
+ timeout = INFINITE;
+
+ ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
+ switch (ret) {
+ case WAIT_OBJECT_0:
+ if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE))
+ return LIBALTOS_ERROR;
+ file->pend_read = FALSE;
+ file->in_read = 0;
+ file->in_used = got;
+ break;
+ case WAIT_TIMEOUT:
+ return LIBALTOS_TIMEOUT;
+ break;
+ default:
+ return LIBALTOS_ERROR;
+ }
+ return LIBALTOS_SUCCESS;
+}
+
+static int
+altos_fill(struct altos_file *file, int timeout)
+{
+ int ret;
+
+ if (file->in_read < file->in_used)
+ return LIBALTOS_SUCCESS;
+
+ file->in_read = file->in_used = 0;
+
+ ret = altos_queue_read(file);
+ if (ret)
+ return ret;
+ ret = altos_wait_read(file, timeout);
+ if (ret)
+ return ret;
+
+ return LIBALTOS_SUCCESS;
+}
+
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+ DWORD put;
+ char *data = file->out_data;
+ char used = file->out_used;
+ DWORD ret;
+
+ while (used) {
+ if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
+ if (GetLastError() != ERROR_IO_PENDING)
+ return LIBALTOS_ERROR;
+ ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
+ switch (ret) {
+ case WAIT_OBJECT_0:
+ if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE))
+ return LIBALTOS_ERROR;
+ break;
+ default:
+ return LIBALTOS_ERROR;
+ }
+ }
+ data += put;
+ used -= put;
+ }
+ file->out_used = 0;
+ return LIBALTOS_SUCCESS;
+}
+
+PUBLIC struct altos_file *
+altos_open(struct altos_device *device)
+{
+ struct altos_file *file = calloc (1, sizeof (struct altos_file));
+ char full_name[64];
+ DCB dcbSerialParams = {0};
+ COMMTIMEOUTS timeouts;
+
+ if (!file)
+ return NULL;
+
+ strcpy(full_name, "\\\\.\\");
+ strcat(full_name, device->path);
+ file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
+ if (file->handle == INVALID_HANDLE_VALUE) {
+ free(file);
+ return NULL;
+ }
+ file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ timeouts.ReadIntervalTimeout = MAXDWORD;
+ timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+ timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
+ timeouts.WriteTotalTimeoutMultiplier = 0;
+ timeouts.WriteTotalTimeoutConstant = 0;
+ SetCommTimeouts(file->handle, &timeouts);
+
+ dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
+ if (!GetCommState(file->handle, &dcbSerialParams)) {
+ CloseHandle(file->handle);
+ free(file);
+ return NULL;
+ }
+ dcbSerialParams.BaudRate = CBR_9600;
+ dcbSerialParams.ByteSize = 8;
+ dcbSerialParams.StopBits = ONESTOPBIT;
+ dcbSerialParams.Parity = NOPARITY;
+ if (!SetCommState(file->handle, &dcbSerialParams)) {
+ CloseHandle(file->handle);
+ free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+PUBLIC void
+altos_close(struct altos_file *file)
+{
+ if (file->handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(file->handle);
+ file->handle = INVALID_HANDLE_VALUE;
+ }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+ altos_close(file);
+ 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 LIBALTOS_SUCCESS;
+}
+
+int
+altos_getchar(struct altos_file *file, int timeout)
+{
+ int ret;
+ while (file->in_read == file->in_used) {
+ if (file->handle == INVALID_HANDLE_VALUE)
+ return LIBALTOS_ERROR;
+ ret = altos_fill(file, timeout);
+ if (ret)
+ return ret;
+ }
+ return file->in_data[file->in_read++];
+}
+
+#endif
--- /dev/null
+/*
+ * 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_
+
+#include <stdlib.h>
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+# ifndef BUILD_STATIC
+# ifdef BUILD_DLL
+# define PUBLIC __declspec(dllexport)
+# else
+# define PUBLIC __declspec(dllimport)
+# endif
+# endif /* BUILD_STATIC */
+#endif
+
+#ifndef PUBLIC
+# define PUBLIC
+#endif
+
+#define USB_VENDOR_FSF 0xfffe
+#define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF
+#define USB_PRODUCT_ALTUSMETRUM 0x000a
+#define USB_PRODUCT_TELEMETRUM 0x000b
+#define USB_PRODUCT_TELEDONGLE 0x000c
+#define USB_PRODUCT_TELETERRA 0x000d
+#define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a
+#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013
+
+#define USB_IS_ALTUSMETRUM(v,p) ((v) == USB_VENDOR_ALTUSMETRUM && \
+ (USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \
+ (p) <= USB_PRODUCT_ALTUSMETRUM_MAX))
+
+struct altos_device {
+ //%immutable;
+ int vendor;
+ int product;
+ int serial;
+ char name[256];
+ char path[256];
+ //%mutable;
+};
+
+#define LIBALTOS_SUCCESS 0
+#define LIBALTOS_ERROR -1
+#define LIBALTOS_TIMEOUT -2
+
+/* Returns 0 for success, < 0 on error */
+PUBLIC int
+altos_init(void);
+
+PUBLIC void
+altos_fini(void);
+
+PUBLIC struct altos_list *
+altos_list_start(void);
+
+/* Returns 1 for success, zero on end of list */
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device);
+
+PUBLIC void
+altos_list_finish(struct altos_list *list);
+
+PUBLIC struct altos_file *
+altos_open(struct altos_device *device);
+
+PUBLIC void
+altos_close(struct altos_file *file);
+
+PUBLIC void
+altos_free(struct altos_file *file);
+
+/* Returns < 0 for error */
+PUBLIC int
+altos_putchar(struct altos_file *file, char c);
+
+/* Returns < 0 for error */
+PUBLIC int
+altos_flush(struct altos_file *file);
+
+/* Returns < 0 for error or timeout. timeout of 0 == wait forever */
+PUBLIC int
+altos_getchar(struct altos_file *file, int timeout);
+
+#endif /* _LIBALTOS_H_ */
--- /dev/null
+%module libaltos
+%{
+#include "libaltos.h"
+%}
+
-SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view libaltos altosui
+SUBDIRS=lib ao-rawload ao-dbg ao-dumplog ao-bitbang ao-eeprom ao-list ao-load ao-postflight ao-view
+++ /dev/null
-windows/
-linux/
-macosx/
-fat/
-Manifest.txt
-Manifest-fat.txt
-libaltosJNI
-classes
-altosui
-altosui-test
-classaltosui.stamp
-Altos-Linux-*.tar.bz2
-Altos-Mac-*.zip
-Altos-Windows-*.exe
-*.dll
-*.dylib
-*.so
-*.jar
-*.class
+++ /dev/null
-<pkg-contents spec="1.12"><f n="AltosUI.app" o="keithp" g="keithp" p="16877" pt="/Users/keithp/altos/ao-tools/altosui/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></f></f></pkg-contents>
\ No newline at end of file
+++ /dev/null
-<pkgref spec="1.12" uuid="C5762664-2F26-4536-94C4-56F0FBC08D1A"><config><identifier>org.altusmetrum.altosUi.AltosUI.pkg</identifier><version>0.7</version><description></description><post-install type="none"/><installFrom relative="true" mod="true">AltosUI.app</installFrom><installTo mod="true" relocatable="true">/Applications/AltosUI.app</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>installTo.path</mod><mod>installFrom.isRelativeType</mod><mod>version</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
+++ /dev/null
-<pkmkdoc spec="1.12"><properties><title>AltOS UI</title><build>/Users/keithp/altos/ao-tools/altosui/AltosUI.pkg</build><organization>org.altusmetrum</organization><userSees ui="both"/><min-target os="3"/><domain system="true" user="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><description>Install AltOS User Interface</description><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="tofit" bg-align="center"><locale lang="en"><resource relative="true" mod="true" type="background">altusmetrum.jpg</resource></locale></resources><flags/><item type="file">01altosui.xml</item><mod>properties.anywhereDomain</mod><mod>properties.title</mod><mod>properties.customizeOption</mod><mod>description</mod><mod>properties.userDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.util.*;
-import java.text.*;
-
-public class Altos {
- /* EEProm command letters */
- static final int AO_LOG_FLIGHT = 'F';
- static final int AO_LOG_SENSOR = 'A';
- static final int AO_LOG_TEMP_VOLT = 'T';
- static final int AO_LOG_DEPLOY = 'D';
- static final int AO_LOG_STATE = 'S';
- static final int AO_LOG_GPS_TIME = 'G';
- static final int AO_LOG_GPS_LAT = 'N';
- static final int AO_LOG_GPS_LON = 'W';
- static final int AO_LOG_GPS_ALT = 'H';
- static final int AO_LOG_GPS_SAT = 'V';
- static final int AO_LOG_GPS_DATE = 'Y';
-
- /* Added for header fields in eeprom files */
- static final int AO_LOG_CONFIG_VERSION = 1000;
- static final int AO_LOG_MAIN_DEPLOY = 1001;
- static final int AO_LOG_APOGEE_DELAY = 1002;
- static final int AO_LOG_RADIO_CHANNEL = 1003;
- static final int AO_LOG_CALLSIGN = 1004;
- static final int AO_LOG_ACCEL_CAL = 1005;
- static final int AO_LOG_RADIO_CAL = 1006;
- static final int AO_LOG_MANUFACTURER = 1007;
- static final int AO_LOG_PRODUCT = 1008;
- static final int AO_LOG_SERIAL_NUMBER = 1009;
- static final int AO_LOG_SOFTWARE_VERSION = 1010;
-
- /* Added to flag invalid records */
- static final int AO_LOG_INVALID = -1;
-
- /* Flight state numbers and names */
- static final int ao_flight_startup = 0;
- static final int ao_flight_idle = 1;
- static final int ao_flight_pad = 2;
- static final int ao_flight_boost = 3;
- static final int ao_flight_fast = 4;
- static final int ao_flight_coast = 5;
- static final int ao_flight_drogue = 6;
- static final int ao_flight_main = 7;
- static final int ao_flight_landed = 8;
- static final int ao_flight_invalid = 9;
-
- static HashMap<String,Integer> string_to_state = new HashMap<String,Integer>();
-
- static boolean map_initialized = false;
-
- static final int tab_elt_pad = 5;
-
- static final Font label_font = new Font("Dialog", Font.PLAIN, 22);
- static final Font value_font = new Font("Monospaced", Font.PLAIN, 22);
- static final Font status_font = new Font("SansSerif", Font.BOLD, 24);
-
- static final int text_width = 16;
-
- static void initialize_map()
- {
- string_to_state.put("startup", ao_flight_startup);
- string_to_state.put("idle", ao_flight_idle);
- string_to_state.put("pad", ao_flight_pad);
- string_to_state.put("boost", ao_flight_boost);
- string_to_state.put("fast", ao_flight_fast);
- string_to_state.put("coast", ao_flight_coast);
- string_to_state.put("drogue", ao_flight_drogue);
- string_to_state.put("main", ao_flight_main);
- string_to_state.put("landed", ao_flight_landed);
- string_to_state.put("invalid", ao_flight_invalid);
- map_initialized = true;
- }
-
- static String[] state_to_string = {
- "startup",
- "idle",
- "pad",
- "boost",
- "fast",
- "coast",
- "drogue",
- "main",
- "landed",
- "invalid",
- };
-
- static public int state(String state) {
- if (!map_initialized)
- initialize_map();
- if (string_to_state.containsKey(state))
- return string_to_state.get(state);
- return ao_flight_invalid;
- }
-
- static public String state_name(int state) {
- if (state < 0 || state_to_string.length <= state)
- return "invalid";
- return state_to_string[state];
- }
-
- static final int AO_GPS_VALID = (1 << 4);
- static final int AO_GPS_RUNNING = (1 << 5);
- static final int AO_GPS_DATE_VALID = (1 << 6);
- static final int AO_GPS_NUM_SAT_SHIFT = 0;
- static final int AO_GPS_NUM_SAT_MASK = 0xf;
-
- static boolean isspace(int c) {
- switch (c) {
- case ' ':
- case '\t':
- return true;
- }
- return false;
- }
-
- static boolean ishex(int c) {
- if ('0' <= c && c <= '9')
- return true;
- if ('a' <= c && c <= 'f')
- return true;
- if ('A' <= c && c <= 'F')
- return true;
- return false;
- }
-
- static boolean ishex(String s) {
- for (int i = 0; i < s.length(); i++)
- if (!ishex(s.charAt(i)))
- return false;
- return true;
- }
-
- static int fromhex(int c) {
- if ('0' <= c && c <= '9')
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - 'a' + 10;
- if ('A' <= c && c <= 'F')
- return c - 'A' + 10;
- return -1;
- }
-
- static int fromhex(String s) throws NumberFormatException {
- int c, v = 0;
- for (int i = 0; i < s.length(); i++) {
- c = s.charAt(i);
- if (!ishex(c)) {
- if (i == 0)
- throw new NumberFormatException(String.format("invalid hex \"%s\"", s));
- return v;
- }
- v = v * 16 + fromhex(c);
- }
- return v;
- }
-
- static boolean isdec(int c) {
- if ('0' <= c && c <= '9')
- return true;
- return false;
- }
-
- static boolean isdec(String s) {
- for (int i = 0; i < s.length(); i++)
- if (!isdec(s.charAt(i)))
- return false;
- return true;
- }
-
- static int fromdec(int c) {
- if ('0' <= c && c <= '9')
- return c - '0';
- return -1;
- }
-
- static int fromdec(String s) throws NumberFormatException {
- int c, v = 0;
- int sign = 1;
- for (int i = 0; i < s.length(); i++) {
- c = s.charAt(i);
- if (i == 0 && c == '-') {
- sign = -1;
- } else if (!isdec(c)) {
- if (i == 0)
- throw new NumberFormatException(String.format("invalid number \"%s\"", s));
- return v;
- } else
- v = v * 10 + fromdec(c);
- }
- return v * sign;
- }
-
- static String replace_extension(String input, String extension) {
- int dot = input.lastIndexOf(".");
- if (dot > 0)
- input = input.substring(0,dot);
- return input.concat(extension);
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosAscent extends JComponent implements AltosFlightDisplay {
- GridBagLayout layout;
-
- public class AscentStatus {
- JLabel label;
- JTextField value;
- AltosLights lights;
-
- void show(AltosState state, int crc_errors) {}
- void reset() {
- value.setText("");
- lights.set(false);
- }
-
- public AscentStatus (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- lights = new AltosLights();
- c.gridx = 0; c.gridy = y;
- c.anchor = GridBagConstraints.CENTER;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(lights, c);
- add(lights);
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 2; c.gridy = y;
- c.gridwidth = 2;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
-
- }
- }
-
- public class AscentValue {
- JLabel label;
- JTextField value;
- void show(AltosState state, int crc_errors) {}
-
- void reset() {
- value.setText("");
- }
- public AscentValue (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 2; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.gridwidth = 2;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
- }
- }
-
- public class AscentValueHold {
- JLabel label;
- JTextField value;
- JTextField max_value;
- double max;
-
- void show(AltosState state, int crc_errors) {}
-
- void reset() {
- value.setText("");
- max_value.setText("");
- max = 0;
- }
-
- void show(String format, double v) {
- value.setText(String.format(format, v));
- if (v > max) {
- max_value.setText(String.format(format, v));
- max = v;
- }
- }
- public AscentValueHold (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 2; c.gridy = y;
- c.anchor = GridBagConstraints.EAST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
-
- max_value = new JTextField(Altos.text_width);
- max_value.setFont(Altos.value_font);
- max_value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 3; c.gridy = y;
- c.anchor = GridBagConstraints.EAST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(max_value, c);
- add(max_value);
- }
- }
-
-
- class Height extends AscentValueHold {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m", state.height);
- }
- public Height (GridBagLayout layout, int y) {
- super (layout, y, "Height");
- }
- }
-
- Height height;
-
- class Speed extends AscentValueHold {
- void show (AltosState state, int crc_errors) {
- double speed = state.speed;
- if (!state.ascent)
- speed = state.baro_speed;
- show("%6.0f m/s", speed);
- }
- public Speed (GridBagLayout layout, int y) {
- super (layout, y, "Speed");
- }
- }
-
- Speed speed;
-
- class Accel extends AscentValueHold {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m/s²", state.acceleration);
- }
- public Accel (GridBagLayout layout, int y) {
- super (layout, y, "Acceleration");
- }
- }
-
- Accel accel;
-
- String pos(double p, String pos, String neg) {
- String h = pos;
- if (p < 0) {
- h = neg;
- p = -p;
- }
- int deg = (int) Math.floor(p);
- double min = (p - Math.floor(p)) * 60.0;
- return String.format("%s %4d° %9.6f", h, deg, min);
- }
-
- class Apogee extends AscentStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.drogue_sense));
- lights.set(state.drogue_sense > 3.2);
- }
- public Apogee (GridBagLayout layout, int y) {
- super(layout, y, "Apogee Igniter Voltage");
- }
- }
-
- Apogee apogee;
-
- class Main extends AscentStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.main_sense));
- lights.set(state.main_sense > 3.2);
- }
- public Main (GridBagLayout layout, int y) {
- super(layout, y, "Main Igniter Voltage");
- }
- }
-
- Main main;
-
- class Lat extends AscentValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- value.setText(pos(state.gps.lat,"N", "S"));
- else
- value.setText("???");
- }
- public Lat (GridBagLayout layout, int y) {
- super (layout, y, "Latitude");
- }
- }
-
- Lat lat;
-
- class Lon extends AscentValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- value.setText(pos(state.gps.lon,"E", "W"));
- else
- value.setText("???");
- }
- public Lon (GridBagLayout layout, int y) {
- super (layout, y, "Longitude");
- }
- }
-
- Lon lon;
-
- public void reset() {
- lat.reset();
- lon.reset();
- main.reset();
- apogee.reset();
- height.reset();
- speed.reset();
- accel.reset();
- }
-
- public void show(AltosState state, int crc_errors) {
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
- height.show(state, crc_errors);
- main.show(state, crc_errors);
- apogee.show(state, crc_errors);
- speed.show(state, crc_errors);
- accel.show(state, crc_errors);
- }
-
- public void labels(GridBagLayout layout, int y) {
- GridBagConstraints c;
- JLabel cur, max;
-
- cur = new JLabel("Current");
- cur.setFont(Altos.label_font);
- c = new GridBagConstraints();
- c.gridx = 2; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- layout.setConstraints(cur, c);
- add(cur);
-
- max = new JLabel("Maximum");
- max.setFont(Altos.label_font);
- c.gridx = 3; c.gridy = y;
- layout.setConstraints(max, c);
- add(max);
- }
-
- public AltosAscent() {
- layout = new GridBagLayout();
-
- setLayout(layout);
-
- /* Elements in ascent display:
- *
- * lat
- * lon
- * height
- */
- labels(layout, 0);
- height = new Height(layout, 1);
- speed = new Speed(layout, 2);
- accel = new Accel(layout, 3);
- lat = new Lat(layout, 4);
- lon = new Lon(layout, 5);
- apogee = new Apogee(layout, 6);
- main = new Main(layout, 7);
- }
-}
+++ /dev/null
-/*
- * 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;
-
-public class AltosCRCException extends Exception {
- public int rssi;
-
- public AltosCRCException (int in_rssi) {
- rssi = in_rssi;
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.util.*;
-
-public class AltosCSV implements AltosWriter {
- File name;
- PrintStream out;
- boolean header_written;
- boolean seen_boost;
- int boost_tick;
- LinkedList<AltosRecord> pad_records;
- AltosState state;
-
- static final int ALTOS_CSV_VERSION = 2;
-
- /* Version 2 format:
- *
- * General info
- * version number
- * serial number
- * flight number
- * callsign
- * time (seconds since boost)
- * rssi
- * link quality
- *
- * Flight status
- * state
- * state name
- *
- * Basic sensors
- * acceleration (m/s²)
- * pressure (mBar)
- * altitude (m)
- * height (m)
- * accelerometer speed (m/s)
- * barometer speed (m/s)
- * temp (°C)
- * battery (V)
- * drogue (V)
- * main (V)
- *
- * GPS data
- * connected (1/0)
- * locked (1/0)
- * nsat (used for solution)
- * latitude (°)
- * longitude (°)
- * altitude (m)
- * year (e.g. 2010)
- * month (1-12)
- * day (1-31)
- * hour (0-23)
- * minute (0-59)
- * second (0-59)
- * from_pad_dist (m)
- * from_pad_azimuth (deg true)
- * from_pad_range (m)
- * from_pad_elevation (deg from horizon)
- * hdop
- *
- * GPS Sat data
- * C/N0 data for all 32 valid SDIDs
- */
-
- void write_general_header() {
- out.printf("version,serial,flight,call,time,rssi,lqi");
- }
-
- void write_general(AltosRecord record) {
- out.printf("%s, %d, %d, %s, %8.2f, %4d, %3d",
- ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign,
- (double) record.time,
- record.rssi,
- record.status & 0x7f);
- }
-
- void write_flight_header() {
- out.printf("state,state_name");
- }
-
- void write_flight(AltosRecord record) {
- out.printf("%d,%8s", record.state, record.state());
- }
-
- void write_basic_header() {
- out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,battery_voltage,drogue_voltage,main_voltage");
- }
-
- void write_basic(AltosRecord record) {
- out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
- record.acceleration(),
- record.raw_pressure(),
- record.raw_altitude(),
- record.raw_height(),
- record.accel_speed(),
- state.baro_speed,
- record.temperature(),
- record.battery_voltage(),
- record.drogue_voltage(),
- record.main_voltage());
- }
-
- void write_gps_header() {
- out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop");
- }
-
- void write_gps(AltosRecord record) {
- AltosGPS gps = record.gps;
- if (gps == null)
- gps = new AltosGPS();
-
- AltosGreatCircle from_pad = state.from_pad;
- if (from_pad == null)
- from_pad = new AltosGreatCircle();
-
- out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
- gps.connected?1:0,
- gps.locked?1:0,
- gps.nsat,
- gps.lat,
- gps.lon,
- gps.alt,
- gps.year,
- gps.month,
- gps.day,
- gps.hour,
- gps.minute,
- gps.second,
- from_pad.distance,
- state.range,
- from_pad.bearing,
- state.elevation,
- gps.hdop);
- }
-
- void write_gps_sat_header() {
- for(int i = 1; i <= 32; i++) {
- out.printf("sat%02d", i);
- if (i != 32)
- out.printf(",");
- }
- }
-
- void write_gps_sat(AltosRecord record) {
- AltosGPS gps = record.gps;
- for(int i = 1; i <= 32; i++) {
- int c_n0 = 0;
- if (gps != null && gps.cc_gps_sat != null) {
- for(int j = 0; j < gps.cc_gps_sat.length; j++)
- if (gps.cc_gps_sat[j].svid == i) {
- c_n0 = gps.cc_gps_sat[j].c_n0;
- break;
- }
- }
- out.printf ("%3d", c_n0);
- if (i != 32)
- out.printf(",");
- }
- }
-
- void write_header() {
- out.printf("#"); write_general_header();
- out.printf(","); write_flight_header();
- out.printf(","); write_basic_header();
- out.printf(","); write_gps_header();
- out.printf(","); write_gps_sat_header();
- out.printf ("\n");
- }
-
- void write_one(AltosRecord record) {
- state = new AltosState(record, state);
- write_general(record); out.printf(",");
- write_flight(record); out.printf(",");
- write_basic(record); out.printf(",");
- write_gps(record); out.printf(",");
- write_gps_sat(record);
- out.printf ("\n");
- }
-
- void flush_pad() {
- while (!pad_records.isEmpty()) {
- write_one (pad_records.remove());
- }
- }
-
- public void write(AltosRecord record) {
- if (!header_written) {
- write_header();
- header_written = true;
- }
- if (!seen_boost) {
- if (record.state >= Altos.ao_flight_boost) {
- seen_boost = true;
- boost_tick = record.tick;
- flush_pad();
- }
- }
- if (seen_boost)
- write_one(record);
- else
- pad_records.add(record);
- }
-
- public PrintStream out() {
- return out;
- }
-
- public void close() {
- if (!pad_records.isEmpty()) {
- boost_tick = pad_records.element().tick;
- flush_pad();
- }
- out.close();
- }
-
- public void write(AltosRecordIterable iterable) {
- iterable.write_comments(out());
- for (AltosRecord r : iterable)
- write(r);
- }
-
- public AltosCSV(File in_name) throws FileNotFoundException {
- name = in_name;
- out = new PrintStream(name);
- pad_records = new LinkedList<AltosRecord>();
- }
-
- public AltosCSV(String in_string) throws FileNotFoundException {
- this(new File(in_string));
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosCSVUI
- extends JDialog
- implements ActionListener
-{
- JFileChooser csv_chooser;
- JPanel accessory;
- JComboBox combo_box;
- AltosRecordIterable iterable;
- AltosWriter writer;
-
- static String[] combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
-
- void set_default_file() {
- File current = csv_chooser.getSelectedFile();
- String current_name = current.getName();
- String new_name = null;
- String selected = (String) combo_box.getSelectedItem();
-
- if (selected.contains("CSV"))
- new_name = Altos.replace_extension(current_name, ".csv");
- else if (selected.contains("KML"))
- new_name = Altos.replace_extension(current_name, ".kml");
- if (new_name != null)
- csv_chooser.setSelectedFile(new File(new_name));
- }
-
- public void actionPerformed(ActionEvent e) {
- if (e.getActionCommand().equals("comboBoxChanged"))
- set_default_file();
- }
-
- public AltosCSVUI(JFrame frame, AltosRecordIterable in_iterable, File source_file) {
- iterable = in_iterable;
- csv_chooser = new JFileChooser(source_file);
-
- accessory = new JPanel();
- accessory.setLayout(new GridBagLayout());
-
- GridBagConstraints c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.weightx = 1;
- c.weighty = 0;
- c.insets = new Insets (4, 4, 4, 4);
-
- JLabel accessory_label = new JLabel("Export File Type");
- c.gridx = 0;
- c.gridy = 0;
- accessory.add(accessory_label, c);
-
- combo_box = new JComboBox(combo_box_items);
- combo_box.addActionListener(this);
- c.gridx = 0;
- c.gridy = 1;
- accessory.add(combo_box, c);
-
- csv_chooser.setAccessory(accessory);
- csv_chooser.setSelectedFile(source_file);
- set_default_file();
- int ret = csv_chooser.showSaveDialog(frame);
- if (ret == JFileChooser.APPROVE_OPTION) {
- File file = csv_chooser.getSelectedFile();
- String type = (String) combo_box.getSelectedItem();
- try {
- if (type.contains("CSV"))
- writer = new AltosCSV(file);
- else
- writer = new AltosKML(file);
- writer.write(iterable);
- writer.close();
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(frame,
- file.getName(),
- "Cannot open file",
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosChannelMenu extends JComboBox implements ActionListener {
- int channel;
-
- public AltosChannelMenu(int current_channel) {
-
- channel = current_channel;
-
- for (int c = 0; c <= 9; c++)
- addItem(String.format("Channel %1d (%7.3fMHz)", c, 434.550 + c * 0.1));
- setSelectedIndex(channel);
- setMaximumRowCount(10);
- }
-
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.*;
-
-import libaltosJNI.*;
-
-public class AltosConfig implements Runnable, ActionListener {
-
- class int_ref {
- int value;
-
- public int get() {
- return value;
- }
- public void set(int i) {
- value = i;
- }
- public int_ref(int i) {
- value = i;
- }
- }
-
- class string_ref {
- String value;
-
- public String get() {
- return value;
- }
- public void set(String i) {
- value = i;
- }
- public string_ref(String i) {
- value = i;
- }
- }
-
- JFrame owner;
- AltosDevice device;
- AltosSerial serial_line;
- boolean remote;
- Thread config_thread;
- int_ref serial;
- int_ref main_deploy;
- int_ref apogee_delay;
- int_ref radio_channel;
- int_ref radio_calibration;
- string_ref version;
- string_ref product;
- string_ref callsign;
- AltosConfigUI config_ui;
- boolean serial_started;
-
- boolean get_int(String line, String label, int_ref x) {
- if (line.startsWith(label)) {
- try {
- String tail = line.substring(label.length()).trim();
- String[] tokens = tail.split("\\s+");
- if (tokens.length > 0) {
- int i = Integer.parseInt(tokens[0]);
- x.set(i);
- return true;
- }
- } catch (NumberFormatException ne) {
- }
- }
- return false;
- }
-
- boolean get_string(String line, String label, string_ref s) {
- if (line.startsWith(label)) {
- String quoted = line.substring(label.length()).trim();
-
- if (quoted.startsWith("\""))
- quoted = quoted.substring(1);
- if (quoted.endsWith("\""))
- quoted = quoted.substring(0,quoted.length()-1);
- s.set(quoted);
- return true;
- } else {
- return false;
- }
- }
-
- void start_serial() throws InterruptedException {
- serial_started = true;
- if (remote) {
- serial_line.set_radio();
- serial_line.printf("p\nE 0\n");
- serial_line.flush_input();
- }
- }
-
- void stop_serial() throws InterruptedException {
- if (!serial_started)
- return;
- serial_started = false;
- if (remote) {
- serial_line.printf("~");
- serial_line.flush_output();
- }
- }
-
- void get_data() throws InterruptedException, TimeoutException {
- try {
- start_serial();
- serial_line.printf("c s\nv\n");
- for (;;) {
- String line = serial_line.get_reply(5000);
- if (line == null)
- throw new TimeoutException();
- get_int(line, "serial-number", serial);
- get_int(line, "Main deploy:", main_deploy);
- get_int(line, "Apogee delay:", apogee_delay);
- get_int(line, "Radio channel:", radio_channel);
- get_int(line, "Radio cal:", radio_calibration);
- get_string(line, "Callsign:", callsign);
- get_string(line,"software-version", version);
- get_string(line,"product", product);
-
- /* signals the end of the version info */
- if (line.startsWith("software-version"))
- break;
- }
- } finally {
- stop_serial();
- }
- }
-
- void init_ui () throws InterruptedException, TimeoutException {
- config_ui = new AltosConfigUI(owner, remote);
- config_ui.addActionListener(this);
- set_ui();
- }
-
- void abort() {
- JOptionPane.showMessageDialog(owner,
- String.format("Connection to \"%s\" failed",
- device.toShortString()),
- "Connection Failed",
- JOptionPane.ERROR_MESSAGE);
- try {
- stop_serial();
- } catch (InterruptedException ie) {
- }
- serial_line.close();
- serial_line = null;
- }
-
- void set_ui() throws InterruptedException, TimeoutException {
- if (serial_line != null)
- get_data();
- config_ui.set_serial(serial.get());
- config_ui.set_product(product.get());
- config_ui.set_version(version.get());
- config_ui.set_main_deploy(main_deploy.get());
- config_ui.set_apogee_delay(apogee_delay.get());
- config_ui.set_radio_channel(radio_channel.get());
- config_ui.set_radio_calibration(radio_calibration.get());
- config_ui.set_callsign(callsign.get());
- config_ui.set_clean();
- }
-
- void run_dialog() {
- }
-
- void save_data() {
- main_deploy.set(config_ui.main_deploy());
- apogee_delay.set(config_ui.apogee_delay());
- radio_channel.set(config_ui.radio_channel());
- radio_calibration.set(config_ui.radio_calibration());
- callsign.set(config_ui.callsign());
- try {
- start_serial();
- serial_line.printf("c m %d\n", main_deploy.get());
- serial_line.printf("c d %d\n", apogee_delay.get());
- if (!remote) {
- serial_line.printf("c r %d\n", radio_channel.get());
- serial_line.printf("c f %d\n", radio_calibration.get());
- }
- serial_line.printf("c c %s\n", callsign.get());
- serial_line.printf("c w\n");
- } catch (InterruptedException ie) {
- } finally {
- try {
- stop_serial();
- } catch (InterruptedException ie) {
- }
- }
- }
-
- public void actionPerformed(ActionEvent e) {
- String cmd = e.getActionCommand();
- try {
- if (cmd.equals("Save")) {
- save_data();
- set_ui();
- } else if (cmd.equals("Reset")) {
- set_ui();
- } else if (cmd.equals("Reboot")) {
- if (serial_line != null) {
- start_serial();
- serial_line.printf("r eboot\n");
- serial_line.flush_output();
- stop_serial();
- serial_line.close();
- }
- } else if (cmd.equals("Close")) {
- if (serial_line != null)
- serial_line.close();
- }
- } catch (InterruptedException ie) {
- abort();
- } catch (TimeoutException te) {
- abort();
- }
- }
-
- public void run () {
- try {
- init_ui();
- config_ui.make_visible();
- } catch (InterruptedException ie) {
- abort();
- } catch (TimeoutException te) {
- abort();
- }
- }
-
- public AltosConfig(JFrame given_owner) {
- owner = given_owner;
-
- serial = new int_ref(0);
- main_deploy = new int_ref(250);
- apogee_delay = new int_ref(0);
- radio_channel = new int_ref(0);
- radio_calibration = new int_ref(1186611);
- callsign = new string_ref("N0CALL");
- version = new string_ref("unknown");
- product = new string_ref("unknown");
-
- device = AltosDeviceDialog.show(owner, AltosDevice.product_any);
- if (device != null) {
- try {
- serial_line = new AltosSerial(device);
- if (!device.matchProduct(AltosDevice.product_telemetrum))
- remote = true;
- config_thread = new Thread(this);
- config_thread.start();
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
- "Cannot open target device",
- JOptionPane.ERROR_MESSAGE);
- } catch (AltosSerialInUseException si) {
- JOptionPane.showMessageDialog(owner,
- String.format("Device \"%s\" already in use",
- device.toShortString()),
- "Device in use",
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(owner,
- device.toShortString(),
- ee.getLocalizedMessage(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import javax.swing.event.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import libaltosJNI.*;
-
-public class AltosConfigUI
- extends JDialog
- implements ActionListener, ItemListener, DocumentListener
-{
-
- Container pane;
- Box box;
- JLabel product_label;
- JLabel version_label;
- JLabel serial_label;
- JLabel main_deploy_label;
- JLabel apogee_delay_label;
- JLabel radio_channel_label;
- JLabel radio_calibration_label;
- JLabel callsign_label;
-
- public boolean dirty;
-
- JFrame owner;
- JLabel product_value;
- JLabel version_value;
- JLabel serial_value;
- JComboBox main_deploy_value;
- JComboBox apogee_delay_value;
- JComboBox radio_channel_value;
- JTextField radio_calibration_value;
- JTextField callsign_value;
-
- JButton save;
- JButton reset;
- JButton reboot;
- JButton close;
-
- ActionListener listener;
-
- static String[] main_deploy_values = {
- "100", "150", "200", "250", "300", "350",
- "400", "450", "500"
- };
-
- static String[] apogee_delay_values = {
- "0", "1", "2", "3", "4", "5"
- };
-
- static String[] radio_channel_values = new String[10];
- {
- for (int i = 0; i <= 9; i++)
- radio_channel_values[i] = String.format("Channel %1d (%7.3fMHz)",
- i, 434.550 + i * 0.1);
- }
-
- /* A window listener to catch closing events and tell the config code */
- class ConfigListener extends WindowAdapter {
- AltosConfigUI ui;
-
- public ConfigListener(AltosConfigUI this_ui) {
- ui = this_ui;
- }
-
- public void windowClosing(WindowEvent e) {
- ui.actionPerformed(new ActionEvent(e.getSource(),
- ActionEvent.ACTION_PERFORMED,
- "Close"));
- }
- }
-
- /* Build the UI using a grid bag */
- public AltosConfigUI(JFrame in_owner, boolean remote) {
- super (in_owner, "Configure TeleMetrum", false);
-
- owner = in_owner;
- GridBagConstraints c;
-
- Insets il = new Insets(4,4,4,4);
- Insets ir = new Insets(4,4,4,4);
-
- pane = getContentPane();
- pane.setLayout(new GridBagLayout());
-
- /* Product */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 0;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- product_label = new JLabel("Product:");
- pane.add(product_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 0;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- product_value = new JLabel("");
- pane.add(product_value, c);
-
- /* Version */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 1;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- version_label = new JLabel("Software version:");
- pane.add(version_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 1;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- version_value = new JLabel("");
- pane.add(version_value, c);
-
- /* Serial */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 2;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- serial_label = new JLabel("Serial:");
- pane.add(serial_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 2;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- serial_value = new JLabel("");
- pane.add(serial_value, c);
-
- /* Main deploy */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 3;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- main_deploy_label = new JLabel("Main Deploy Altitude(m):");
- pane.add(main_deploy_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 3;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- main_deploy_value = new JComboBox(main_deploy_values);
- main_deploy_value.setEditable(true);
- main_deploy_value.addItemListener(this);
- pane.add(main_deploy_value, c);
-
- /* Apogee delay */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 4;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- apogee_delay_label = new JLabel("Apogee Delay(s):");
- pane.add(apogee_delay_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 4;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- apogee_delay_value = new JComboBox(apogee_delay_values);
- apogee_delay_value.setEditable(true);
- apogee_delay_value.addItemListener(this);
- pane.add(apogee_delay_value, c);
-
- /* Radio channel */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 5;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- radio_channel_label = new JLabel("Radio Channel:");
- pane.add(radio_channel_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 5;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- radio_channel_value = new JComboBox(radio_channel_values);
- radio_channel_value.setEditable(false);
- radio_channel_value.addItemListener(this);
- if (remote)
- radio_channel_value.setEnabled(false);
- pane.add(radio_channel_value, c);
-
- /* Radio Calibration */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 6;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- radio_calibration_label = new JLabel("RF Calibration:");
- pane.add(radio_calibration_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 6;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- radio_calibration_value = new JTextField(String.format("%d", 1186611));
- radio_calibration_value.getDocument().addDocumentListener(this);
- if (remote)
- radio_calibration_value.setEnabled(false);
- pane.add(radio_calibration_value, c);
-
- /* Callsign */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 7;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- callsign_label = new JLabel("Callsign:");
- pane.add(callsign_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 7;
- c.gridwidth = 4;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- callsign_value = new JTextField(AltosPreferences.callsign());
- callsign_value.getDocument().addDocumentListener(this);
- pane.add(callsign_value, c);
-
- /* Buttons */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 8;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- save = new JButton("Save");
- pane.add(save, c);
- save.addActionListener(this);
- save.setActionCommand("Save");
-
- c = new GridBagConstraints();
- c.gridx = 2; c.gridy = 8;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.insets = il;
- reset = new JButton("Reset");
- pane.add(reset, c);
- reset.addActionListener(this);
- reset.setActionCommand("Reset");
-
- c = new GridBagConstraints();
- c.gridx = 4; c.gridy = 8;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.insets = il;
- reboot = new JButton("Reboot");
- pane.add(reboot, c);
- reboot.addActionListener(this);
- reboot.setActionCommand("Reboot");
-
- c = new GridBagConstraints();
- c.gridx = 6; c.gridy = 8;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_END;
- c.insets = il;
- close = new JButton("Close");
- pane.add(close, c);
- close.addActionListener(this);
- close.setActionCommand("Close");
-
- addWindowListener(new ConfigListener(this));
- }
-
- /* Once the initial values are set, the config code will show the dialog */
- public void make_visible() {
- pack();
- setLocationRelativeTo(owner);
- setVisible(true);
- }
-
- /* If any values have been changed, confirm before closing */
- public boolean check_dirty(String operation) {
- if (dirty) {
- Object[] options = { String.format("%s anyway", operation), "Keep editing" };
- int i;
- i = JOptionPane.showOptionDialog(this,
- String.format("Configuration modified. %s anyway?", operation),
- "Configuration Modified",
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.WARNING_MESSAGE,
- null, options, options[1]);
- if (i != 0)
- return false;
- }
- return true;
- }
-
- /* Listen for events from our buttons */
- public void actionPerformed(ActionEvent e) {
- String cmd = e.getActionCommand();
-
- if (cmd.equals("Close") || cmd.equals("Reboot"))
- if (!check_dirty(cmd))
- return;
- listener.actionPerformed(e);
- if (cmd.equals("Close") || cmd.equals("Reboot")) {
- setVisible(false);
- dispose();
- }
- dirty = false;
- }
-
- /* ItemListener interface method */
- public void itemStateChanged(ItemEvent e) {
- dirty = true;
- }
-
- /* DocumentListener interface methods */
- public void changedUpdate(DocumentEvent e) {
- dirty = true;
- }
-
- public void insertUpdate(DocumentEvent e) {
- dirty = true;
- }
-
- public void removeUpdate(DocumentEvent e) {
- dirty = true;
- }
-
- /* Let the config code hook on a listener */
- public void addActionListener(ActionListener l) {
- listener = l;
- }
-
- /* set and get all of the dialog values */
- public void set_product(String product) {
- product_value.setText(product);
- }
-
- public void set_version(String version) {
- version_value.setText(version);
- }
-
- public void set_serial(int serial) {
- serial_value.setText(String.format("%d", serial));
- }
-
- public void set_main_deploy(int new_main_deploy) {
- main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
- }
-
- public int main_deploy() {
- return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
- }
-
- public void set_apogee_delay(int new_apogee_delay) {
- apogee_delay_value.setSelectedItem(Integer.toString(new_apogee_delay));
- }
-
- public int apogee_delay() {
- return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
- }
-
- public void set_radio_channel(int new_radio_channel) {
- radio_channel_value.setSelectedIndex(new_radio_channel);
- }
-
- public int radio_channel() {
- return radio_channel_value.getSelectedIndex();
- }
-
- public void set_radio_calibration(int new_radio_calibration) {
- radio_calibration_value.setText(String.format("%d", new_radio_calibration));
- }
-
- public int radio_calibration() {
- return Integer.parseInt(radio_calibration_value.getText());
- }
-
- public void set_callsign(String new_callsign) {
- callsign_value.setText(new_callsign);
- }
-
- public String callsign() {
- return callsign_value.getText();
- }
-
- public void set_clean() {
- dirty = false;
- }
-
- }
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import javax.swing.event.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosConfigureUI
- extends JDialog
- implements DocumentListener
-{
- JFrame owner;
- AltosVoice voice;
- Container pane;
-
- JRadioButton enable_voice;
- JButton test_voice;
- JButton close;
-
- JButton configure_log;
- JTextField log_directory;
-
- JLabel callsign_label;
- JTextField callsign_value;
-
- /* DocumentListener interface methods */
- public void changedUpdate(DocumentEvent e) {
- AltosPreferences.set_callsign(callsign_value.getText());
- }
-
- public void insertUpdate(DocumentEvent e) {
- changedUpdate(e);
- }
-
- public void removeUpdate(DocumentEvent e) {
- changedUpdate(e);
- }
-
- public AltosConfigureUI(JFrame in_owner, AltosVoice in_voice) {
- super(in_owner, "Configure AltosUI", false);
-
- GridBagConstraints c;
-
- Insets insets = new Insets(4, 4, 4, 4);
-
- owner = in_owner;
- voice = in_voice;
- pane = getContentPane();
- pane.setLayout(new GridBagLayout());
-
- c = new GridBagConstraints();
- c.insets = insets;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.WEST;
-
- /* Nice label at the top */
- c.gridx = 0;
- c.gridy = 0;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- pane.add(new JLabel ("Configure AltOS UI"), c);
-
- /* Voice settings */
- c.gridx = 0;
- c.gridy = 1;
- c.gridwidth = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.WEST;
- pane.add(new JLabel("Voice"), c);
-
- enable_voice = new JRadioButton("Enable", AltosPreferences.voice());
- enable_voice.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JRadioButton item = (JRadioButton) e.getSource();
- boolean enabled = item.isSelected();
- AltosPreferences.set_voice(enabled);
- if (enabled)
- voice.speak_always("Enable voice.");
- else
- voice.speak_always("Disable voice.");
- }
- });
- c.gridx = 1;
- c.gridy = 1;
- c.gridwidth = 1;
- c.weightx = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.WEST;
- pane.add(enable_voice, c);
-
- c.gridx = 2;
- c.gridy = 1;
- c.gridwidth = 1;
- c.weightx = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.EAST;
- test_voice = new JButton("Test Voice");
- test_voice.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- voice.speak("That's one small step for man; one giant leap for mankind.");
- }
- });
- pane.add(test_voice, c);
-
- /* Log directory settings */
- c.gridx = 0;
- c.gridy = 2;
- c.gridwidth = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.WEST;
- pane.add(new JLabel("Log Directory"), c);
-
- configure_log = new JButton(AltosPreferences.logdir().getPath());
- configure_log.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- AltosPreferences.ConfigureLog();
- configure_log.setText(AltosPreferences.logdir().getPath());
- }
- });
- c.gridx = 1;
- c.gridy = 2;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.BOTH;
- c.anchor = GridBagConstraints.WEST;
- pane.add(configure_log, c);
-
- /* Callsign setting */
- c.gridx = 0;
- c.gridy = 3;
- c.gridwidth = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.WEST;
- pane.add(new JLabel("Callsign"), c);
-
- callsign_value = new JTextField(AltosPreferences.callsign());
- callsign_value.getDocument().addDocumentListener(this);
- c.gridx = 1;
- c.gridy = 3;
- c.gridwidth = 2;
- c.fill = GridBagConstraints.BOTH;
- c.anchor = GridBagConstraints.WEST;
- pane.add(callsign_value, c);
-
- /* And a close button at the bottom */
- close = new JButton("Close");
- close.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setVisible(false);
- }
- });
- c.gridx = 0;
- c.gridy = 4;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- pane.add(close, c);
-
- pack();
- setLocationRelativeTo(owner);
- setVisible(true);
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * Sensor data conversion functions
- */
-package altosui;
-
-public class AltosConvert {
- /*
- * Pressure Sensor Model, version 1.1
- *
- * written by Holly Grimes
- *
- * Uses the International Standard Atmosphere as described in
- * "A Quick Derivation relating altitude to air pressure" (version 1.03)
- * from the Portland State Aerospace Society, except that the atmosphere
- * is divided into layers with each layer having a different lapse rate.
- *
- * Lapse rate data for each layer was obtained from Wikipedia on Sept. 1, 2007
- * at site <http://en.wikipedia.org/wiki/International_Standard_Atmosphere
- *
- * Height measurements use the local tangent plane. The postive z-direction is up.
- *
- * All measurements are given in SI units (Kelvin, Pascal, meter, meters/second^2).
- * The lapse rate is given in Kelvin/meter, the gas constant for air is given
- * in Joules/(kilogram-Kelvin).
- */
-
- static final double GRAVITATIONAL_ACCELERATION = -9.80665;
- static final double AIR_GAS_CONSTANT = 287.053;
- static final double NUMBER_OF_LAYERS = 7;
- static final double MAXIMUM_ALTITUDE = 84852.0;
- static final double MINIMUM_PRESSURE = 0.3734;
- static final double LAYER0_BASE_TEMPERATURE = 288.15;
- static final double LAYER0_BASE_PRESSURE = 101325;
-
- /* lapse rate and base altitude for each layer in the atmosphere */
- static final double[] lapse_rate = {
- -0.0065, 0.0, 0.001, 0.0028, 0.0, -0.0028, -0.002
- };
-
- static final int[] base_altitude = {
- 0, 11000, 20000, 32000, 47000, 51000, 71000
- };
-
- /* outputs atmospheric pressure associated with the given altitude.
- * altitudes are measured with respect to the mean sea level
- */
- static double
- altitude_to_pressure(double altitude)
- {
- double base_temperature = LAYER0_BASE_TEMPERATURE;
- double base_pressure = LAYER0_BASE_PRESSURE;
-
- double pressure;
- double base; /* base for function to determine pressure */
- double exponent; /* exponent for function to determine pressure */
- int layer_number; /* identifies layer in the atmosphere */
- double delta_z; /* difference between two altitudes */
-
- if (altitude > MAXIMUM_ALTITUDE) /* FIX ME: use sensor data to improve model */
- return 0;
-
- /* calculate the base temperature and pressure for the atmospheric layer
- associated with the inputted altitude */
- for(layer_number = 0; layer_number < NUMBER_OF_LAYERS - 1 && altitude > base_altitude[layer_number + 1]; layer_number++) {
- delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- base_pressure *= Math.exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- base_pressure *= Math.pow(base, exponent);
- }
- base_temperature += delta_z * lapse_rate[layer_number];
- }
-
- /* calculate the pressure at the inputted altitude */
- delta_z = altitude - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- pressure = base_pressure * Math.exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- pressure = base_pressure * Math.pow(base, exponent);
- }
-
- return pressure;
- }
-
-
-/* outputs the altitude associated with the given pressure. the altitude
- returned is measured with respect to the mean sea level */
- static double
- pressure_to_altitude(double pressure)
- {
-
- double next_base_temperature = LAYER0_BASE_TEMPERATURE;
- double next_base_pressure = LAYER0_BASE_PRESSURE;
-
- double altitude;
- double base_pressure;
- double base_temperature;
- double base; /* base for function to determine base pressure of next layer */
- double exponent; /* exponent for function to determine base pressure
- of next layer */
- double coefficient;
- int layer_number; /* identifies layer in the atmosphere */
- int delta_z; /* difference between two altitudes */
-
- if (pressure < 0) /* illegal pressure */
- return -1;
- if (pressure < MINIMUM_PRESSURE) /* FIX ME: use sensor data to improve model */
- return MAXIMUM_ALTITUDE;
-
- /* calculate the base temperature and pressure for the atmospheric layer
- associated with the inputted pressure. */
- layer_number = -1;
- do {
- layer_number++;
- base_pressure = next_base_pressure;
- base_temperature = next_base_temperature;
- delta_z = base_altitude[layer_number + 1] - base_altitude[layer_number];
- if (lapse_rate[layer_number] == 0.0) {
- exponent = GRAVITATIONAL_ACCELERATION * delta_z
- / AIR_GAS_CONSTANT / base_temperature;
- next_base_pressure *= Math.exp(exponent);
- }
- else {
- base = (lapse_rate[layer_number] * delta_z / base_temperature) + 1.0;
- exponent = GRAVITATIONAL_ACCELERATION /
- (AIR_GAS_CONSTANT * lapse_rate[layer_number]);
- next_base_pressure *= Math.pow(base, exponent);
- }
- next_base_temperature += delta_z * lapse_rate[layer_number];
- }
- while(layer_number < NUMBER_OF_LAYERS - 1 && pressure < next_base_pressure);
-
- /* calculate the altitude associated with the inputted pressure */
- if (lapse_rate[layer_number] == 0.0) {
- coefficient = (AIR_GAS_CONSTANT / GRAVITATIONAL_ACCELERATION)
- * base_temperature;
- altitude = base_altitude[layer_number]
- + coefficient * Math.log(pressure / base_pressure);
- }
- else {
- base = pressure / base_pressure;
- exponent = AIR_GAS_CONSTANT * lapse_rate[layer_number]
- / GRAVITATIONAL_ACCELERATION;
- coefficient = base_temperature / lapse_rate[layer_number];
- altitude = base_altitude[layer_number]
- + coefficient * (Math.pow(base, exponent) - 1);
- }
-
- return altitude;
- }
-
- static double
- cc_battery_to_voltage(double battery)
- {
- return battery / 32767.0 * 5.0;
- }
-
- static double
- cc_ignitor_to_voltage(double ignite)
- {
- return ignite / 32767 * 15.0;
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-
-public class AltosDataChooser extends JFileChooser {
- JFrame frame;
- String filename;
- File file;
-
- public String filename() {
- return filename;
- }
-
- public File file() {
- return file;
- }
-
- public AltosRecordIterable runDialog() {
- int ret;
-
- ret = showOpenDialog(frame);
- if (ret == APPROVE_OPTION) {
- file = getSelectedFile();
- if (file == null)
- return null;
- filename = file.getName();
- try {
- if (filename.endsWith("eeprom")) {
- FileInputStream in = new FileInputStream(file);
- return new AltosEepromIterable(in);
- } else if (filename.endsWith("telem")) {
- FileInputStream in = new FileInputStream(file);
- return new AltosTelemetryIterable(in);
- } else {
- throw new FileNotFoundException();
- }
- } catch (FileNotFoundException fe) {
- JOptionPane.showMessageDialog(frame,
- filename,
- "Cannot open file",
- JOptionPane.ERROR_MESSAGE);
- }
- }
- return null;
- }
-
- public AltosDataChooser(JFrame in_frame) {
- frame = in_frame;
- setDialogTitle("Select Flight Record File");
- setFileFilter(new FileNameExtensionFilter("Flight data file",
- "telem", "eeprom"));
- setCurrentDirectory(AltosPreferences.logdir());
- }
-}
+++ /dev/null
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
-
-package altosui;
-
-interface AltosDataPoint {
- int version();
- int serial();
- int flight();
- String callsign();
- double time();
- double rssi();
-
- int state();
- String state_name();
-
- double acceleration();
- double pressure();
- double altitude();
- double height();
- double accel_speed();
- double baro_speed();
- double temperature();
- double battery_voltage();
- double drogue_voltage();
- double main_voltage();
-}
-
+++ /dev/null
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
-
-package altosui;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.lang.UnsupportedOperationException;
-import java.util.NoSuchElementException;
-import java.util.Iterator;
-
-class AltosDataPointReader implements Iterable<AltosDataPoint> {
- Iterator<AltosRecord> iter;
- AltosState state;
- AltosRecord record;
-
- public AltosDataPointReader(Iterable<AltosRecord> reader) {
- this.iter = reader.iterator();
- this.state = null;
- }
-
- private void read_next_record()
- throws NoSuchElementException
- {
- record = iter.next();
- state = new AltosState(record, state);
- }
-
- private AltosDataPoint current_dp() {
- assert this.record != null;
-
- return new AltosDataPoint() {
- public int version() { return record.version; }
- public int serial() { return record.serial; }
- public int flight() { return record.flight; }
- public String callsign() { return record.callsign; }
- public double time() { return record.time; }
- public double rssi() { return record.rssi; }
-
- public int state() { return record.state; }
- public String state_name() { return record.state(); }
-
- public double acceleration() { return record.acceleration(); }
- public double pressure() { return record.raw_pressure(); }
- public double altitude() { return record.raw_altitude(); }
- public double height() { return record.raw_height(); }
- public double accel_speed() { return record.accel_speed(); }
- public double baro_speed() { return state.baro_speed; }
- public double temperature() { return record.temperature(); }
- public double battery_voltage() { return record.battery_voltage(); }
- public double drogue_voltage() { return record.drogue_voltage(); }
- public double main_voltage() { return record.main_voltage(); }
- };
- }
-
- public Iterator<AltosDataPoint> iterator() {
- return new Iterator<AltosDataPoint>() {
- public void remove() {
- throw new UnsupportedOperationException();
- }
- public boolean hasNext() {
- return iter.hasNext();
- }
- public AltosDataPoint next() {
- read_next_record();
- return current_dp();
- }
- };
- }
-}
-
+++ /dev/null
-/*
- * 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.concurrent.*;
-import java.util.*;
-
-import libaltosJNI.*;
-
-public class AltosDebug extends AltosSerial {
-
- public static final byte WR_CONFIG = 0x1d;
- public static final byte RD_CONFIG = 0x24;
- public static final byte CONFIG_TIMERS_OFF = (1 << 3);
- public static final byte CONFIG_DMA_PAUSE = (1 << 2);
- public static final byte CONFIG_TIMER_SUSPEND = (1 << 1);
- public static final byte SET_FLASH_INFO_PAGE = (1 << 0);
-
- public static final byte GET_PC = 0x28;
- public static final byte READ_STATUS = 0x34;
- public static final byte STATUS_CHIP_ERASE_DONE = (byte) (1 << 7);
- public static final byte STATUS_PCON_IDLE = (1 << 6);
- public static final byte STATUS_CPU_HALTED = (1 << 5);
- public static final byte STATUS_POWER_MODE_0 = (1 << 4);
- public static final byte STATUS_HALT_STATUS = (1 << 3);
- public static final byte STATUS_DEBUG_LOCKED = (1 << 2);
- public static final byte STATUS_OSCILLATOR_STABLE = (1 << 1);
- public static final byte STATUS_STACK_OVERFLOW = (1 << 0);
-
- public static final byte SET_HW_BRKPNT = 0x3b;
- public static byte HW_BRKPNT_N(byte n) { return (byte) ((n) << 3); }
- public static final byte HW_BRKPNT_N_MASK = (0x3 << 3);
- public static final byte HW_BRKPNT_ENABLE = (1 << 2);
-
- public static final byte HALT = 0x44;
- public static final byte RESUME = 0x4c;
- public static byte DEBUG_INSTR(byte n) { return (byte) (0x54|(n)); }
- public static final byte STEP_INSTR = 0x5c;
- public static byte STEP_REPLACE(byte n) { return (byte) (0x64|(n)); }
- public static final byte GET_CHIP_ID = 0x68;
-
-
- boolean debug_mode;
-
- void ensure_debug_mode() {
- if (!debug_mode) {
- printf("D\n");
- flush_input();
- debug_mode = true;
- }
- }
-
- void dump_memory(String header, int address, byte[] bytes, int start, int len) {
- System.out.printf("%s\n", header);
- for (int j = 0; j < len; j++) {
- if ((j & 15) == 0) {
- if (j != 0)
- System.out.printf("\n");
- System.out.printf ("%04x:", address + j);
- }
- System.out.printf(" %02x", bytes[start + j]);
- }
- System.out.printf("\n");
- }
-
- /*
- * Write target memory
- */
- public void write_memory(int address, byte[] bytes, int start, int len) {
- ensure_debug_mode();
-// dump_memory("write_memory", address, bytes, start, len);
- printf("O %x %x\n", len, address);
- for (int i = 0; i < len; i++)
- printf("%02x", bytes[start + i]);
- }
-
- public void write_memory(int address, byte[] bytes) {
- write_memory(address, bytes, 0, bytes.length);
- }
-
- /*
- * Read target memory
- */
- public byte[] read_memory(int address, int length)
- throws IOException, InterruptedException {
- byte[] data = new byte[length];
-
- flush_input();
- ensure_debug_mode();
- printf("I %x %x\n", length, address);
- int i = 0;
- int start = 0;
- while (i < length) {
- String line = get_reply().trim();
- if (!Altos.ishex(line) || line.length() % 2 != 0)
- throw new IOException(
- String.format
- ("Invalid reply \"%s\"", line));
- int this_time = line.length() / 2;
- for (int j = 0; j < this_time; j++)
- data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) +
- Altos.fromhex(line.charAt(j*2+1)));
- start += this_time;
- i += this_time;
- }
-// dump_memory("read_memory", address, data, 0, length);
-
- return data;
- }
-
- /*
- * Write raw bytes to the debug link using the 'P' command
- */
- public void write_bytes(byte[] bytes) throws IOException {
- int i = 0;
- ensure_debug_mode();
- while (i < bytes.length) {
- int this_time = bytes.length - i;
- if (this_time > 8)
- this_time = 0;
- printf("P");
- for (int j = 0; j < this_time; j++)
- printf(" %02x", bytes[i+j]);
- printf("\n");
- i += this_time;
- }
- }
-
- public void write_byte(byte b) throws IOException {
- byte[] bytes = { b };
- write_bytes(bytes);
- }
-
- /*
- * Read raw bytes from the debug link using the 'G' command
- */
- public byte[] read_bytes(int length)
- throws IOException, InterruptedException {
-
- flush_input();
- ensure_debug_mode();
- printf("G %x\n", length);
- int i = 0;
- byte[] data = new byte[length];
- while (i < length) {
- String line = get_reply().trim();
- String tokens[] = line.split("\\s+");
- for (int j = 0; j < tokens.length; j++) {
- if (!Altos.ishex(tokens[j]) ||
- tokens[j].length() != 2)
- throw new IOException(
- String.format
- ("Invalid read_bytes reply \"%s\"", line));
- try {
- data[i + j] = (byte) Integer.parseInt(tokens[j], 16);
- } catch (NumberFormatException ne) {
- throw new IOException(
- String.format
- ("Invalid read_bytes reply \"%s\"", line));
- }
- }
- i += tokens.length;
- }
- return data;
- }
-
- public byte read_byte() throws IOException, InterruptedException {
- return read_bytes(1)[0];
- }
-
- public byte debug_instr(byte[] instruction) throws IOException, InterruptedException {
- byte[] command = new byte[1 + instruction.length];
- command[0] = DEBUG_INSTR((byte) instruction.length);
- for (int i = 0; i < instruction.length; i++)
- command[i+1] = instruction[i];
- write_bytes(command);
- return read_byte();
- }
-
- public byte resume() throws IOException, InterruptedException {
- write_byte(RESUME);
- return read_byte();
- }
-
- public int read_uint16() throws IOException, InterruptedException {
- byte[] d = read_bytes(2);
- return ((int) (d[0] & 0xff) << 8) | (d[1] & 0xff);
- }
-
- public int read_uint8() throws IOException, InterruptedException {
- byte[] d = read_bytes(1);
- return (int) (d[0] & 0xff);
- }
-
- public int get_chip_id() throws IOException, InterruptedException {
- write_byte(GET_CHIP_ID);
- return read_uint16();
- }
-
- public int get_pc() throws IOException, InterruptedException {
- write_byte(GET_PC);
- return read_uint16();
- }
-
- public byte read_status() throws IOException, InterruptedException {
- write_byte(READ_STATUS);
- return read_byte();
- }
-
- static final byte LJMP = 0x02;
-
- public void set_pc(int pc) throws IOException, InterruptedException {
- byte high = (byte) (pc >> 8);
- byte low = (byte) pc;
- byte[] jump_mem = { LJMP, high, low };
- debug_instr(jump_mem);
- }
-
- public boolean check_connection() throws IOException, InterruptedException {
- byte reply = read_status();
- if ((reply & STATUS_CHIP_ERASE_DONE) == 0)
- return false;
- if ((reply & STATUS_PCON_IDLE) != 0)
- return false;
- if ((reply & STATUS_POWER_MODE_0) == 0)
- return false;
- return true;
- }
-
- public AltosRomconfig romconfig() {
- try {
- byte[] bytes = read_memory(0xa0, 10);
- return new AltosRomconfig(bytes, 0);
- } catch (IOException ie) {
- } catch (InterruptedException ie) {
- }
- return new AltosRomconfig();
- }
-
- /*
- * Reset target
- */
- public void reset() {
- printf ("R\n");
- }
-
- public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
- super(in_device);
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosDescent extends JComponent implements AltosFlightDisplay {
- GridBagLayout layout;
-
- public abstract class DescentStatus {
- JLabel label;
- JTextField value;
- AltosLights lights;
-
- abstract void show(AltosState state, int crc_errors);
- void reset() {
- value.setText("");
- lights.set(false);
- }
-
- public DescentStatus (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- lights = new AltosLights();
- c.gridx = 0; c.gridy = y;
- c.anchor = GridBagConstraints.CENTER;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(lights, c);
- add(lights);
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.gridwidth = 3;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 4; c.gridy = y;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
-
- }
- }
-
- public abstract class DescentValue {
- JLabel label;
- JTextField value;
-
- void reset() {
- value.setText("");
- }
-
- abstract void show(AltosState state, int crc_errors);
-
- void show(String format, double v) {
- value.setText(String.format(format, v));
- }
-
- void show(String v) {
- value.setText(v);
- }
-
- public DescentValue (GridBagLayout layout, int x, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = x + 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- add(label, c);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = x + 2; c.gridy = y;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- add(value, c);
- }
- }
-
- public abstract class DescentDualValue {
- JLabel label;
- JTextField value1;
- JTextField value2;
-
- void reset() {
- value1.setText("");
- value2.setText("");
- }
-
- abstract void show(AltosState state, int crc_errors);
- void show(String v1, String v2) {
- value1.setText(v1);
- value2.setText(v2);
- }
- void show(String f1, double v1, String f2, double v2) {
- value1.setText(String.format(f1, v1));
- value2.setText(String.format(f2, v2));
- }
-
- public DescentDualValue (GridBagLayout layout, int x, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = x + 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value1 = new JTextField(Altos.text_width);
- value1.setFont(Altos.value_font);
- value1.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = x + 2; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value1, c);
- add(value1);
-
- value2 = new JTextField(Altos.text_width);
- value2.setFont(Altos.value_font);
- value2.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = x + 4; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- c.gridwidth = 1;
- layout.setConstraints(value2, c);
- add(value2);
- }
- }
-
- class Height extends DescentValue {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m", state.height);
- }
- public Height (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Height");
- }
- }
-
- Height height;
-
- class Speed extends DescentValue {
- void show (AltosState state, int crc_errors) {
- double speed = state.speed;
- if (!state.ascent)
- speed = state.baro_speed;
- show("%6.0f m/s", speed);
- }
- public Speed (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Speed");
- }
- }
-
- Speed speed;
-
- String pos(double p, String pos, String neg) {
- String h = pos;
- if (p < 0) {
- h = neg;
- p = -p;
- }
- int deg = (int) Math.floor(p);
- double min = (p - Math.floor(p)) * 60.0;
- return String.format("%s %d° %9.6f", h, deg, min);
- }
-
- class Lat extends DescentValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- show(pos(state.gps.lat,"N", "S"));
- else
- show("???");
- }
- public Lat (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Latitude");
- }
- }
-
- Lat lat;
-
- class Lon extends DescentValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- show(pos(state.gps.lon,"W", "E"));
- else
- show("???");
- }
- public Lon (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Longitude");
- }
- }
-
- Lon lon;
-
- class Apogee extends DescentStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.drogue_sense));
- lights.set(state.drogue_sense > 3.2);
- }
- public Apogee (GridBagLayout layout, int y) {
- super(layout, y, "Apogee Igniter Voltage");
- }
- }
-
- Apogee apogee;
-
- class Main extends DescentStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.main_sense));
- lights.set(state.main_sense > 3.2);
- }
- public Main (GridBagLayout layout, int y) {
- super(layout, y, "Main Igniter Voltage");
- }
- }
-
- Main main;
-
- class Bearing extends DescentDualValue {
- void show (AltosState state, int crc_errors) {
- if (state.from_pad != null) {
- show( String.format("%3.0f°", state.from_pad.bearing),
- state.from_pad.bearing_words(
- AltosGreatCircle.BEARING_LONG));
- } else {
- show("???", "???");
- }
- }
- public Bearing (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Bearing");
- }
- }
-
- Bearing bearing;
-
- class Range extends DescentValue {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m", state.range);
- }
- public Range (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Range");
- }
- }
-
- Range range;
-
- class Elevation extends DescentValue {
- void show (AltosState state, int crc_errors) {
- show("%3.0f°", state.elevation);
- }
- public Elevation (GridBagLayout layout, int x, int y) {
- super (layout, x, y, "Elevation");
- }
- }
-
- Elevation elevation;
-
- public void reset() {
- lat.reset();
- lon.reset();
- height.reset();
- speed.reset();
- bearing.reset();
- range.reset();
- elevation.reset();
- main.reset();
- apogee.reset();
- }
-
- public void show(AltosState state, int crc_errors) {
- height.show(state, crc_errors);
- speed.show(state, crc_errors);
- bearing.show(state, crc_errors);
- range.show(state, crc_errors);
- elevation.show(state, crc_errors);
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
- main.show(state, crc_errors);
- apogee.show(state, crc_errors);
- }
-
- public AltosDescent() {
- layout = new GridBagLayout();
-
- setLayout(layout);
-
- /* Elements in descent display */
- speed = new Speed(layout, 0, 0);
- height = new Height(layout, 2, 0);
- elevation = new Elevation(layout, 0, 1);
- range = new Range(layout, 2, 1);
- bearing = new Bearing(layout, 0, 2);
- lat = new Lat(layout, 0, 3);
- lon = new Lon(layout, 2, 3);
-
- apogee = new Apogee(layout, 4);
- main = new Main(layout, 5);
- }
-}
+++ /dev/null
-/*
- * 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.util.*;
-import libaltosJNI.*;
-
-public class AltosDevice extends altos_device {
-
- static public boolean initialized = false;
- static public boolean loaded_library = false;
-
- public static boolean load_library() {
- if (!initialized) {
- try {
- System.loadLibrary("altos");
- libaltos.altos_init();
- loaded_library = true;
- } catch (UnsatisfiedLinkError e) {
- loaded_library = false;
- }
- initialized = true;
- }
- return loaded_library;
- }
-
- static int usb_vendor_altusmetrum() {
- if (load_library())
- return libaltosConstants.USB_VENDOR_ALTUSMETRUM;
- return 0x000a;
- }
-
- static int usb_product_altusmetrum() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_ALTUSMETRUM;
- return 0x000a;
- }
-
- static int usb_product_altusmetrum_min() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MIN;
- return 0x000a;
- }
-
- static int usb_product_altusmetrum_max() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_ALTUSMETRUM_MAX;
- return 0x000d;
- }
-
- static int usb_product_telemetrum() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_TELEMETRUM;
- return 0x000b;
- }
-
- static int usb_product_teledongle() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_TELEDONGLE;
- return 0x000c;
- }
-
- static int usb_product_teleterra() {
- if (load_library())
- return libaltosConstants.USB_PRODUCT_TELETERRA;
- return 0x000d;
- }
-
- public final static int vendor_altusmetrum = usb_vendor_altusmetrum();
- public final static int product_altusmetrum = usb_product_altusmetrum();
- public final static int product_telemetrum = usb_product_telemetrum();
- public final static int product_teledongle = usb_product_teledongle();
- public final static int product_teleterra = usb_product_teleterra();
- public final static int product_altusmetrum_min = usb_product_altusmetrum_min();
- public final static int product_altusmetrum_max = usb_product_altusmetrum_max();
-
-
- public final static int product_any = 0x10000;
- public final static int product_basestation = 0x10000 + 1;
-
- public String toString() {
- String name = getName();
- if (name == null)
- name = "Altus Metrum";
- return String.format("%-20.20s %4d %s",
- getName(), getSerial(), getPath());
- }
-
- public String toShortString() {
- String name = getName();
- if (name == null)
- name = "Altus Metrum";
- return String.format("%s %d %s",
- name, getSerial(), getPath());
-
- }
-
- public boolean isAltusMetrum() {
- if (getVendor() != vendor_altusmetrum)
- return false;
- if (getProduct() < product_altusmetrum_min)
- return false;
- if (getProduct() > product_altusmetrum_max)
- return false;
- return true;
- }
-
- public boolean matchProduct(int want_product) {
-
- if (!isAltusMetrum())
- return false;
-
- if (want_product == product_any)
- return true;
-
- if (want_product == product_basestation)
- return matchProduct(product_teledongle) || matchProduct(product_teleterra);
-
- int have_product = getProduct();
-
- if (have_product == product_altusmetrum) /* old devices match any request */
- return true;
-
- if (want_product == have_product)
- return true;
-
- return false;
- }
-
- static AltosDevice[] list(int product) {
- if (!load_library())
- return null;
-
- 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;
- if (device.matchProduct(product))
- 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
+++ /dev/null
-/*
- * 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.util.*;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.*;
-import libaltosJNI.libaltos;
-import libaltosJNI.altos_device;
-import libaltosJNI.SWIGTYPE_p_altos_file;
-import libaltosJNI.SWIGTYPE_p_altos_list;
-
-public class AltosDeviceDialog extends JDialog implements ActionListener {
-
- private static AltosDeviceDialog dialog;
- private static AltosDevice value = null;
- private JList list;
-
- public static AltosDevice show (Component frameComp, int product) {
-
- Frame frame = JOptionPane.getFrameForComponent(frameComp);
- AltosDevice[] devices;
- devices = AltosDevice.list(product);
-
- if (devices != null && devices.length > 0) {
- value = null;
- dialog = new AltosDeviceDialog(frame, frameComp,
- devices,
- devices[0]);
-
- dialog.setVisible(true);
- return value;
- } else {
- /* check for missing altos JNI library, which
- * will put up its own error dialog
- */
- if (AltosUI.load_library(frame)) {
- JOptionPane.showMessageDialog(frame,
- "No AltOS devices available",
- "No AltOS devices",
- JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
- }
-
- private AltosDeviceDialog (Frame frame, Component location,
- AltosDevice[] devices,
- AltosDevice initial) {
- super(frame, "Device Selection", true);
-
- value = null;
-
- JButton cancelButton = new JButton("Cancel");
- cancelButton.addActionListener(this);
-
- final JButton selectButton = new JButton("Select");
- selectButton.setActionCommand("select");
- selectButton.addActionListener(this);
- getRootPane().setDefaultButton(selectButton);
-
- list = new JList(devices) {
- //Subclass JList to workaround bug 4832765, which can cause the
- //scroll pane to not let the user easily scroll up to the beginning
- //of the list. An alternative would be to set the unitIncrement
- //of the JScrollBar to a fixed value. You wouldn't get the nice
- //aligned scrolling, but it should work.
- public int getScrollableUnitIncrement(Rectangle visibleRect,
- int orientation,
- int direction) {
- int row;
- if (orientation == SwingConstants.VERTICAL &&
- direction < 0 && (row = getFirstVisibleIndex()) != -1) {
- Rectangle r = getCellBounds(row, row);
- if ((r.y == visibleRect.y) && (row != 0)) {
- Point loc = r.getLocation();
- loc.y--;
- int prevIndex = locationToIndex(loc);
- Rectangle prevR = getCellBounds(prevIndex, prevIndex);
-
- if (prevR == null || prevR.y >= r.y) {
- return 0;
- }
- return prevR.height;
- }
- }
- return super.getScrollableUnitIncrement(
- visibleRect, orientation, direction);
- }
- };
-
- list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
- list.setVisibleRowCount(-1);
- list.addMouseListener(new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- if (e.getClickCount() == 2) {
- selectButton.doClick(); //emulate button click
- }
- }
- });
- JScrollPane listScroller = new JScrollPane(list);
- listScroller.setPreferredSize(new Dimension(400, 80));
- listScroller.setAlignmentX(LEFT_ALIGNMENT);
-
- //Create a container so that we can add a title around
- //the scroll pane. Can't add a title directly to the
- //scroll pane because its background would be white.
- //Lay out the label and scroll pane from top to bottom.
- JPanel listPane = new JPanel();
- listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
-
- JLabel label = new JLabel("Select Device");
- label.setLabelFor(list);
- listPane.add(label);
- listPane.add(Box.createRigidArea(new Dimension(0,5)));
- listPane.add(listScroller);
- listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
-
- //Lay out the buttons from left to right.
- JPanel buttonPane = new JPanel();
- buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
- buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
- buttonPane.add(Box.createHorizontalGlue());
- buttonPane.add(cancelButton);
- buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
- buttonPane.add(selectButton);
-
- //Put everything together, using the content pane's BorderLayout.
- Container contentPane = getContentPane();
- contentPane.add(listPane, BorderLayout.CENTER);
- contentPane.add(buttonPane, BorderLayout.PAGE_END);
-
- //Initialize values.
- list.setSelectedValue(initial, true);
- pack();
- setLocationRelativeTo(location);
- }
-
- //Handle clicks on the Set and Cancel buttons.
- public void actionPerformed(ActionEvent e) {
- if ("select".equals(e.getActionCommand()))
- AltosDeviceDialog.value = (AltosDevice)(list.getSelectedValue());
- AltosDeviceDialog.dialog.setVisible(false);
- }
-
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosDisplayThread extends Thread {
-
- Frame parent;
- IdleThread idle_thread;
- AltosVoice voice;
- String name;
- AltosFlightReader reader;
- int crc_errors;
- AltosFlightDisplay display;
-
- synchronized void show(AltosState state, int crc_errors) {
- if (state != null)
- display.show(state, crc_errors);
- }
-
- class IdleThread extends Thread {
-
- boolean started;
- private AltosState state;
- int reported_landing;
- int report_interval;
- long report_time;
-
- public synchronized void report(boolean last) {
- if (state == null)
- return;
-
- /* reset the landing count once we hear about a new flight */
- if (state.state < Altos.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 (Altos.ao_flight_drogue <= state.state &&
- state.state < Altos.ao_flight_landed &&
- state.range >= 0)
- {
- voice.speak("Height %d, bearing %s %d, elevation %d, range %d.\n",
- (int) (state.height + 0.5),
- state.from_pad.bearing_words(
- AltosGreatCircle.BEARING_VOICE),
- (int) (state.from_pad.bearing + 0.5),
- (int) (state.elevation + 0.5),
- (int) (state.range + 0.5));
- } else if (state.state > Altos.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.state >= Altos.ao_flight_drogue &&
- (last ||
- System.currentTimeMillis() - state.report_time >= 15000 ||
- state.state == Altos.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.from_pad != 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;
- if (state.state != Altos.ao_flight_landed) {
- state.state = Altos.ao_flight_landed;
- show(state, 0);
- }
- }
- }
-
- long now () {
- return System.currentTimeMillis();
- }
-
- void set_report_time() {
- report_time = now() + report_interval;
- }
-
- public void run () {
- try {
- for (;;) {
- set_report_time();
- for (;;) {
- voice.drain();
- synchronized (this) {
- long sleep_time = report_time - now();
- if (sleep_time <= 0)
- break;
- wait(sleep_time);
- }
- }
- report(false);
- }
- } catch (InterruptedException ie) {
- try {
- voice.drain();
- } catch (InterruptedException iie) { }
- }
- }
-
- public synchronized void notice(AltosState new_state, boolean spoken) {
- AltosState old_state = state;
- state = new_state;
- if (!started && state.state > Altos.ao_flight_pad) {
- started = true;
- start();
- }
-
- if (state.state < Altos.ao_flight_drogue)
- report_interval = 10000;
- else
- report_interval = 20000;
- if (old_state != null && old_state.state != state.state) {
- report_time = now();
- this.notify();
- } else if (spoken)
- set_report_time();
- }
-
- public IdleThread() {
- state = null;
- reported_landing = 0;
- report_interval = 10000;
- }
- }
-
- boolean tell(AltosState state, AltosState old_state) {
- boolean ret = false;
- if (old_state == null || old_state.state != state.state) {
- voice.speak(state.data.state());
- if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&
- state.state > Altos.ao_flight_boost) {
- voice.speak("max speed: %d meters per second.",
- (int) (state.max_speed + 0.5));
- ret = true;
- } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&
- state.state >= Altos.ao_flight_drogue) {
- voice.speak("max height: %d meters.",
- (int) (state.max_height + 0.5));
- ret = true;
- }
- }
- if (old_state == null || old_state.gps_ready != state.gps_ready) {
- if (state.gps_ready) {
- voice.speak("GPS ready");
- ret = true;
- }
- else if (old_state != null) {
- voice.speak("GPS lost");
- ret = true;
- }
- }
- old_state = state;
- return ret;
- }
-
- public void run() {
- boolean interrupted = false;
- String line;
- AltosState state = null;
- AltosState old_state = null;
- boolean told;
-
- idle_thread = new IdleThread();
-
- display.reset();
- try {
- for (;;) {
- try {
- AltosRecord record = reader.read();
- if (record == null)
- break;
- old_state = state;
- state = new AltosState(record, state);
- reader.update(state);
- show(state, crc_errors);
- told = tell(state, old_state);
- idle_thread.notice(state, told);
- } catch (ParseException pp) {
- System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
- } catch (AltosCRCException ce) {
- ++crc_errors;
- show(state, crc_errors);
- }
- }
- } catch (InterruptedException ee) {
- interrupted = true;
- } catch (IOException ie) {
- JOptionPane.showMessageDialog(parent,
- String.format("Error reading from \"%s\"", name),
- "Telemetry Read Error",
- JOptionPane.ERROR_MESSAGE);
- } finally {
- if (!interrupted)
- idle_thread.report(true);
- reader.close(interrupted);
- idle_thread.interrupt();
- try {
- idle_thread.join();
- } catch (InterruptedException ie) {}
- }
- }
-
- public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
- parent = in_parent;
- voice = in_voice;
- display = in_display;
- reader = in_reader;
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.*;
-
-import libaltosJNI.*;
-
-public class AltosEepromDownload implements Runnable {
-
- static final String[] state_names = {
- "startup",
- "idle",
- "pad",
- "boost",
- "fast",
- "coast",
- "drogue",
- "main",
- "landed",
- "invalid",
- };
-
- int[] ParseHex(String line) {
- String[] tokens = line.split("\\s+");
- int[] array = new int[tokens.length];
-
- for (int i = 0; i < tokens.length; i++)
- try {
- array[i] = Integer.parseInt(tokens[i], 16);
- } catch (NumberFormatException ne) {
- return null;
- }
- return array;
- }
-
- int checksum(int[] line) {
- int csum = 0x5a;
- for (int i = 1; i < line.length; i++)
- csum += line[i];
- return csum & 0xff;
- }
-
- void FlushPending(FileWriter file, LinkedList<String> pending) throws IOException {
- while (!pending.isEmpty()) {
- file.write(pending.remove());
- }
- }
-
- JFrame frame;
- AltosDevice device;
- AltosSerial serial_line;
- boolean remote;
- Thread eeprom_thread;
- AltosEepromMonitor monitor;
-
- void CaptureLog() throws IOException, InterruptedException, TimeoutException {
- int serial = 0;
- int block, state_block = 0;
- int addr;
- int flight = 0;
- int year = 0, month = 0, day = 0;
- int state = 0;
- boolean done = false;
- boolean want_file = false;
- boolean any_valid;
- FileWriter eeprom_file = null;
- AltosFile eeprom_name;
- LinkedList<String> eeprom_pending = new LinkedList<String>();
-
- serial_line.printf("\nc s\nv\n");
-
- /* Pull the serial number out of the version information */
-
- for (;;) {
- String line = serial_line.get_reply(5000);
-
- if (line == null)
- throw new TimeoutException();
- if (line.startsWith("serial-number")) {
- try {
- serial = Integer.parseInt(line.substring(13).trim());
- } catch (NumberFormatException ne) {
- serial = 0;
- }
- }
-
- eeprom_pending.add(String.format("%s\n", line));
-
- /* signals the end of the version info */
- if (line.startsWith("software-version"))
- break;
- }
- if (serial == 0)
- throw new IOException("no serial number found");
-
- monitor.set_serial(serial);
- /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
-
- state = 0; state_block = 0;
- for (block = 0; !done && block < 511; block++) {
- serial_line.printf("e %x\n", block);
- any_valid = false;
- monitor.set_value(state_names[state], state, block - state_block);
- for (addr = 0; addr < 0x100;) {
- String line = serial_line.get_reply(5000);
- if (line == null)
- throw new TimeoutException();
- int[] values = ParseHex(line);
-
- if (values == null) {
- System.out.printf("invalid line: %s\n", line);
- continue;
- } else if (values[0] != addr) {
- System.out.printf("data address out of sync at 0x%x\n",
- block * 256 + values[0]);
- } else if (checksum(values) != 0) {
- System.out.printf("invalid checksum at 0x%x\n",
- block * 256 + values[0]);
- } else {
- any_valid = true;
- int cmd = values[1];
- int tick = values[3] + (values[4] << 8);
- int a = values[5] + (values[6] << 8);
- int b = values[7] + (values[8] << 8);
-
- if (cmd == Altos.AO_LOG_FLIGHT) {
- flight = b;
- monitor.set_flight(flight);
- }
-
- /* Monitor state transitions to update display */
- if (cmd == Altos.AO_LOG_STATE && a <= Altos.ao_flight_landed) {
- if (a > Altos.ao_flight_pad)
- want_file = true;
- if (a > state)
- state_block = block;
- state = a;
- }
-
- if (cmd == Altos.AO_LOG_GPS_DATE) {
- year = 2000 + (a & 0xff);
- month = (a >> 8) & 0xff;
- day = (b & 0xff);
- want_file = true;
- }
-
- if (eeprom_file == null) {
- if (serial != 0 && flight != 0 && want_file) {
- if (year != 0 && month != 0 && day != 0)
- eeprom_name = new AltosFile(year, month, day, serial, flight, "eeprom");
- else
- eeprom_name = new AltosFile(serial, flight, "eeprom");
-
- monitor.set_file(eeprom_name.getName());
- eeprom_file = new FileWriter(eeprom_name);
- if (eeprom_file != null) {
- FlushPending(eeprom_file, eeprom_pending);
- eeprom_pending = null;
- }
- }
- }
-
- String log_line = String.format("%c %4x %4x %4x\n",
- cmd, tick, a, b);
- if (eeprom_file != null)
- eeprom_file.write(log_line);
- else
- eeprom_pending.add(log_line);
-
- if (cmd == Altos.AO_LOG_STATE && a == Altos.ao_flight_landed) {
- done = true;
- }
- }
- addr += 8;
- }
- if (!any_valid)
- done = true;
- }
- if (eeprom_file == null) {
- eeprom_name = new AltosFile(serial,flight,"eeprom");
- eeprom_file = new FileWriter(eeprom_name);
- if (eeprom_file != null) {
- FlushPending(eeprom_file, eeprom_pending);
- }
- }
- if (eeprom_file != null) {
- eeprom_file.flush();
- eeprom_file.close();
- }
- }
-
- public void run () {
- if (remote) {
- serial_line.set_radio();
- serial_line.printf("p\nE 0\n");
- serial_line.flush_input();
- }
-
- monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
- monitor.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- eeprom_thread.interrupt();
- }
- });
- try {
- CaptureLog();
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(frame,
- device.toShortString(),
- ee.getLocalizedMessage(),
- JOptionPane.ERROR_MESSAGE);
- } catch (InterruptedException ie) {
- } catch (TimeoutException te) {
- JOptionPane.showMessageDialog(frame,
- String.format("Connection to \"%s\" failed",
- device.toShortString()),
- "Connection Failed",
- JOptionPane.ERROR_MESSAGE);
- }
- if (remote)
- serial_line.printf("~");
- monitor.done();
- serial_line.flush_output();
- serial_line.close();
- }
-
- public AltosEepromDownload(JFrame given_frame) {
- frame = given_frame;
- device = AltosDeviceDialog.show(frame, AltosDevice.product_any);
-
- remote = false;
-
- if (device != null) {
- try {
- serial_line = new AltosSerial(device);
- if (!device.matchProduct(AltosDevice.product_telemetrum))
- remote = true;
- eeprom_thread = new Thread(this);
- eeprom_thread.start();
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(frame,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
- "Cannot open target device",
- JOptionPane.ERROR_MESSAGE);
- } catch (AltosSerialInUseException si) {
- JOptionPane.showMessageDialog(frame,
- String.format("Device \"%s\" already in use",
- device.toShortString()),
- "Device in use",
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(frame,
- device.toShortString(),
- ee.getLocalizedMessage(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/*
- * AltosRecords with an index field so they can be sorted by tick while preserving
- * the original ordering for elements with matching ticks
- */
-class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> {
-
- public int index;
-
- public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
- throws ParseException {
- super(line);
- if (prev_tick_valid) {
- tick |= (prev_tick & ~0xffff);
- if (tick < prev_tick) {
- if (prev_tick - tick > 0x8000)
- tick += 0x10000;
- } else {
- if (tick - prev_tick > 0x8000)
- tick -= 0x10000;
- }
- }
- index = in_index;
- }
-
- public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
- super(in_cmd, in_tick, in_a, in_b);
- index = in_index;
- }
-
- public int compareTo(AltosOrderedRecord o) {
- int tick_diff = tick - o.tick;
- if (tick_diff != 0)
- return tick_diff;
- return index - o.index;
- }
-}
-
-public class AltosEepromIterable extends AltosRecordIterable {
-
- static final int seen_flight = 1;
- static final int seen_sensor = 2;
- static final int seen_temp_volt = 4;
- static final int seen_deploy = 8;
- static final int seen_gps_time = 16;
- static final int seen_gps_lat = 32;
- static final int seen_gps_lon = 64;
-
- static final int seen_basic = seen_flight|seen_sensor|seen_temp_volt|seen_deploy;
-
- AltosEepromRecord flight_record;
- AltosEepromRecord gps_date_record;
-
- TreeSet<AltosOrderedRecord> records;
-
- LinkedList<AltosRecord> list;
-
- class EepromState {
- int seen;
- int n_pad_samples;
- double ground_pres;
- int gps_tick;
- int boost_tick;
-
- EepromState() {
- seen = 0;
- n_pad_samples = 0;
- ground_pres = 0.0;
- gps_tick = 0;
- }
- }
-
- void update_state(AltosRecord state, AltosEepromRecord record, EepromState eeprom) {
- state.tick = record.tick;
- switch (record.cmd) {
- case Altos.AO_LOG_FLIGHT:
- eeprom.seen |= seen_flight;
- state.ground_accel = record.a;
- state.flight_accel = record.a;
- state.flight = record.b;
- eeprom.boost_tick = record.tick;
- break;
- case Altos.AO_LOG_SENSOR:
- state.accel = record.a;
- state.pres = record.b;
- if (state.state < Altos.ao_flight_boost) {
- eeprom.n_pad_samples++;
- eeprom.ground_pres += state.pres;
- state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
- state.flight_pres = state.ground_pres;
- } else {
- state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
- state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
- state.flight_vel += (state.accel_plus_g - state.accel);
- }
- eeprom.seen |= seen_sensor;
- break;
- case Altos.AO_LOG_TEMP_VOLT:
- state.temp = record.a;
- state.batt = record.b;
- eeprom.seen |= seen_temp_volt;
- break;
- case Altos.AO_LOG_DEPLOY:
- state.drogue = record.a;
- state.main = record.b;
- eeprom.seen |= seen_deploy;
- break;
- case Altos.AO_LOG_STATE:
- state.state = record.a;
- break;
- case Altos.AO_LOG_GPS_TIME:
- eeprom.gps_tick = state.tick;
- AltosGPS old = state.gps;
- state.gps = new AltosGPS();
-
- /* GPS date doesn't get repeated through the file */
- if (old != null) {
- state.gps.year = old.year;
- state.gps.month = old.month;
- state.gps.day = old.day;
- }
- state.gps.hour = (record.a & 0xff);
- state.gps.minute = (record.a >> 8);
- state.gps.second = (record.b & 0xff);
-
- int flags = (record.b >> 8);
- state.gps.connected = (flags & Altos.AO_GPS_RUNNING) != 0;
- state.gps.locked = (flags & Altos.AO_GPS_VALID) != 0;
- state.gps.date_valid = (flags & Altos.AO_GPS_DATE_VALID) != 0;
- state.gps.nsat = (flags & Altos.AO_GPS_NUM_SAT_MASK) >>
- Altos.AO_GPS_NUM_SAT_SHIFT;
- break;
- case Altos.AO_LOG_GPS_LAT:
- int lat32 = record.a | (record.b << 16);
- state.gps.lat = (double) lat32 / 1e7;
- break;
- case Altos.AO_LOG_GPS_LON:
- int lon32 = record.a | (record.b << 16);
- state.gps.lon = (double) lon32 / 1e7;
- break;
- case Altos.AO_LOG_GPS_ALT:
- state.gps.alt = record.a;
- break;
- case Altos.AO_LOG_GPS_SAT:
- if (state.tick == eeprom.gps_tick) {
- int svid = record.a;
- int c_n0 = record.b >> 8;
- state.gps.add_sat(svid, c_n0);
- }
- break;
- case Altos.AO_LOG_GPS_DATE:
- state.gps.year = (record.a & 0xff) + 2000;
- state.gps.month = record.a >> 8;
- state.gps.day = record.b & 0xff;
- break;
-
- case Altos.AO_LOG_CONFIG_VERSION:
- break;
- case Altos.AO_LOG_MAIN_DEPLOY:
- break;
- case Altos.AO_LOG_APOGEE_DELAY:
- break;
- case Altos.AO_LOG_RADIO_CHANNEL:
- break;
- case Altos.AO_LOG_CALLSIGN:
- state.callsign = record.data;
- break;
- case Altos.AO_LOG_ACCEL_CAL:
- state.accel_plus_g = record.a;
- state.accel_minus_g = record.b;
- break;
- case Altos.AO_LOG_RADIO_CAL:
- break;
- case Altos.AO_LOG_MANUFACTURER:
- break;
- case Altos.AO_LOG_PRODUCT:
- break;
- case Altos.AO_LOG_SERIAL_NUMBER:
- state.serial = record.a;
- break;
- case Altos.AO_LOG_SOFTWARE_VERSION:
- break;
- }
- }
-
- LinkedList<AltosRecord> make_list() {
- LinkedList<AltosRecord> list = new LinkedList<AltosRecord>();
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- AltosOrderedRecord record = null;
- AltosRecord state = new AltosRecord();
- boolean last_reported = false;
- EepromState eeprom = new EepromState();
-
- state.state = Altos.ao_flight_pad;
- state.accel_plus_g = 15758;
- state.accel_minus_g = 16294;
-
- /* Pull in static data from the flight and gps_date records */
- if (flight_record != null)
- update_state(state, flight_record, eeprom);
- if (gps_date_record != null)
- update_state(state, gps_date_record, eeprom);
-
- while (iterator.hasNext()) {
- record = iterator.next();
- if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
- AltosRecord r = new AltosRecord(state);
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
- }
- update_state(state, record, eeprom);
- }
- AltosRecord r = new AltosRecord(state);
- r.time = (r.tick - eeprom.boost_tick) / 100.0;
- list.add(r);
- return list;
- }
-
- public Iterator<AltosRecord> iterator() {
- if (list == null)
- list = make_list();
- return list.iterator();
- }
-
- public void write_comments(PrintStream out) {
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- out.printf("# Comments\n");
- while (iterator.hasNext()) {
- AltosOrderedRecord record = iterator.next();
- switch (record.cmd) {
- case Altos.AO_LOG_CONFIG_VERSION:
- out.printf("# Config version: %s\n", record.data);
- break;
- case Altos.AO_LOG_MAIN_DEPLOY:
- out.printf("# Main deploy: %s\n", record.a);
- break;
- case Altos.AO_LOG_APOGEE_DELAY:
- out.printf("# Apogee delay: %s\n", record.a);
- break;
- case Altos.AO_LOG_RADIO_CHANNEL:
- out.printf("# Radio channel: %s\n", record.a);
- break;
- case Altos.AO_LOG_CALLSIGN:
- out.printf("# Callsign: %s\n", record.data);
- break;
- case Altos.AO_LOG_ACCEL_CAL:
- out.printf ("# Accel cal: %d %d\n", record.a, record.b);
- break;
- case Altos.AO_LOG_RADIO_CAL:
- out.printf ("# Radio cal: %d\n", record.a);
- break;
- case Altos.AO_LOG_MANUFACTURER:
- out.printf ("# Manufacturer: %s\n", record.data);
- break;
- case Altos.AO_LOG_PRODUCT:
- out.printf ("# Product: %s\n", record.data);
- break;
- case Altos.AO_LOG_SERIAL_NUMBER:
- out.printf ("# Serial number: %d\n", record.a);
- break;
- case Altos.AO_LOG_SOFTWARE_VERSION:
- out.printf ("# Software version: %s\n", record.data);
- break;
- }
- }
- }
-
- /*
- * Given an AO_LOG_GPS_TIME record with correct time, and one
- * missing time, rewrite the missing time values with the good
- * ones, assuming that the difference between them is 'diff' seconds
- */
- void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
-
- int diff = (bad.tick - good.tick + 50) / 100;
-
- int hour = (good.a & 0xff);
- int minute = (good.a >> 8);
- int second = (good.b & 0xff);
- int flags = (good.b >> 8);
- int seconds = hour * 3600 + minute * 60 + second;
-
- /* Make sure this looks like a good GPS value */
- if ((flags & Altos.AO_GPS_NUM_SAT_MASK) >> Altos.AO_GPS_NUM_SAT_SHIFT < 4)
- flags = (flags & ~Altos.AO_GPS_NUM_SAT_MASK) | (4 << Altos.AO_GPS_NUM_SAT_SHIFT);
- flags |= Altos.AO_GPS_RUNNING;
- flags |= Altos.AO_GPS_VALID;
-
- int new_seconds = seconds + diff;
- if (new_seconds < 0)
- new_seconds += 24 * 3600;
- int new_second = (new_seconds % 60);
- int new_minutes = (new_seconds / 60);
- int new_minute = (new_minutes % 60);
- int new_hours = (new_minutes / 60);
- int new_hour = (new_hours % 24);
-
- bad.a = new_hour + (new_minute << 8);
- bad.b = new_second + (flags << 8);
- }
-
- /*
- * Read the whole file, dumping records into a RB tree so
- * we can enumerate them in time order -- the eeprom data
- * are sometimes out of order with GPS data getting timestamps
- * matching the first packet out of the GPS unit but not
- * written until the final GPS packet has been received.
- */
- public AltosEepromIterable (FileInputStream input) {
- records = new TreeSet<AltosOrderedRecord>();
-
- AltosOrderedRecord last_gps_time = null;
-
- int index = 0;
- int prev_tick = 0;
- boolean prev_tick_valid = false;
- boolean missing_time = false;
-
- try {
- for (;;) {
- String line = AltosRecord.gets(input);
- if (line == null)
- break;
- AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
- if (record == null)
- break;
- if (record.cmd == Altos.AO_LOG_INVALID)
- continue;
- prev_tick = record.tick;
- if (record.cmd < Altos.AO_LOG_CONFIG_VERSION)
- prev_tick_valid = true;
- if (record.cmd == Altos.AO_LOG_FLIGHT) {
- flight_record = record;
- continue;
- }
-
- /* Two firmware bugs caused the loss of some GPS data.
- * The flight date would never be recorded, and often
- * the flight time would get overwritten by another
- * record. Detect the loss of the GPS date and fix up the
- * missing time records
- */
- if (record.cmd == Altos.AO_LOG_GPS_DATE) {
- gps_date_record = record;
- continue;
- }
-
- /* go back and fix up any missing time values */
- if (record.cmd == Altos.AO_LOG_GPS_TIME) {
- last_gps_time = record;
- if (missing_time) {
- Iterator<AltosOrderedRecord> iterator = records.iterator();
- while (iterator.hasNext()) {
- AltosOrderedRecord old = iterator.next();
- if (old.cmd == Altos.AO_LOG_GPS_TIME &&
- old.a == -1 && old.b == -1)
- {
- update_time(record, old);
- }
- }
- missing_time = false;
- }
- }
-
- if (record.cmd == Altos.AO_LOG_GPS_LAT) {
- if (last_gps_time == null || last_gps_time.tick != record.tick) {
- AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME,
- record.tick,
- -1, -1, index-1);
- if (last_gps_time != null)
- update_time(last_gps_time, add_gps_time);
- else
- missing_time = true;
-
- records.add(add_gps_time);
- record.index = index++;
- }
- }
- records.add(record);
-
- /* Bail after reading the 'landed' record; we're all done */
- if (record.cmd == Altos.AO_LOG_STATE &&
- record.a == Altos.ao_flight_landed)
- break;
- }
- } catch (IOException io) {
- } catch (ParseException pe) {
- }
- try {
- input.close();
- } catch (IOException ie) {
- }
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosEepromMonitor extends JDialog {
-
- Container pane;
- Box box;
- JLabel serial_label;
- JLabel flight_label;
- JLabel file_label;
- JLabel serial_value;
- JLabel flight_value;
- JLabel file_value;
- JButton cancel;
- JProgressBar pbar;
- int min_state, max_state;
-
- public AltosEepromMonitor(JFrame owner, int in_min_state, int in_max_state) {
- super (owner, "Download Flight Data", false);
-
- GridBagConstraints c;
- Insets il = new Insets(4,4,4,4);
- Insets ir = new Insets(4,4,4,4);
-
- pane = getContentPane();
- pane.setLayout(new GridBagLayout());
-
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 0;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- serial_label = new JLabel("Serial:");
- pane.add(serial_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 1; c.gridy = 0;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- serial_value = new JLabel("");
- pane.add(serial_value, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.gridx = 0; c.gridy = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- flight_label = new JLabel("Flight:");
- pane.add(flight_label, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.gridx = 1; c.gridy = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- flight_value = new JLabel("");
- pane.add(flight_value, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.gridx = 0; c.gridy = 2;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- file_label = new JLabel("File:");
- pane.add(file_label, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.gridx = 1; c.gridy = 2;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- file_value = new JLabel("");
- pane.add(file_value, c);
-
- min_state = in_min_state;
- max_state = in_max_state;
- pbar = new JProgressBar();
- pbar.setMinimum(0);
- pbar.setMaximum((max_state - min_state) * 100);
- pbar.setValue(0);
- pbar.setString("startup");
- pbar.setStringPainted(true);
- pbar.setPreferredSize(new Dimension(600, 20));
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.HORIZONTAL;
- c.anchor = GridBagConstraints.CENTER;
- c.gridx = 0; c.gridy = 3;
- c.gridwidth = GridBagConstraints.REMAINDER;
- Insets ib = new Insets(4,4,4,4);
- c.insets = ib;
- pane.add(pbar, c);
-
-
- cancel = new JButton("Cancel");
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.gridx = 0; c.gridy = 4;
- c.gridwidth = GridBagConstraints.REMAINDER;
- Insets ic = new Insets(4,4,4,4);
- c.insets = ic;
- pane.add(cancel, c);
-
- pack();
- setLocationRelativeTo(owner);
- setVisible(true);
- }
-
- public void addActionListener (ActionListener l) {
- cancel.addActionListener(l);
- }
-
- public void set_value(String state_name, int in_state, int in_block) {
- int block = in_block;
- int state = in_state;
-
- if (block > 100)
- block = 100;
- if (state < min_state) state = min_state;
- if (state >= max_state) state = max_state - 1;
- state -= min_state;
-
- int pos = state * 100 + block;
-
- pbar.setString(state_name);
- pbar.setValue(pos);
- }
-
- public void set_serial(int serial) {
- serial_value.setText(String.format("%d", serial));
- }
-
- public void set_flight(int flight) {
- flight_value.setText(String.format("%d", flight));
- }
-
- public void set_file(String file) {
- file_value.setText(String.format("%s", file));
- }
-
- public void done() {
- setVisible(false);
- dispose();
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosEepromRecord {
- public int cmd;
- public int tick;
- public int a;
- public int b;
- public String data;
- public boolean tick_valid;
-
- public AltosEepromRecord (String line) {
- tick_valid = false;
- tick = 0;
- a = 0;
- b = 0;
- data = null;
- if (line == null) {
- cmd = Altos.AO_LOG_INVALID;
- data = "";
- } else {
- try {
- String[] tokens = line.split("\\s+");
-
- if (tokens[0].length() == 1) {
- if (tokens.length != 4) {
- cmd = Altos.AO_LOG_INVALID;
- data = line;
- } else {
- cmd = tokens[0].codePointAt(0);
- tick = Integer.parseInt(tokens[1],16);
- tick_valid = true;
- a = Integer.parseInt(tokens[2],16);
- b = Integer.parseInt(tokens[3],16);
- }
- } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
- cmd = Altos.AO_LOG_CONFIG_VERSION;
- data = tokens[2];
- } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
- cmd = Altos.AO_LOG_MAIN_DEPLOY;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
- cmd = Altos.AO_LOG_APOGEE_DELAY;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
- cmd = Altos.AO_LOG_RADIO_CHANNEL;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("Callsign:")) {
- cmd = Altos.AO_LOG_CALLSIGN;
- data = tokens[1].replaceAll("\"","");
- } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
- cmd = Altos.AO_LOG_ACCEL_CAL;
- a = Integer.parseInt(tokens[3]);
- b = Integer.parseInt(tokens[5]);
- } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
- cmd = Altos.AO_LOG_RADIO_CAL;
- a = Integer.parseInt(tokens[2]);
- } else if (tokens[0].equals("manufacturer")) {
- cmd = Altos.AO_LOG_MANUFACTURER;
- data = tokens[1];
- } else if (tokens[0].equals("product")) {
- cmd = Altos.AO_LOG_PRODUCT;
- data = tokens[1];
- } else if (tokens[0].equals("serial-number")) {
- cmd = Altos.AO_LOG_SERIAL_NUMBER;
- a = Integer.parseInt(tokens[1]);
- } else if (tokens[0].equals("software-version")) {
- cmd = Altos.AO_LOG_SOFTWARE_VERSION;
- data = tokens[1];
- } else {
- cmd = Altos.AO_LOG_INVALID;
- data = line;
- }
- } catch (NumberFormatException ne) {
- cmd = Altos.AO_LOG_INVALID;
- data = line;
- }
- }
- }
-
- public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) {
- tick_valid = true;
- cmd = in_cmd;
- tick = in_tick;
- a = in_a;
- b = in_b;
- }
-}
+++ /dev/null
-/*
- * 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.File;
-import java.util.*;
-
-class AltosFile extends File {
-
- public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
- super (AltosPreferences.logdir(),
- String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
- year, month, day, serial, flight, extension));
- }
-
- public AltosFile(int serial, int flight, String extension) {
- this(Calendar.getInstance().get(Calendar.YEAR),
- Calendar.getInstance().get(Calendar.MONTH) + 1,
- Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
- serial,
- flight,
- extension);
- }
-
- public AltosFile(AltosTelemetry telem) {
- this(telem.serial, telem.flight, "telem");
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlash {
- File file;
- FileInputStream input;
- AltosHexfile image;
- JFrame frame;
- AltosDevice debug_dongle;
- AltosDebug debug;
- AltosRomconfig rom_config;
- ActionListener listener;
- boolean aborted;
-
- static final byte MOV_direct_data = (byte) 0x75;
- static final byte MOV_DPTR_data16 = (byte) 0x90;
- static final byte MOV_A_data = (byte) 0x74;
- static final byte MOVX_atDPTR_A = (byte) 0xf0;
- static final byte MOVX_A_atDPTR = (byte) 0xe0;
- static final byte INC_DPTR = (byte) 0xa3;
- static final byte TRAP = (byte) 0xa5;
-
- static final byte JB = (byte) 0x20;
-
- static final byte MOV_A_direct = (byte) 0xe5;
- static final byte MOV_direct1_direct2 = (byte) 0x85;
- static final byte MOV_direct_A = (byte) 0xf5;
- static final byte MOV_R0_data = (byte) (0x78 | 0);
- static final byte MOV_R1_data = (byte) (0x78 | 1);
- static final byte MOV_R2_data = (byte) (0x78 | 2);
- static final byte MOV_R3_data = (byte) (0x78 | 3);
- static final byte MOV_R4_data = (byte) (0x78 | 4);
- static final byte MOV_R5_data = (byte) (0x78 | 5);
- static final byte MOV_R6_data = (byte) (0x78 | 6);
- static final byte MOV_R7_data = (byte) (0x78 | 7);
- static final byte DJNZ_R0_rel = (byte) (0xd8 | 0);
- static final byte DJNZ_R1_rel = (byte) (0xd8 | 1);
- static final byte DJNZ_R2_rel = (byte) (0xd8 | 2);
- static final byte DJNZ_R3_rel = (byte) (0xd8 | 3);
- static final byte DJNZ_R4_rel = (byte) (0xd8 | 4);
- static final byte DJNZ_R5_rel = (byte) (0xd8 | 5);
- static final byte DJNZ_R6_rel = (byte) (0xd8 | 6);
- static final byte DJNZ_R7_rel = (byte) (0xd8 | 7);
-
- static final byte P1DIR = (byte) 0xFE;
- static final byte P1 = (byte) 0x90;
-
- /* flash controller */
- static final byte FWT = (byte) 0xAB;
- static final byte FADDRL = (byte) 0xAC;
- static final byte FADDRH = (byte) 0xAD;
- static final byte FCTL = (byte) 0xAE;
- static final byte FCTL_BUSY = (byte) 0x80;
- static final byte FCTL_BUSY_BIT = (byte) 7;
- static final byte FCTL_SWBSY = (byte) 0x40;
- static final byte FCTL_SWBSY_BIT = (byte) 6;
- static final byte FCTL_CONTRD = (byte) 0x10;
- static final byte FCTL_WRITE = (byte) 0x02;
- static final byte FCTL_ERASE = (byte) 0x01;
- static final byte FWDATA = (byte) 0xAF;
-
- static final byte ACC = (byte) 0xE0;
-
- /* offsets within the flash_page program */
- static final int FLASH_ADDR_HIGH = 8;
- static final int FLASH_ADDR_LOW = 11;
- static final int RAM_ADDR_HIGH = 13;
- static final int RAM_ADDR_LOW = 14;
- static final int FLASH_WORDS_HIGH = 16;
- static final int FLASH_WORDS_LOW = 18;
- static final int FLASH_TIMING = 21;
-
- /* sleep mode control */
- static final int SLEEP = (byte) 0xbe;
- static final int SLEEP_USB_EN = (byte) 0x80;
- static final int SLEEP_XOSC_STB = (byte) 0x40;
- static final int SLEEP_HFRC_STB = (byte) 0x20;
- static final int SLEEP_RST_MASK = (byte) 0x18;
- static final int SLEEP_RST_POWERON = (byte) 0x00;
- static final int SLEEP_RST_EXTERNAL = (byte) 0x10;
- static final int SLEEP_RST_WATCHDOG = (byte) 0x08;
- static final int SLEEP_OSC_PD = (byte) 0x04;
- static final int SLEEP_MODE_MASK = (byte) 0x03;
- static final int SLEEP_MODE_PM0 = (byte) 0x00;
- static final int SLEEP_MODE_PM1 = (byte) 0x01;
- static final int SLEEP_MODE_PM2 = (byte) 0x02;
- static final int SLEEP_MODE_PM3 = (byte) 0x03;
-
- /* clock controller */
- static final byte CLKCON = (byte) 0xC6;
- static final byte CLKCON_OSC32K = (byte) 0x80;
- static final byte CLKCON_OSC = (byte) 0x40;
- static final byte CLKCON_TICKSPD = (byte) 0x38;
- static final byte CLKCON_CLKSPD = (byte) 0x07;
-
- static final byte[] flash_page_proto = {
-
- MOV_direct_data, P1DIR, (byte) 0x02,
- MOV_direct_data, P1, (byte) 0xFF,
-
- MOV_direct_data, FADDRH, 0, /* FLASH_ADDR_HIGH */
-
- MOV_direct_data, FADDRL, 0, /* FLASH_ADDR_LOW */
-
- MOV_DPTR_data16, 0, 0, /* RAM_ADDR_HIGH, RAM_ADDR_LOW */
-
- MOV_R7_data, 0, /* FLASH_WORDS_HIGH */
-
- MOV_R6_data, 0, /* FLASH_WORDS_LOW */
-
-
- MOV_direct_data, FWT, 0x20, /* FLASH_TIMING */
-
- MOV_direct_data, FCTL, FCTL_ERASE,
-/* eraseWaitLoop: */
- MOV_A_direct, FCTL,
- JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb,
-
- MOV_direct_data, P1, (byte) 0xfd,
-
- MOV_direct_data, FCTL, FCTL_WRITE,
-/* writeLoop: */
- MOV_R5_data, 2,
-/* writeWordLoop: */
- MOVX_A_atDPTR,
- INC_DPTR,
- MOV_direct_A, FWDATA,
- DJNZ_R5_rel, (byte) 0xfa, /* writeWordLoop */
-/* writeWaitLoop: */
- MOV_A_direct, FCTL,
- JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb, /* writeWaitLoop */
- DJNZ_R6_rel, (byte) 0xf1, /* writeLoop */
- DJNZ_R7_rel, (byte) 0xef, /* writeLoop */
-
- MOV_direct_data, P1DIR, (byte) 0x00,
- MOV_direct_data, P1, (byte) 0xFF,
- TRAP,
- };
-
- public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) {
- int flash_word_addr = flash_addr >> 1;
- int flash_word_count = ((byte_count + 1) >> 1);
-
- byte[] flash_page = new byte[flash_page_proto.length];
- for (int i = 0; i < flash_page.length; i++)
- flash_page[i] = flash_page_proto[i];
-
- flash_page[FLASH_ADDR_HIGH] = (byte) (flash_word_addr >> 8);
- flash_page[FLASH_ADDR_LOW] = (byte) (flash_word_addr);
- flash_page[RAM_ADDR_HIGH] = (byte) (ram_addr >> 8);
- flash_page[RAM_ADDR_LOW] = (byte) (ram_addr);
-
- byte flash_words_low = (byte) (flash_word_count);
- byte flash_words_high = (byte) (flash_word_count >> 8);
- /* the flashing code has a minor 'bug' */
- if (flash_words_low != 0)
- flash_words_high++;
-
- flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high;
- flash_page[FLASH_WORDS_LOW] = (byte) flash_words_low;
- return flash_page;
- }
-
- static byte[] set_clkcon_fast = {
- MOV_direct_data, CLKCON, 0x00
- };
-
- static byte[] get_sleep = {
- MOV_A_direct, SLEEP
- };
-
- public void clock_init() throws IOException, InterruptedException {
- debug.debug_instr(set_clkcon_fast);
-
- byte status;
- for (int times = 0; times < 20; times++) {
- Thread.sleep(1);
- status = debug.debug_instr(get_sleep);
- if ((status & SLEEP_XOSC_STB) != 0)
- return;
- }
- throw new IOException("Failed to initialize target clock");
- }
-
- void action(String s, int percent) {
- if (listener != null && !aborted)
- listener.actionPerformed(new ActionEvent(this,
- percent,
- s));
- }
-
- void action(int part, int total) {
- int percent = 100 * part / total;
- action(String.format("%d/%d (%d%%)",
- part, total, percent),
- percent);
- }
-
- void run(int pc) throws IOException, InterruptedException {
- debug.set_pc(pc);
- int set_pc = debug.get_pc();
- if (pc != set_pc)
- throw new IOException("Failed to set target program counter");
- debug.resume();
-
- for (int times = 0; times < 20; times++) {
- byte status = debug.read_status();
- if ((status & AltosDebug.STATUS_CPU_HALTED) != 0)
- return;
- }
-
- throw new IOException("Failed to execute program on target");
- }
-
- public void flash() throws IOException, FileNotFoundException, InterruptedException {
- if (!check_rom_config())
- throw new IOException("Invalid rom config settings");
- if (image.address + image.data.length > 0x8000)
- throw new IOException(String.format("Flash image too long %d",
- image.address +
- image.data.length));
- if ((image.address & 0x3ff) != 0)
- throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)",
- image.address));
- int ram_address = 0xf000;
- int flash_prog = 0xf400;
-
- /*
- * Store desired config values into image
- */
- rom_config.write(image);
- /*
- * Bring up the clock
- */
- clock_init();
-
- int remain = image.data.length;
- int flash_addr = image.address;
- int image_start = 0;
-
- action("start", 0);
- action(0, image.data.length);
- while (remain > 0 && !aborted) {
- int this_time = remain;
- if (this_time > 0x400)
- this_time = 0x400;
-
- /* write the data */
- debug.write_memory(ram_address, image.data,
- image_start, this_time);
-
- /* write the flash program */
- byte[] flash_page = make_flash_page(flash_addr,
- ram_address,
- this_time);
- debug.write_memory(flash_prog, flash_page);
-
- run(flash_prog);
-
- byte[] check = debug.read_memory(flash_addr, this_time);
- for (int i = 0; i < this_time; i++)
- if (check[i] != image.data[image_start + i])
- throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
- image.address + image_start + i,
- check[i], image.data[image_start + i]));
- remain -= this_time;
- flash_addr += this_time;
- image_start += this_time;
-
- action(image.data.length - remain, image.data.length);
- }
- if (!aborted) {
- action("done", 100);
- debug.set_pc(image.address);
- debug.resume();
- }
- debug.close();
- }
-
- public void abort() {
- aborted = true;
- debug.close();
- }
-
- public void addActionListener(ActionListener l) {
- listener = l;
- }
-
- public boolean check_rom_config() {
- if (rom_config == null)
- rom_config = debug.romconfig();
- return rom_config != null && rom_config.valid();
- }
-
- public void set_romconfig (AltosRomconfig romconfig) {
- rom_config = romconfig;
- }
-
- public AltosRomconfig romconfig() {
- if (!check_rom_config())
- return null;
- return rom_config;
- }
-
- public AltosFlash(File in_file, AltosDevice in_debug_dongle)
- throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException {
- file = in_file;
- debug_dongle = in_debug_dongle;
- debug = new AltosDebug(in_debug_dongle);
- input = new FileInputStream(file);
- image = new AltosHexfile(input);
- if (!debug.check_connection()) {
- debug.close();
- throw new IOException("Debug port not connected");
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlashUI
- extends JDialog
- implements Runnable, ActionListener
-{
- Container pane;
- Box box;
- JLabel serial_label;
- JLabel serial_value;
- JLabel file_label;
- JLabel file_value;
- JProgressBar pbar;
- JButton cancel;
-
- File file;
- Thread thread;
- JFrame frame;
- AltosDevice debug_dongle;
- AltosFlash flash;
-
- public void actionPerformed(ActionEvent e) {
- if (e.getSource() == cancel) {
- abort();
- dispose();
- } else {
- String cmd = e.getActionCommand();
- if (cmd.equals("done"))
- ;
- else if (cmd.equals("start")) {
- setVisible(true);
- } else {
- pbar.setValue(e.getID());
- pbar.setString(cmd);
- }
- }
- }
-
- public void run() {
- try {
- flash = new AltosFlash(file, debug_dongle);
- flash.addActionListener(this);
- AltosRomconfigUI romconfig_ui = new AltosRomconfigUI (frame);
-
- romconfig_ui.set(flash.romconfig());
- AltosRomconfig romconfig = romconfig_ui.showDialog();
-
- if (romconfig != null && romconfig.valid()) {
- flash.set_romconfig(romconfig);
- serial_value.setText(String.format("%d",
- flash.romconfig().serial_number));
- file_value.setText(file.toString());
- setVisible(true);
- flash.flash();
- flash = null;
- }
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(frame,
- "Cannot open image",
- file.toString(),
- JOptionPane.ERROR_MESSAGE);
- } catch (AltosSerialInUseException si) {
- JOptionPane.showMessageDialog(frame,
- String.format("Device \"%s\" already in use",
- debug_dongle.toShortString()),
- "Device in use",
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException e) {
- JOptionPane.showMessageDialog(frame,
- e.getMessage(),
- file.toString(),
- JOptionPane.ERROR_MESSAGE);
- } catch (InterruptedException ie) {
- } finally {
- abort();
- }
- dispose();
- }
-
- public void abort() {
- if (flash != null)
- flash.abort();
- }
-
- public void build_dialog() {
- GridBagConstraints c;
- Insets il = new Insets(4,4,4,4);
- Insets ir = new Insets(4,4,4,4);
-
- pane = getContentPane();
- pane.setLayout(new GridBagLayout());
-
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 0;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- serial_label = new JLabel("Serial:");
- pane.add(serial_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 1; c.gridy = 0;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- serial_value = new JLabel("");
- pane.add(serial_value, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.gridx = 0; c.gridy = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- file_label = new JLabel("File:");
- pane.add(file_label, c);
-
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.gridx = 1; c.gridy = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- file_value = new JLabel("");
- pane.add(file_value, c);
-
- pbar = new JProgressBar();
- pbar.setMinimum(0);
- pbar.setMaximum(100);
- pbar.setValue(0);
- pbar.setString("");
- pbar.setStringPainted(true);
- pbar.setPreferredSize(new Dimension(600, 20));
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.HORIZONTAL;
- c.anchor = GridBagConstraints.CENTER;
- c.gridx = 0; c.gridy = 2;
- c.gridwidth = GridBagConstraints.REMAINDER;
- Insets ib = new Insets(4,4,4,4);
- c.insets = ib;
- pane.add(pbar, c);
-
- cancel = new JButton("Cancel");
- c = new GridBagConstraints();
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.gridx = 0; c.gridy = 3;
- c.gridwidth = GridBagConstraints.REMAINDER;
- Insets ic = new Insets(4,4,4,4);
- c.insets = ic;
- pane.add(cancel, c);
- cancel.addActionListener(this);
- pack();
- setLocationRelativeTo(frame);
- }
-
- public AltosFlashUI(JFrame in_frame) {
- super(in_frame, "Program Altusmetrum Device", false);
-
- frame = in_frame;
-
- build_dialog();
-
- debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.product_any);
-
- if (debug_dongle == null)
- return;
-
- JFileChooser hexfile_chooser = new JFileChooser();
-
- File firmwaredir = AltosPreferences.firmwaredir();
- if (firmwaredir != null)
- hexfile_chooser.setCurrentDirectory(firmwaredir);
-
- hexfile_chooser.setDialogTitle("Select Flash Image");
- hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
- int returnVal = hexfile_chooser.showOpenDialog(frame);
-
- if (returnVal != JFileChooser.APPROVE_OPTION)
- return;
-
- file = hexfile_chooser.getSelectedFile();
-
- if (file != null)
- AltosPreferences.set_firmwaredir(file.getParentFile());
-
- thread = new Thread(this);
- thread.start();
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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;
-
-public interface AltosFlightDisplay {
- void reset();
-
- void show(AltosState state, int crc_errors);
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlightInfoTableModel extends AbstractTableModel {
- final static private String[] columnNames = {"Field", "Value"};
-
- int rows;
- int cols;
- private String[][] data;
-
- public int getColumnCount() { return cols; }
- public int getRowCount() { return rows; }
- public String getColumnName(int col) { return columnNames[col & 1]; }
-
- public Object getValueAt(int row, int col) {
- if (row >= rows || col >= cols)
- return "";
- return data[row][col];
- }
-
- int[] current_row;
-
- public void reset() {
- for (int i = 0; i < cols / 2; i++)
- current_row[i] = 0;
- }
-
- public void clear() {
- reset();
- for (int c = 0; c < cols; c++)
- for (int r = 0; r < rows; r++)
- data[r][c] = "";
- fireTableDataChanged();
- }
-
- public void addRow(int col, String name, String value) {
- if (current_row[col] < rows) {
- data[current_row[col]][col * 2] = name;
- data[current_row[col]][col * 2 + 1] = value;
- }
- current_row[col]++;
- }
-
- public void finish() {
- for (int c = 0; c < cols / 2; c++)
- while (current_row[c] < rows)
- addRow(c, "", "");
- fireTableDataChanged();
- }
-
- public AltosFlightInfoTableModel (int in_rows, int in_cols) {
- rows = in_rows;
- cols = in_cols * 2;
- data = new String[rows][cols];
- current_row = new int[in_cols];
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.io.*;
-
-public class AltosFlightReader {
- String name;
-
- int serial;
-
- void init() { }
-
- AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
-
- void close(boolean interrupted) { }
-
- void set_channel(int channel) { }
-
- void update(AltosState state) throws InterruptedException { }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
- GridBagLayout layout;
-
- public class FlightValue {
- JLabel label;
- JTextField value;
-
- void show(AltosState state, int crc_errors) {}
-
- void reset() {
- value.setText("");
- }
- public FlightValue (GridBagLayout layout, int x, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.insets = new Insets(5, 5, 5, 5);
- c.anchor = GridBagConstraints.CENTER;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.status_font);
- label.setHorizontalAlignment(SwingConstants.CENTER);
- c.gridx = x; c.gridy = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField("");
- value.setFont(Altos.status_font);
- value.setHorizontalAlignment(SwingConstants.CENTER);
- c.gridx = x; c.gridy = 1;
- layout.setConstraints(value, c);
- add(value);
- }
- }
-
- class Call extends FlightValue {
- void show(AltosState state, int crc_errors) {
- value.setText(state.data.callsign);
- }
- public Call (GridBagLayout layout, int x) {
- super (layout, x, "Callsign");
- }
- }
-
- Call call;
-
- class Serial extends FlightValue {
- void show(AltosState state, int crc_errors) {
- value.setText(String.format("%d", state.data.serial));
- }
- public Serial (GridBagLayout layout, int x) {
- super (layout, x, "Serial");
- }
- }
-
- Serial serial;
-
- class Flight extends FlightValue {
- void show(AltosState state, int crc_errors) {
- value.setText(String.format("%d", state.data.flight));
- }
- public Flight (GridBagLayout layout, int x) {
- super (layout, x, "Flight");
- }
- }
-
- Flight flight;
-
- class FlightState extends FlightValue {
- void show(AltosState state, int crc_errors) {
- value.setText(state.data.state());
- }
- public FlightState (GridBagLayout layout, int x) {
- super (layout, x, "State");
- }
- }
-
- FlightState flight_state;
-
- class RSSI extends FlightValue {
- void show(AltosState state, int crc_errors) {
- value.setText(String.format("%d", state.data.rssi));
- }
- public RSSI (GridBagLayout layout, int x) {
- super (layout, x, "RSSI (dBm)");
- }
- }
-
- RSSI rssi;
-
- public void reset () {
- call.reset();
- serial.reset();
- flight.reset();
- flight_state.reset();
- rssi.reset();
- }
-
- public void show (AltosState state, int crc_errors) {
- call.show(state, crc_errors);
- serial.show(state, crc_errors);
- flight.show(state, crc_errors);
- flight_state.show(state, crc_errors);
- rssi.show(state, crc_errors);
- }
-
- public int height() {
- Dimension d = layout.preferredLayoutSize(this);
- return d.height;
- }
-
- public AltosFlightStatus() {
- layout = new GridBagLayout();
-
- setLayout(layout);
-
- call = new Call(layout, 0);
- serial = new Serial(layout, 1);
- flight = new Flight(layout, 2);
- flight_state = new FlightState(layout, 3);
- rssi = new RSSI(layout, 4);
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlightStatusTableModel extends AbstractTableModel {
- private String[] columnNames = {"Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
- private Object[] data = { 0, "idle", 0, 0 };
-
- public int getColumnCount() { return columnNames.length; }
- public int getRowCount() { return 2; }
- public Object getValueAt(int row, int col) {
- if (row == 0)
- return columnNames[col];
- return data[col];
- }
-
- public void setValueAt(Object value, int col) {
- data[col] = value;
- fireTableCellUpdated(1, col);
- }
-
- public void setValueAt(Object value, int row, int col) {
- setValueAt(value, col);
- }
-
- public void set(AltosState state) {
- setValueAt(String.format("%1.0f", state.height), 0);
- setValueAt(state.data.state(), 1);
- setValueAt(state.data.rssi, 2);
- double speed = state.baro_speed;
- if (state.ascent)
- speed = state.speed;
- setValueAt(String.format("%1.0f", speed), 3);
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosFlightUI extends JFrame implements AltosFlightDisplay {
- String[] statusNames = { "Height (m)", "State", "RSSI (dBm)", "Speed (m/s)" };
- Object[][] statusData = { { "0", "pad", "-50", "0" } };
-
- AltosVoice voice;
- AltosFlightReader reader;
- AltosDisplayThread thread;
-
- JTabbedPane pane;
-
- AltosPad pad;
- AltosAscent ascent;
- AltosDescent descent;
- AltosLanded landed;
- AltosSiteMap sitemap;
-
- private AltosFlightStatus flightStatus;
- private AltosInfoTable flightInfo;
-
- static final int tab_pad = 1;
- static final int tab_ascent = 2;
- static final int tab_descent = 3;
- static final int tab_landed = 4;
-
- int cur_tab = 0;
-
- boolean exit_on_close = false;
-
- int which_tab(AltosState state) {
- if (state.state < Altos.ao_flight_boost)
- return tab_pad;
- if (state.state <= Altos.ao_flight_coast)
- return tab_ascent;
- if (state.state <= Altos.ao_flight_main)
- return tab_descent;
- return tab_landed;
- }
-
- void stop_display() {
- if (thread != null && thread.isAlive()) {
- thread.interrupt();
- try {
- thread.join();
- } catch (InterruptedException ie) {}
- }
- thread = null;
- }
-
- void disconnect() {
- stop_display();
- }
-
- public void reset() {
- pad.reset();
- ascent.reset();
- descent.reset();
- landed.reset();
- flightInfo.clear();
- sitemap.reset();
- }
-
- public void show(AltosState state, int crc_errors) {
- int tab = which_tab(state);
- pad.show(state, crc_errors);
- ascent.show(state, crc_errors);
- descent.show(state, crc_errors);
- landed.show(state, crc_errors);
- if (tab != cur_tab) {
- switch (tab) {
- case tab_pad:
- pane.setSelectedComponent(pad);
- break;
- case tab_ascent:
- pane.setSelectedComponent(ascent);
- break;
- case tab_descent:
- pane.setSelectedComponent(descent);
- break;
- case tab_landed:
- pane.setSelectedComponent(landed);
- }
- cur_tab = tab;
- }
- flightStatus.show(state, crc_errors);
- flightInfo.show(state, crc_errors);
- sitemap.show(state, crc_errors);
- }
-
- public void set_exit_on_close() {
- exit_on_close = true;
- }
-
- Container bag;
- JComboBox channels;
-
- public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) {
- AltosPreferences.init(this);
-
- voice = in_voice;
- reader = in_reader;
-
- bag = getContentPane();
- bag.setLayout(new GridBagLayout());
-
- GridBagConstraints c = new GridBagConstraints();
-
- java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
- if (imgURL != null)
- setIconImage(new ImageIcon(imgURL).getImage());
-
- setTitle(String.format("AltOS %s", reader.name));
-
- /* Stick channel selector at top of table for telemetry monitoring */
- if (serial >= 0) {
- // Channel menu
- channels = new AltosChannelMenu(AltosPreferences.channel(serial));
- channels.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- int channel = channels.getSelectedIndex();
- reader.set_channel(channel);
- }
- });
- c.gridx = 0;
- c.gridy = 0;
- c.anchor = GridBagConstraints.WEST;
- bag.add (channels, c);
- }
-
- /* Flight status is always visible */
- flightStatus = new AltosFlightStatus();
- c.gridx = 0;
- c.gridy = 1;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- bag.add(flightStatus, c);
-
- /* The rest of the window uses a tabbed pane to
- * show one of the alternate data views
- */
- pane = new JTabbedPane();
-
- pad = new AltosPad();
- pane.add("Launch Pad", pad);
-
- ascent = new AltosAscent();
- pane.add("Ascent", ascent);
-
- descent = new AltosDescent();
- pane.add("Descent", descent);
-
- landed = new AltosLanded();
- pane.add("Landed", landed);
-
- flightInfo = new AltosInfoTable();
- pane.add("Table", new JScrollPane(flightInfo));
-
- sitemap = new AltosSiteMap();
- pane.add("Site Map", sitemap);
-
- /* Make the tabbed pane use the rest of the window space */
- c.gridx = 0;
- c.gridy = 2;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- c.weighty = 1;
- bag.add(pane, c);
-
- setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- disconnect();
- setVisible(false);
- dispose();
- if (exit_on_close)
- System.exit(0);
- }
- });
-
- pack();
- setVisible(true);
-
- thread = new AltosDisplayThread(this, voice, this, reader);
-
- thread.start();
- }
-
- public AltosFlightUI (AltosVoice in_voice, AltosFlightReader in_reader) {
- this(in_voice, in_reader, -1);
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-
-public class AltosGPS {
- public class AltosGPSSat {
- int svid;
- int c_n0;
- }
-
- int nsat;
- boolean locked;
- boolean connected;
- boolean date_valid;
- double lat; /* degrees (+N -S) */
- double lon; /* degrees (+E -W) */
- int alt; /* m */
- int year;
- int month;
- int day;
- int hour;
- int minute;
- int second;
-
- int gps_extended; /* has extra data */
- double ground_speed; /* m/s */
- int course; /* degrees */
- double climb_rate; /* m/s */
- double hdop; /* unitless? */
- int h_error; /* m */
- int v_error; /* m */
-
- AltosGPSSat[] cc_gps_sat; /* tracking data */
-
- void ParseGPSDate(String date) throws ParseException {
- String[] ymd = date.split("-");
- if (ymd.length != 3)
- throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0);
- year = AltosParse.parse_int(ymd[0]);
- month = AltosParse.parse_int(ymd[1]);
- day = AltosParse.parse_int(ymd[2]);
- }
-
- void ParseGPSTime(String time) throws ParseException {
- String[] hms = time.split(":");
- if (hms.length != 3)
- throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0);
- hour = AltosParse.parse_int(hms[0]);
- minute = AltosParse.parse_int(hms[1]);
- second = AltosParse.parse_int(hms[2]);
- }
-
- void ClearGPSTime() {
- year = month = day = 0;
- hour = minute = second = 0;
- }
-
- public AltosGPS(String[] words, int i, int version) throws ParseException {
- AltosParse.word(words[i++], "GPS");
- nsat = AltosParse.parse_int(words[i++]);
- AltosParse.word(words[i++], "sat");
-
- connected = false;
- locked = false;
- lat = lon = 0;
- alt = 0;
- ClearGPSTime();
- if ((words[i]).equals("unlocked")) {
- connected = true;
- i++;
- } else if ((words[i]).equals("not-connected")) {
- i++;
- } else if (words.length >= 40) {
- locked = true;
- connected = true;
-
- if (version > 1)
- ParseGPSDate(words[i++]);
- else
- year = month = day = 0;
- ParseGPSTime(words[i++]);
- lat = AltosParse.parse_coord(words[i++]);
- lon = AltosParse.parse_coord(words[i++]);
- alt = AltosParse.parse_int(words[i++]);
- if (version > 1 || (i < words.length && !words[i].equals("SAT"))) {
- ground_speed = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(H)"));
- course = AltosParse.parse_int(words[i++]);
- climb_rate = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "m/s(V)"));
- hdop = AltosParse.parse_double(AltosParse.strip_suffix(words[i++], "(hdop)"));
- h_error = AltosParse.parse_int(words[i++]);
- v_error = AltosParse.parse_int(words[i++]);
- }
- } else {
- i++;
- }
- if (i < words.length) {
- AltosParse.word(words[i++], "SAT");
- int tracking_channels = 0;
- if (words[i].equals("not-connected"))
- tracking_channels = 0;
- else
- tracking_channels = AltosParse.parse_int(words[i]);
- i++;
- cc_gps_sat = new AltosGPS.AltosGPSSat[tracking_channels];
- for (int chan = 0; chan < tracking_channels; chan++) {
- cc_gps_sat[chan] = new AltosGPS.AltosGPSSat();
- cc_gps_sat[chan].svid = AltosParse.parse_int(words[i++]);
- /* Older versions included SiRF status bits */
- if (version < 2)
- i++;
- cc_gps_sat[chan].c_n0 = AltosParse.parse_int(words[i++]);
- }
- } else
- cc_gps_sat = new AltosGPS.AltosGPSSat[0];
- }
-
- public void set_latitude(int in_lat) {
- lat = in_lat / 10.0e7;
- }
-
- public void set_longitude(int in_lon) {
- lon = in_lon / 10.0e7;
- }
-
- public void set_time(int hour, int minute, int second) {
- hour = hour;
- minute = minute;
- second = second;
- }
-
- public void set_date(int year, int month, int day) {
- year = year;
- month = month;
- day = day;
- }
-
- public void set_flags(int flags) {
- flags = flags;
- }
-
- public void set_altitude(int altitude) {
- altitude = altitude;
- }
-
- public void add_sat(int svid, int c_n0) {
- if (cc_gps_sat == null) {
- cc_gps_sat = new AltosGPS.AltosGPSSat[1];
- } else {
- AltosGPSSat[] new_gps_sat = new AltosGPS.AltosGPSSat[cc_gps_sat.length + 1];
- for (int i = 0; i < cc_gps_sat.length; i++)
- new_gps_sat[i] = cc_gps_sat[i];
- cc_gps_sat = new_gps_sat;
- }
- AltosGPS.AltosGPSSat sat = new AltosGPS.AltosGPSSat();
- sat.svid = svid;
- sat.c_n0 = c_n0;
- cc_gps_sat[cc_gps_sat.length - 1] = sat;
- }
-
- public AltosGPS() {
- ClearGPSTime();
- cc_gps_sat = null;
- }
-
- public AltosGPS(AltosGPS old) {
- nsat = old.nsat;
- locked = old.locked;
- connected = old.connected;
- date_valid = old.date_valid;
- lat = old.lat; /* degrees (+N -S) */
- lon = old.lon; /* degrees (+E -W) */
- alt = old.alt; /* m */
- year = old.year;
- month = old.month;
- day = old.day;
- hour = old.hour;
- minute = old.minute;
- second = old.second;
-
- gps_extended = old.gps_extended; /* has extra data */
- ground_speed = old.ground_speed; /* m/s */
- course = old.course; /* degrees */
- climb_rate = old.climb_rate; /* m/s */
- hdop = old.hdop; /* unitless? */
- h_error = old.h_error; /* m */
- v_error = old.v_error; /* m */
-
- if (old.cc_gps_sat != null) {
- cc_gps_sat = new AltosGPSSat[old.cc_gps_sat.length];
- for (int i = 0; i < old.cc_gps_sat.length; i++) {
- cc_gps_sat[i] = new AltosGPSSat();
- cc_gps_sat[i].svid = old.cc_gps_sat[i].svid;
- cc_gps_sat[i].c_n0 = old.cc_gps_sat[i].c_n0;
- }
- }
- }
-}
+++ /dev/null
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
-
-package altosui;
-
-import java.io.*;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.ChartUtilities;
-
-abstract class AltosGraph {
- public String filename;
- public abstract void addData(AltosDataPoint d);
- public abstract JFreeChart createChart();
- public void toPNG() throws java.io.IOException { toPNG(300, 500); }
- public void toPNG(int width, int height)
- throws java.io.IOException
- {
- File pngout = new File(filename);
- JFreeChart chart = createChart();
- ChartUtilities.saveChartAsPNG(pngout, chart, width, height);
- System.out.println("Created " + filename);
- }
-}
+++ /dev/null
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
-
-package altosui;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import org.jfree.chart.ChartUtilities;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.AxisLocation;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.labels.StandardXYToolTipGenerator;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.plot.ValueMarker;
-import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.data.xy.XYSeries;
-import org.jfree.data.xy.XYSeriesCollection;
-import org.jfree.ui.RectangleAnchor;
-import org.jfree.ui.TextAnchor;
-
-class AltosGraphTime extends AltosGraph {
- static interface Element {
- void attachGraph(AltosGraphTime g);
- void gotTimeData(double time, AltosDataPoint d);
- void addToPlot(AltosGraphTime g, XYPlot plot);
- }
-
- static class TimeAxis implements Element {
- private int axis;
- private Color color;
- private String label;
- private AxisLocation locn;
- private double min_y = Double.NaN;
-
- public TimeAxis(int axis, String label, Color color, AxisLocation locn)
- {
- this.axis = axis;
- this.color = color;
- this.label = label;
- this.locn = locn;
- }
-
- public void setLowerBound(double min_y) {
- this.min_y = min_y;
- }
-
- public void attachGraph(AltosGraphTime g) { return; }
- public void gotTimeData(double time, AltosDataPoint d) { return; }
-
- public void addToPlot(AltosGraphTime g, XYPlot plot) {
- NumberAxis numAxis = new NumberAxis(label);
- if (!Double.isNaN(min_y))
- numAxis.setLowerBound(min_y);
- plot.setRangeAxis(axis, numAxis);
- plot.setRangeAxisLocation(axis, locn);
- numAxis.setLabelPaint(color);
- numAxis.setTickLabelPaint(color);
- numAxis.setAutoRangeIncludesZero(false);
- }
- }
-
- abstract static class TimeSeries implements Element {
- protected XYSeries series;
- private String axisName;
- private Color color;
-
- public TimeSeries(String axisName, String label, Color color) {
- this.series = new XYSeries(label);
- this.axisName = axisName;
- this.color = color;
- }
-
- public void attachGraph(AltosGraphTime g) {
- g.setAxis(this, axisName, color);
- }
- abstract public void gotTimeData(double time, AltosDataPoint d);
-
- public void addToPlot(AltosGraphTime g, XYPlot plot) {
- XYSeriesCollection dataset = new XYSeriesCollection();
- dataset.addSeries(this.series);
-
- XYItemRenderer renderer = new StandardXYItemRenderer();
- renderer.setSeriesPaint(0, color);
-
- int dataNum = g.getDataNum(this);
- int axisNum = g.getAxisNum(this);
-
- plot.setDataset(dataNum, dataset);
- plot.mapDatasetToRangeAxis(dataNum, axisNum);
- plot.setRenderer(dataNum, renderer);
- }
- }
-
- static class StateMarker implements Element {
- private double val = Double.NaN;
- private String name;
- private int state;
-
- StateMarker(int state, String name) {
- this.state = state;
- this.name = name;
- }
-
- public void attachGraph(AltosGraphTime g) { return; }
- public void gotTimeData(double time, AltosDataPoint d) {
- if (Double.isNaN(val) || time < val) {
- if (d.state() == state) {
- val = time;
- }
- }
- }
-
- public void addToPlot(AltosGraphTime g, XYPlot plot) {
- if (Double.isNaN(val))
- return;
-
- ValueMarker m = new ValueMarker(val);
- m.setLabel(name);
- m.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
- m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
- plot.addDomainMarker(m);
- }
- }
-
- private String callsign = null;
- private Integer serial = null;
- private Integer flight = null;
-
- private String title;
- private ArrayList<Element> elements;
- private HashMap<String,Integer> axes;
- private HashMap<Element,Integer> datasets;
- private ArrayList<Integer> datasetAxis;
-
- public AltosGraphTime(String title) {
- this.filename = title.toLowerCase().replaceAll("[^a-z0-9]","_")+".png";
- this.title = title;
- this.elements = new ArrayList<Element>();
- this.axes = new HashMap<String,Integer>();
- this.datasets = new HashMap<Element,Integer>();
- this.datasetAxis = new ArrayList<Integer>();
- }
-
- public AltosGraphTime addElement(Element e) {
- e.attachGraph(this);
- elements.add(e);
- return this;
- }
-
- public void setAxis(Element ds, String axisName, Color color) {
- Integer axisNum = axes.get(axisName);
- int dsNum = datasetAxis.size();
- if (axisNum == null) {
- axisNum = newAxis(axisName, color);
- }
- datasets.put(ds, dsNum);
- datasetAxis.add(axisNum);
- }
-
- public int getAxisNum(Element ds) {
- return datasetAxis.get( datasets.get(ds) ).intValue();
- }
- public int getDataNum(Element ds) {
- return datasets.get(ds).intValue();
- }
-
- private Integer newAxis(String name, Color color) {
- int cnt = axes.size();
- AxisLocation locn = AxisLocation.BOTTOM_OR_LEFT;
- if (cnt > 0) {
- locn = AxisLocation.TOP_OR_RIGHT;
- }
- Integer res = new Integer(cnt);
- axes.put(name, res);
- this.addElement(new TimeAxis(cnt, name, color, locn));
- return res;
- }
-
- public void addData(AltosDataPoint d) {
- double time = d.time();
- for (Element e : elements) {
- e.gotTimeData(time, d);
- }
- if (callsign == null) callsign = d.callsign();
- if (serial == null) serial = new Integer(d.serial());
- if (flight == null) flight = new Integer(d.flight());
- }
-
- public JFreeChart createChart() {
- NumberAxis xAxis = new NumberAxis("Time (s)");
- xAxis.setAutoRangeIncludesZero(false);
- XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
- XYPlot plot = new XYPlot();
- plot.setDomainAxis(xAxis);
- plot.setRenderer(renderer);
- plot.setOrientation(PlotOrientation.VERTICAL);
-
- if (serial != null && flight != null) {
- title = serial + "/" + flight + ": " + title;
- }
- if (callsign != null) {
- title = callsign + " - " + title;
- }
-
- renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
- JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
- plot, true);
- ChartUtilities.applyCurrentTheme(chart);
-
- plot.setDomainPannable(true);
- plot.setRangePannable(true);
-
- for (Element e : elements) {
- e.addToPlot(this, plot);
- }
-
- return chart;
- }
-
- public void toPNG() throws java.io.IOException {
- if (axes.size() > 1) {
- toPNG(800, 500);
- } else {
- toPNG(300, 500);
- }
- }
-}
+++ /dev/null
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
-
-package altosui;
-
-import java.io.*;
-import java.util.ArrayList;
-
-import javax.swing.JFrame;
-import java.awt.Color;
-
-import org.jfree.chart.ChartPanel;
-import org.jfree.chart.ChartUtilities;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.AxisLocation;
-import org.jfree.ui.ApplicationFrame;
-import org.jfree.ui.RefineryUtilities;
-
-public class AltosGraphUI extends JFrame
-{
- static final private Color red = new Color(194,31,31);
- static final private Color green = new Color(31,194,31);
- static final private Color blue = new Color(31,31,194);
- static final private Color black = new Color(31,31,31);
-
- static private class OverallGraphs {
- AltosGraphTime.Element height =
- new AltosGraphTime.TimeSeries("Height (m)", "Height (AGL)", red) {
- public void gotTimeData(double time, AltosDataPoint d) {
- series.add(time, d.height());
- }
- };
-
- AltosGraphTime.Element speed =
- new AltosGraphTime.TimeSeries("Speed (m/s)", "Vertical Speed", green) {
- public void gotTimeData(double time, AltosDataPoint d) {
- if (d.state() < Altos.ao_flight_drogue) {
- series.add(time, d.accel_speed());
- } else {
- series.add(time, d.baro_speed());
- }
- }
- };
-
- AltosGraphTime.Element acceleration =
- new AltosGraphTime.TimeSeries("Acceleration (m/s\u00B2)",
- "Axial Acceleration", blue)
- {
- public void gotTimeData(double time, AltosDataPoint d) {
- series.add(time, d.acceleration());
- }
- };
-
- AltosGraphTime.Element temperature =
- new AltosGraphTime.TimeSeries("Temperature (\u00B0C)",
- "Board temperature", red)
- {
- public void gotTimeData(double time, AltosDataPoint d) {
- series.add(time, d.temperature());
- }
- };
-
- AltosGraphTime.Element drogue_voltage =
- new AltosGraphTime.TimeSeries("Voltage (V)", "Drogue Continuity", blue)
- {
- public void gotTimeData(double time, AltosDataPoint d) {
- series.add(time, d.drogue_voltage());
- }
- };
-
- AltosGraphTime.Element main_voltage =
- new AltosGraphTime.TimeSeries("Voltage (V)", "Main Continuity", green)
- {
- public void gotTimeData(double time, AltosDataPoint d) {
- series.add(time, d.main_voltage());
- }
- };
-
- AltosGraphTime.Element e_pad = new AltosGraphTime.StateMarker(Altos.ao_flight_pad, "Pad");
- AltosGraphTime.Element e_boost = new AltosGraphTime.StateMarker(Altos.ao_flight_boost, "Boost");
- AltosGraphTime.Element e_fast = new AltosGraphTime.StateMarker(Altos.ao_flight_fast, "Fast");
- AltosGraphTime.Element e_coast = new AltosGraphTime.StateMarker(Altos.ao_flight_coast, "Coast");
- AltosGraphTime.Element e_drogue = new AltosGraphTime.StateMarker(Altos.ao_flight_drogue, "Drogue");
- AltosGraphTime.Element e_main = new AltosGraphTime.StateMarker(Altos.ao_flight_main, "Main");
- AltosGraphTime.Element e_landed = new AltosGraphTime.StateMarker(Altos.ao_flight_landed, "Landed");
-
- protected AltosGraphTime myAltosGraphTime(String suffix) {
- return (new AltosGraphTime("Overall " + suffix))
- .addElement(e_boost)
- .addElement(e_drogue)
- .addElement(e_main)
- .addElement(e_landed);
- }
-
- public ArrayList<AltosGraph> graphs() {
- ArrayList<AltosGraph> graphs = new ArrayList<AltosGraph>();
-
- graphs.add( myAltosGraphTime("Summary")
- .addElement(height)
- .addElement(speed)
- .addElement(acceleration) );
-
- graphs.add( myAltosGraphTime("Altitude")
- .addElement(height) );
-
- graphs.add( myAltosGraphTime("Speed")
- .addElement(speed) );
-
- graphs.add( myAltosGraphTime("Acceleration")
- .addElement(acceleration) );
-
- graphs.add( myAltosGraphTime("Temperature")
- .addElement(temperature) );
-
- graphs.add( myAltosGraphTime("Continuity")
- .addElement(drogue_voltage)
- .addElement(main_voltage) );
-
- return graphs;
- }
- }
-
- static private class AscentGraphs extends OverallGraphs {
- protected AltosGraphTime myAltosGraphTime(String suffix) {
- return (new AltosGraphTime("Ascent " + suffix) {
- public void addData(AltosDataPoint d) {
- int state = d.state();
- if (Altos.ao_flight_boost <= state && state <= Altos.ao_flight_coast) {
- super.addData(d);
- }
- }
- }).addElement(e_boost)
- .addElement(e_fast)
- .addElement(e_coast);
- }
- }
-
- static private class DescentGraphs extends OverallGraphs {
- protected AltosGraphTime myAltosGraphTime(String suffix) {
- return (new AltosGraphTime("Descent " + suffix) {
- public void addData(AltosDataPoint d) {
- int state = d.state();
- if (Altos.ao_flight_drogue <= state && state <= Altos.ao_flight_main) {
- super.addData(d);
- }
- }
- }).addElement(e_drogue)
- .addElement(e_main);
- // ((XYGraph)graph[8]).ymin = new Double(-50);
- }
- }
-
- public AltosGraphUI(AltosRecordIterable records) {
- super("Altos Graph");
-
- Iterable<AltosDataPoint> reader = new AltosDataPointReader (records);
- if (reader == null)
- return;
-
- init(reader, 0);
- }
-
- public AltosGraphUI(Iterable<AltosDataPoint> data, int which)
- {
- super("Altos Graph");
- init(data, which);
- }
-
- private void init(Iterable<AltosDataPoint> data, int which) {
- AltosGraph graph = createGraph(data, which);
-
- JFreeChart chart = graph.createChart();
- ChartPanel chartPanel = new ChartPanel(chart);
- chartPanel.setMouseWheelEnabled(true);
- chartPanel.setPreferredSize(new java.awt.Dimension(800, 500));
- setContentPane(chartPanel);
-
- pack();
-
- RefineryUtilities.centerFrameOnScreen(this);
-
- setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- setVisible(true);
- }
-
- private static AltosGraph createGraph(Iterable<AltosDataPoint> data,
- int which)
- {
- return createGraphsWhich(data, which).get(0);
- }
-
- private static ArrayList<AltosGraph> createGraphs(
- Iterable<AltosDataPoint> data)
- {
- return createGraphsWhich(data, -1);
- }
-
- private static ArrayList<AltosGraph> createGraphsWhich(
- Iterable<AltosDataPoint> data, int which)
- {
- ArrayList<AltosGraph> graph = new ArrayList<AltosGraph>();
- graph.addAll((new OverallGraphs()).graphs());
- graph.addAll((new AscentGraphs()).graphs());
- graph.addAll((new DescentGraphs()).graphs());
-
- if (which > 0) {
- if (which >= graph.size()) {
- which = 0;
- }
- AltosGraph g = graph.get(which);
- graph = new ArrayList<AltosGraph>();
- graph.add(g);
- }
-
- for (AltosDataPoint dp : data) {
- for (AltosGraph g : graph) {
- g.addData(dp);
- }
- }
-
- return graph;
- }
-}
-
-/* gnuplot bits...
- *
-300x400
-
---------------------------------------------------------
-TOO HARD! :)
-
-"ascent-gps-accuracy.png" "Vertical error margin to apogee - GPS v Baro (m)"
- 5:($7 < 6 ? $24-$11 : 1/0)
-"descent-gps-accuracy.png" "Vertical error margin during descent - GPS v Baro (m)"
- 5:($7 < 6 ? 1/0 : $24-$11)
-
-set output "overall-gps-accuracy.png"
-set ylabel "distance above sea level (m)"
-plot "telemetry.csv" using 5:11 with lines ti "baro altitude" axis x1y1, \
- "telemetry.csv" using 5:24 with lines ti "gps altitude" axis x1y1
-
-set term png tiny size 700,700 enhanced
-set xlabel "m"
-set ylabel "m"
-set polar
-set grid polar
-set rrange[*:*]
-set angles degrees
-
-set output "overall-gps-path.png"
-#:30 with yerrorlines
-plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0) with lines ti "pad", \
- "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0) with lines ti "boost", \
- "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0) with lines ti "fast", \
- "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0) with lines ti "coast", \
- "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
- "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
- "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
-
-set output "ascent-gps-path.png"
-plot "telemetry.csv" using (90-$33):($7 == 2 ? $31 : 1/0):30 with lines ti "pad", \
- "telemetry.csv" using (90-$33):($7 == 3 ? $31 : 1/0):20 with lines ti "boost", \
- "telemetry.csv" using (90-$33):($7 == 4 ? $31 : 1/0):10 with lines ti "fast", \
- "telemetry.csv" using (90-$33):($7 == 5 ? $31 : 1/0):5 with lines ti "coast"
-
-set output "descent-gps-path.png"
-plot "telemetry.csv" using (90-$33):($7 == 6 ? $31 : 1/0) with lines ti "drogue", \
- "telemetry.csv" using (90-$33):($7 == 7 ? $31 : 1/0) with lines ti "main", \
- "telemetry.csv" using (90-$33):($7 == 8 ? $31 : 1/0) with lines ti "landed"
-
- */
-
-
+++ /dev/null
-/*
- * 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.Math;
-
-public class AltosGreatCircle {
- double distance;
- double bearing;
-
- double sqr(double a) { return a * a; }
-
- static final double rad = Math.PI / 180;
- static final double earth_radius = 6371.2 * 1000; /* in meters */
-
- static int BEARING_LONG = 0;
- static int BEARING_SHORT = 1;
- static int BEARING_VOICE = 2;
- String bearing_words(int length) {
- String [][] bearing_string = {
- {
- "North", "North North East", "North East", "East North East",
- "East", "East South East", "South East", "South South East",
- "South", "South South West", "South West", "West South West",
- "West", "West North West", "North West", "North North West"
- }, {
- "N", "NNE", "NE", "ENE",
- "E", "ESE", "SE", "SSE",
- "S", "SSW", "SW", "WSW",
- "W", "WNW", "NW", "NNW"
- }, {
- "north", "nor nor east", "north east", "east nor east",
- "east", "east sow east", "south east", "sow sow east",
- "south", "sow sow west", "south west", "west sow west",
- "west", "west nor west", "north west", "nor nor west "
- }
- };
- return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16];
- }
-
- public AltosGreatCircle (double start_lat, double start_lon,
- double end_lat, double end_lon)
- {
- double lat1 = rad * start_lat;
- double lon1 = rad * -start_lon;
- double lat2 = rad * end_lat;
- double lon2 = rad * -end_lon;
-
- double d_lon = lon2 - lon1;
-
- /* From http://en.wikipedia.org/wiki/Great-circle_distance */
- double vdn = Math.sqrt(sqr(Math.cos(lat2) * Math.sin(d_lon)) +
- sqr(Math.cos(lat1) * Math.sin(lat2) -
- Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon)));
- double vdd = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(d_lon);
- double d = Math.atan2(vdn,vdd);
- double course;
-
- if (Math.cos(lat1) < 1e-20) {
- if (lat1 > 0)
- course = Math.PI;
- else
- course = -Math.PI;
- } else {
- if (d < 1e-10)
- course = 0;
- else
- course = Math.acos((Math.sin(lat2)-Math.sin(lat1)*Math.cos(d)) /
- (Math.sin(d)*Math.cos(lat1)));
- if (Math.sin(lon2-lon1) > 0)
- course = 2 * Math.PI-course;
- }
- distance = d * earth_radius;
- bearing = course * 180/Math.PI;
- }
-
- public AltosGreatCircle(AltosGPS start, AltosGPS end) {
- this(start.lat, start.lon, end.lat, end.lon);
- }
-
- public AltosGreatCircle() {
- distance = 0;
- bearing = 0;
- }
-}
+++ /dev/null
-/*
- * 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.concurrent.LinkedBlockingQueue;
-import java.util.LinkedList;
-import java.util.Iterator;
-import java.util.Arrays;
-
-class HexFileInputStream extends PushbackInputStream {
- public int line;
-
- public HexFileInputStream(FileInputStream o) {
- super(new BufferedInputStream(o));
- line = 1;
- }
-
- public int read() throws IOException {
- int c = super.read();
- if (c == '\n')
- line++;
- return c;
- }
-
- public void unread(int c) throws IOException {
- if (c == '\n')
- line--;
- if (c != -1)
- super.unread(c);
- }
-}
-
-class HexRecord implements Comparable {
- public int address;
- public int type;
- public byte checksum;
- public byte[] data;
-
- static final int NORMAL = 0;
- static final int EOF = 1;
- static final int EXTENDED_ADDRESS = 2;
-
- enum read_state {
- marker,
- length,
- address,
- type,
- data,
- checksum,
- newline,
- white,
- done,
- }
-
- boolean ishex(int c) {
- if ('0' <= c && c <= '9')
- return true;
- if ('a' <= c && c <= 'f')
- return true;
- if ('A' <= c && c <= 'F')
- return true;
- return false;
- }
-
- boolean isspace(int c) {
- switch (c) {
- case ' ':
- case '\t':
- return true;
- }
- return false;
- }
-
- int fromhex(int c) {
- if ('0' <= c && c <= '9')
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - 'a' + 10;
- if ('A' <= c && c <= 'F')
- return c - 'A' + 10;
- return -1;
- }
-
- public byte checksum() {
- byte got = 0;
-
- got += data.length;
- got += (address >> 8) & 0xff;
- got += (address ) & 0xff;
- got += type;
- for (int i = 0; i < data.length; i++)
- got += data[i];
- return (byte) (-got);
- }
-
- public int compareTo(Object other) {
- HexRecord o = (HexRecord) other;
- return address - o.address;
- }
-
- public String toString() {
- return String.format("%04x: %02x (%d)", address, type, data.length);
- }
-
- public HexRecord(HexFileInputStream input) throws IOException {
- read_state state = read_state.marker;
- int nhexbytes = 0;
- int hex = 0;
- int ndata = 0;
- byte got_checksum;
-
- while (state != read_state.done) {
- int c = input.read();
- if (c < 0 && state != read_state.white)
- throw new IOException(String.format("%d: Unexpected EOF", input.line));
- if (c == ' ')
- continue;
- switch (state) {
- case marker:
- if (c != ':')
- throw new IOException("Missing ':'");
- state = read_state.length;
- nhexbytes = 2;
- hex = 0;
- break;
- case length:
- case address:
- case type:
- case data:
- case checksum:
- if(!ishex(c))
- throw new IOException(String.format("Non-hex char '%c'", c));
- hex = hex << 4 | fromhex(c);
- --nhexbytes;
- if (nhexbytes != 0)
- break;
-
- switch (state) {
- case length:
- data = new byte[hex];
- state = read_state.address;
- nhexbytes = 4;
- break;
- case address:
- address = hex;
- state = read_state.type;
- nhexbytes = 2;
- break;
- case type:
- type = hex;
- if (data.length > 0)
- state = read_state.data;
- else
- state = read_state.checksum;
- nhexbytes = 2;
- ndata = 0;
- break;
- case data:
- data[ndata] = (byte) hex;
- ndata++;
- nhexbytes = 2;
- if (ndata == data.length)
- state = read_state.checksum;
- break;
- case checksum:
- checksum = (byte) hex;
- state = read_state.newline;
- break;
- default:
- break;
- }
- hex = 0;
- break;
- case newline:
- if (c != '\n' && c != '\r')
- throw new IOException("Missing newline");
- state = read_state.white;
- break;
- case white:
- if (!isspace(c)) {
- input.unread(c);
- state = read_state.done;
- }
- break;
- case done:
- break;
- }
- }
- got_checksum = checksum();
- if (got_checksum != checksum)
- throw new IOException(String.format("Invalid checksum (read 0x%02x computed 0x%02x)\n",
- checksum, got_checksum));
- }
-}
-
-public class AltosHexfile {
- public int address;
- public byte[] data;
-
- public byte get_byte(int a) {
- return data[a - address];
- }
-
- public AltosHexfile(FileInputStream file) throws IOException {
- HexFileInputStream input = new HexFileInputStream(file);
- LinkedList<HexRecord> record_list = new LinkedList<HexRecord>();
- boolean done = false;
-
- while (!done) {
- HexRecord record = new HexRecord(input);
-
- if (record.type == HexRecord.EOF)
- done = true;
- else
- record_list.add(record);
- }
- HexRecord[] records = record_list.toArray(new HexRecord[0]);
- Arrays.sort(records);
- if (records.length > 0) {
- int base = records[0].address;
- int bound = records[records.length-1].address +
- records[records.length-1].data.length;
-
- data = new byte[bound - base];
- address = base;
- Arrays.fill(data, (byte) 0xff);
-
- /* Paint the records into the new array */
- for (int i = 0; i < records.length; i++) {
- for (int j = 0; j < records[i].data.length; j++)
- data[records[i].address - base + j] = records[i].data[j];
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.io.*;
-import java.util.concurrent.*;
-
-public class AltosIgnite {
- AltosDevice device;
- AltosSerial serial;
- boolean remote;
- boolean serial_started;
- final static int None = 0;
- final static int Apogee = 1;
- final static int Main = 2;
-
- final static int Unknown = 0;
- final static int Ready = 1;
- final static int Active = 2;
- final static int Open = 3;
-
- private void start_serial() throws InterruptedException {
- serial_started = true;
- if (remote) {
- serial.set_radio();
- serial.printf("p\nE 0\n");
- serial.flush_input();
- }
- }
-
- private void stop_serial() throws InterruptedException {
- if (!serial_started)
- return;
- serial_started = false;
- if (serial == null)
- return;
- if (remote) {
- serial.printf("~");
- serial.flush_output();
- }
- }
-
- class string_ref {
- String value;
-
- public String get() {
- return value;
- }
- public void set(String i) {
- value = i;
- }
- public string_ref() {
- value = null;
- }
- }
-
- private boolean get_string(String line, String label, string_ref s) {
- if (line.startsWith(label)) {
- String quoted = line.substring(label.length()).trim();
-
- if (quoted.startsWith("\""))
- quoted = quoted.substring(1);
- if (quoted.endsWith("\""))
- quoted = quoted.substring(0,quoted.length()-1);
- s.set(quoted);
- return true;
- } else {
- return false;
- }
- }
-
- private int status(String status_name) {
- if (status_name.equals("unknown"))
- return Unknown;
- if (status_name.equals("ready"))
- return Ready;
- if (status_name.equals("active"))
- return Active;
- if (status_name.equals("open"))
- return Open;
- return Unknown;
- }
-
- public int status(int igniter) throws InterruptedException, TimeoutException {
- int status = Unknown;
- if (serial == null)
- return status;
- string_ref status_name = new string_ref();
- start_serial();
- serial.printf("t\n");
- for (;;) {
- String line = serial.get_reply(5000);
- if (line == null)
- throw new TimeoutException();
- if (get_string(line, "Igniter: drogue Status: ", status_name))
- if (igniter == Apogee)
- status = status(status_name.get());
- if (get_string(line, "Igniter: main Status: ", status_name)) {
- if (igniter == Main)
- status = status(status_name.get());
- break;
- }
- }
- stop_serial();
- return status;
- }
-
- public String status_string(int status) {
- switch (status) {
- case Unknown: return "Unknown";
- case Ready: return "Ready";
- case Active: return "Active";
- case Open: return "Open";
- default: return "Unknown";
- }
- }
-
- public void fire(int igniter) {
- if (serial == null)
- return;
- try {
- start_serial();
- switch (igniter) {
- case Main:
- serial.printf("i DoIt main\n");
- break;
- case Apogee:
- serial.printf("i DoIt drogue\n");
- break;
- }
- } catch (InterruptedException ie) {
- } finally {
- try {
- stop_serial();
- } catch (InterruptedException ie) {
- }
- }
- }
-
- public void close() {
- try {
- stop_serial();
- } catch (InterruptedException ie) {
- }
- serial.close();
- serial = null;
- }
-
- public AltosIgnite(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
-
- device = in_device;
- serial = new AltosSerial(device);
- remote = false;
-
- if (!device.matchProduct(AltosDevice.product_telemetrum))
- remote = true;
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import javax.swing.event.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.*;
-
-public class AltosIgniteUI
- extends JDialog
- implements ActionListener
-{
- AltosDevice device;
- AltosIgnite ignite;
- JFrame owner;
- JLabel label;
- JRadioButton apogee;
- JLabel apogee_status_label;
- JRadioButton main;
- JLabel main_status_label;
- JToggleButton arm;
- JButton fire;
- javax.swing.Timer timer;
-
- int apogee_status;
- int main_status;
-
- final static int timeout = 1 * 1000;
-
- int time_remaining;
- boolean timer_running;
-
- void set_arm_text() {
- if (arm.isSelected())
- arm.setText(String.format("%d", time_remaining));
- else
- arm.setText("Arm");
- }
-
- void start_timer() {
- time_remaining = 10;
- set_arm_text();
- timer_running = true;
- }
-
- void stop_timer() {
- time_remaining = 0;
- arm.setSelected(false);
- arm.setEnabled(false);
- fire.setEnabled(false);
- timer_running = false;
- set_arm_text();
- }
-
- void cancel () {
- apogee.setSelected(false);
- main.setSelected(false);
- fire.setEnabled(false);
- stop_timer();
- }
-
- void get_ignite_status() throws InterruptedException, TimeoutException {
- apogee_status = ignite.status(AltosIgnite.Apogee);
- main_status = ignite.status(AltosIgnite.Main);
- }
-
- void set_ignite_status() throws InterruptedException, TimeoutException {
- get_ignite_status();
- apogee_status_label.setText(String.format("\"%s\"", ignite.status_string(apogee_status)));
- main_status_label.setText(String.format("\"%s\"", ignite.status_string(main_status)));
- }
-
- void close() {
- timer.stop();
- setVisible(false);
- ignite.close();
- }
-
- void abort() {
- close();
- JOptionPane.showMessageDialog(owner,
- String.format("Connection to \"%s\" failed",
- device.toShortString()),
- "Connection Failed",
- JOptionPane.ERROR_MESSAGE);
- }
-
- void tick_timer() {
- if (timer_running) {
- --time_remaining;
- if (time_remaining <= 0)
- cancel();
- else
- set_arm_text();
- }
- try {
- set_ignite_status();
- } catch (InterruptedException ie) {
- abort();
- } catch (TimeoutException te) {
- abort();
- }
- }
-
- void fire() {
- if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
- int igniter = AltosIgnite.None;
- if (apogee.isSelected() && !main.isSelected())
- igniter = AltosIgnite.Apogee;
- else if (main.isSelected() && !apogee.isSelected())
- igniter = AltosIgnite.Main;
- ignite.fire(igniter);
- cancel();
- }
- }
-
- public void actionPerformed(ActionEvent e) {
- String cmd = e.getActionCommand();
- if (cmd.equals("apogee") || cmd.equals("main")) {
- stop_timer();
- }
-
- if (cmd.equals("apogee") && apogee.isSelected()) {
- main.setSelected(false);
- arm.setEnabled(true);
- }
- if (cmd.equals("main") && main.isSelected()) {
- apogee.setSelected(false);
- arm.setEnabled(true);
- }
-
- if (cmd.equals("arm")) {
- if (arm.isSelected()) {
- fire.setEnabled(true);
- start_timer();
- } else
- cancel();
- }
- if (cmd.equals("fire"))
- fire();
- if (cmd.equals("tick"))
- tick_timer();
- if (cmd.equals("close")) {
- close();
- }
- }
-
- /* A window listener to catch closing events and tell the config code */
- class ConfigListener extends WindowAdapter {
- AltosIgniteUI ui;
-
- public ConfigListener(AltosIgniteUI this_ui) {
- ui = this_ui;
- }
-
- public void windowClosing(WindowEvent e) {
- ui.actionPerformed(new ActionEvent(e.getSource(),
- ActionEvent.ACTION_PERFORMED,
- "close"));
- }
- }
-
- private boolean open() {
- device = AltosDeviceDialog.show(owner, AltosDevice.product_any);
- if (device != null) {
- try {
- ignite = new AltosIgnite(device);
- return true;
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(owner,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
- "Cannot open target device",
- JOptionPane.ERROR_MESSAGE);
- } catch (AltosSerialInUseException si) {
- JOptionPane.showMessageDialog(owner,
- String.format("Device \"%s\" already in use",
- device.toShortString()),
- "Device in use",
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(owner,
- device.toShortString(),
- ee.getLocalizedMessage(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- return false;
- }
-
- public AltosIgniteUI(JFrame in_owner) {
-
- owner = in_owner;
- apogee_status = AltosIgnite.Unknown;
- main_status = AltosIgnite.Unknown;
-
- if (!open())
- return;
-
- Container pane = getContentPane();
- GridBagConstraints c = new GridBagConstraints();
- Insets i = new Insets(4,4,4,4);
-
- timer = new javax.swing.Timer(timeout, this);
- timer.setActionCommand("tick");
- timer_running = false;
- timer.restart();
-
- owner = in_owner;
-
- pane.setLayout(new GridBagLayout());
-
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.insets = i;
- c.weightx = 1;
- c.weighty = 1;
-
- c.gridx = 0;
- c.gridy = 0;
- c.gridwidth = 2;
- c.anchor = GridBagConstraints.CENTER;
- label = new JLabel ("Fire Igniter");
- pane.add(label, c);
-
- c.gridx = 0;
- c.gridy = 1;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- apogee = new JRadioButton ("Apogee");
- pane.add(apogee, c);
- apogee.addActionListener(this);
- apogee.setActionCommand("apogee");
-
- c.gridx = 1;
- c.gridy = 1;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- apogee_status_label = new JLabel();
- pane.add(apogee_status_label, c);
-
- c.gridx = 0;
- c.gridy = 2;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- main = new JRadioButton ("Main");
- pane.add(main, c);
- main.addActionListener(this);
- main.setActionCommand("main");
-
- c.gridx = 1;
- c.gridy = 2;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.WEST;
- main_status_label = new JLabel();
- pane.add(main_status_label, c);
-
- try {
- set_ignite_status();
- } catch (InterruptedException ie) {
- abort();
- return;
- } catch (TimeoutException te) {
- abort();
- return;
- }
-
- c.gridx = 0;
- c.gridy = 3;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.CENTER;
- arm = new JToggleButton ("Arm");
- pane.add(arm, c);
- arm.addActionListener(this);
- arm.setActionCommand("arm");
- arm.setEnabled(false);
-
- c.gridx = 1;
- c.gridy = 3;
- c.gridwidth = 1;
- c.anchor = GridBagConstraints.CENTER;
- fire = new JButton ("Fire");
- fire.setEnabled(false);
- pane.add(fire, c);
- fire.addActionListener(this);
- fire.setActionCommand("fire");
-
- pack();
- setLocationRelativeTo(owner);
- setVisible(true);
-
- addWindowListener(new ConfigListener(this));
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosInfoTable extends JTable {
- private AltosFlightInfoTableModel model;
-
- private Font infoLabelFont = new Font("SansSerif", Font.PLAIN, 14);
- private Font infoValueFont = new Font("Monospaced", Font.PLAIN, 14);
-
- static final int info_columns = 3;
- static final int info_rows = 17;
-
- int desired_row_height() {
- FontMetrics infoValueMetrics = getFontMetrics(infoValueFont);
- return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
- }
-
- public AltosInfoTable() {
- super(new AltosFlightInfoTableModel(info_rows, info_columns));
- model = (AltosFlightInfoTableModel) getModel();
- setFont(infoValueFont);
- setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
- setShowGrid(true);
- setRowHeight(desired_row_height());
- doLayout();
- }
-
- public Dimension getPreferredScrollableViewportSize() {
- return getPreferredSize();
- }
-
- void info_reset() {
- model.reset();
- }
-
- void info_add_row(int col, String name, String value) {
- model.addRow(col, name, value);
- }
-
- void info_add_row(int col, String name, String format, Object... parameters) {
- info_add_row (col, name, String.format(format, parameters));
- }
-
- void info_add_deg(int col, String name, double v, int pos, int neg) {
- int c = pos;
- if (v < 0) {
- c = neg;
- v = -v;
- }
- double deg = Math.floor(v);
- double min = (v - deg) * 60;
-
- info_add_row(col, name, String.format("%3.0f°%08.5f'", deg, min));
- }
-
- void info_finish() {
- model.finish();
- }
-
- public void clear() {
- model.clear();
- }
-
- public void show(AltosState state, int crc_errors) {
- if (state == null)
- return;
- info_reset();
- info_add_row(0, "Rocket state", "%s", state.data.state());
- info_add_row(0, "Callsign", "%s", state.data.callsign);
- info_add_row(0, "Rocket serial", "%6d", state.data.serial);
- info_add_row(0, "Rocket flight", "%6d", state.data.flight);
-
- info_add_row(0, "RSSI", "%6d dBm", state.data.rssi);
- info_add_row(0, "CRC Errors", "%6d", crc_errors);
- info_add_row(0, "Height", "%6.0f m", state.height);
- info_add_row(0, "Max height", "%6.0f m", state.max_height);
- info_add_row(0, "Acceleration", "%8.1f m/s²", state.acceleration);
- info_add_row(0, "Max acceleration", "%8.1f m/s²", state.max_acceleration);
- info_add_row(0, "Speed", "%8.1f m/s", state.ascent ? state.speed : state.baro_speed);
- info_add_row(0, "Max Speed", "%8.1f m/s", state.max_speed);
- info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
- info_add_row(0, "Battery", "%9.2f V", state.battery);
- info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense);
- info_add_row(0, "Main", "%9.2f V", state.main_sense);
- info_add_row(0, "Pad altitude", "%6.0f m", state.ground_altitude);
- if (state.gps == null) {
- info_add_row(1, "GPS", "not available");
- } else {
- if (state.gps_ready)
- info_add_row(1, "GPS state", "%s", "ready");
- else
- info_add_row(1, "GPS state", "wait (%d)",
- state.gps_waiting);
- if (state.data.gps.locked)
- info_add_row(1, "GPS", " locked");
- else if (state.data.gps.connected)
- info_add_row(1, "GPS", " unlocked");
- else
- info_add_row(1, "GPS", " missing");
- info_add_row(1, "Satellites", "%6d", state.data.gps.nsat);
- info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
- info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
- info_add_row(1, "GPS altitude", "%6d", state.gps.alt);
- info_add_row(1, "GPS height", "%6.0f", state.gps_height);
-
- /* The SkyTraq GPS doesn't report these values */
- if (false) {
- info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°",
- state.gps.ground_speed,
- state.gps.course);
- info_add_row(1, "GPS climb rate", "%8.1f m/s",
- state.gps.climb_rate);
- info_add_row(1, "GPS error", "%6d m(h)%3d m(v)",
- state.gps.h_error, state.gps.v_error);
- }
- info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop);
-
- if (state.npad > 0) {
- if (state.from_pad != null) {
- info_add_row(1, "Distance from pad", "%6d m",
- (int) (state.from_pad.distance + 0.5));
- info_add_row(1, "Direction from pad", "%6d°",
- (int) (state.from_pad.bearing + 0.5));
- info_add_row(1, "Elevation from pad", "%6d°",
- (int) (state.elevation + 0.5));
- info_add_row(1, "Range from pad", "%6d m",
- (int) (state.range + 0.5));
- } else {
- info_add_row(1, "Distance from pad", "unknown");
- info_add_row(1, "Direction from pad", "unknown");
- info_add_row(1, "Elevation from pad", "unknown");
- info_add_row(1, "Range from pad", "unknown");
- }
- info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
- info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
- info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
- }
- info_add_row(1, "GPS date", "%04d-%02d-%02d",
- state.gps.year,
- state.gps.month,
- state.gps.day);
- info_add_row(1, "GPS time", " %02d:%02d:%02d",
- state.gps.hour,
- state.gps.minute,
- state.gps.second);
- int nsat_vis = 0;
- int c;
-
- if (state.gps.cc_gps_sat == null)
- info_add_row(2, "Satellites Visible", "%4d", 0);
- else {
- info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length);
- for (c = 0; c < state.gps.cc_gps_sat.length; c++) {
- info_add_row(2, "Satellite id,C/N0",
- "%4d, %4d",
- state.gps.cc_gps_sat[c].svid,
- state.gps.cc_gps_sat[c].c_n0);
- }
- }
- }
- info_finish();
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.util.*;
-
-public class AltosKML implements AltosWriter {
-
- File name;
- PrintStream out;
- int state = -1;
- AltosRecord prev = null;
-
- static final String[] kml_state_colors = {
- "FF000000",
- "FF000000",
- "FF000000",
- "FF0000FF",
- "FF4080FF",
- "FF00FFFF",
- "FFFF0000",
- "FF00FF00",
- "FF000000",
- "FFFFFFFF"
- };
-
- static final String kml_header_start =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
- "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
- "<Document>\n" +
- " <name>AO Flight#%d S/N: %03d</name>\n" +
- " <description>\n";
- static final String kml_header_end =
- " </description>\n" +
- " <open>0</open>\n";
-
- static final String kml_style_start =
- " <Style id=\"ao-flightstate-%s\">\n" +
- " <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
- " <BalloonStyle>\n" +
- " <text>\n";
-
- static final String kml_style_end =
- " </text>\n" +
- " </BalloonStyle>\n" +
- " </Style>\n";
-
- static final String kml_placemark_start =
- " <Placemark>\n" +
- " <name>%s</name>\n" +
- " <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
- " <LineString>\n" +
- " <tessellate>1</tessellate>\n" +
- " <altitudeMode>absolute</altitudeMode>\n" +
- " <coordinates>\n";
-
- static final String kml_coord_fmt =
- " %12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
-
- static final String kml_placemark_end =
- " </coordinates>\n" +
- " </LineString>\n" +
- " </Placemark>\n";
-
- static final String kml_footer =
- "</Document>\n" +
- "</kml>\n";
-
- void start (AltosRecord record) {
- out.printf(kml_header_start, record.flight, record.serial);
- out.printf("Date: %04d-%02d-%02d\n",
- record.gps.year, record.gps.month, record.gps.day);
- out.printf("Time: %2d:%02d:%02d\n",
- record.gps.hour, record.gps.minute, record.gps.second);
- out.printf("%s", kml_header_end);
- }
-
- boolean started = false;
-
- void state_start(AltosRecord record) {
- String state_name = Altos.state_name(record.state);
- out.printf(kml_style_start, state_name, kml_state_colors[record.state]);
- out.printf("\tState: %s\n", state_name);
- out.printf("%s", kml_style_end);
- out.printf(kml_placemark_start, state_name, state_name);
- }
-
- void state_end(AltosRecord record) {
- out.printf("%s", kml_placemark_end);
- }
-
- void coord(AltosRecord record) {
- AltosGPS gps = record.gps;
- out.printf(kml_coord_fmt,
- gps.lon, gps.lat,
- record.filtered_altitude(), (double) gps.alt,
- record.time, gps.nsat);
- }
-
- void end() {
- out.printf("%s", kml_footer);
- }
-
- public void close() {
- if (prev != null) {
- state_end(prev);
- end();
- prev = null;
- }
- }
-
- public void write(AltosRecord record) {
- AltosGPS gps = record.gps;
-
- if (gps == null)
- return;
- if (!started) {
- start(record);
- started = true;
- }
- if (prev != null &&
- prev.gps.second == record.gps.second &&
- prev.gps.minute == record.gps.minute &&
- prev.gps.hour == record.gps.hour)
- return;
- if (record.state != state) {
- state = record.state;
- if (prev != null) {
- coord(record);
- state_end(prev);
- }
- state_start(record);
- }
- coord(record);
- prev = record;
- }
-
- public void write(AltosRecordIterable iterable) {
- for (AltosRecord record : iterable)
- write(record);
- }
-
- public AltosKML(File in_name) throws FileNotFoundException {
- name = in_name;
- out = new PrintStream(name);
- }
-
- public AltosKML(String in_string) throws FileNotFoundException {
- this(new File(in_string));
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosLanded extends JComponent implements AltosFlightDisplay {
- GridBagLayout layout;
- Font label_font;
- Font value_font;
-
- public class LandedValue {
- JLabel label;
- JTextField value;
- void show(AltosState state, int crc_errors) {}
-
- void reset() {
- value.setText("");
- }
-
- void show(String format, double v) {
- value.setText(String.format(format, v));
- }
-
- public LandedValue (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 0; c.gridy = y;
- c.insets = new Insets(10, 10, 10, 10);
- c.anchor = GridBagConstraints.WEST;
- c.weightx = 0;
- c.fill = GridBagConstraints.VERTICAL;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 1; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.weightx = 1;
- c.fill = GridBagConstraints.BOTH;
- layout.setConstraints(value, c);
- add(value);
- }
- }
-
- String pos(double p, String pos, String neg) {
- String h = pos;
- if (p < 0) {
- h = neg;
- p = -p;
- }
- int deg = (int) Math.floor(p);
- double min = (p - Math.floor(p)) * 60.0;
- return String.format("%s %4d° %9.6f", h, deg, min);
- }
-
- class Lat extends LandedValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- value.setText(pos(state.gps.lat,"N", "S"));
- else
- value.setText("???");
- }
- public Lat (GridBagLayout layout, int y) {
- super (layout, y, "Latitude");
- }
- }
-
- Lat lat;
-
- class Lon extends LandedValue {
- void show (AltosState state, int crc_errors) {
- if (state.gps != null)
- value.setText(pos(state.gps.lon,"E", "W"));
- else
- value.setText("???");
- }
- public Lon (GridBagLayout layout, int y) {
- super (layout, y, "Longitude");
- }
- }
-
- Lon lon;
-
- class Bearing extends LandedValue {
- void show (AltosState state, int crc_errors) {
- if (state.from_pad != null)
- show("%3.0f°", state.from_pad.bearing);
- else
- value.setText("???");
- }
- public Bearing (GridBagLayout layout, int y) {
- super (layout, y, "Bearing");
- }
- }
-
- Bearing bearing;
-
- class Distance extends LandedValue {
- void show (AltosState state, int crc_errors) {
- if (state.from_pad != null)
- show("%6.0f m", state.from_pad.distance);
- else
- value.setText("???");
- }
- public Distance (GridBagLayout layout, int y) {
- super (layout, y, "Distance");
- }
- }
-
- Distance distance;
-
- class Height extends LandedValue {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m", state.max_height);
- }
- public Height (GridBagLayout layout, int y) {
- super (layout, y, "Maximum Height");
- }
- }
-
- Height height;
-
- class Speed extends LandedValue {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m/s", state.max_speed);
- }
- public Speed (GridBagLayout layout, int y) {
- super (layout, y, "Maximum Speed");
- }
- }
-
- Speed speed;
-
- class Accel extends LandedValue {
- void show (AltosState state, int crc_errors) {
- show("%6.0f m/s²", state.max_acceleration);
- }
- public Accel (GridBagLayout layout, int y) {
- super (layout, y, "Maximum Acceleration");
- }
- }
-
- Accel accel;
-
- public void reset() {
- lat.reset();
- lon.reset();
- bearing.reset();
- distance.reset();
- height.reset();
- speed.reset();
- accel.reset();
- }
-
- public void show(AltosState state, int crc_errors) {
- bearing.show(state, crc_errors);
- distance.show(state, crc_errors);
- lat.show(state, crc_errors);
- lon.show(state, crc_errors);
- height.show(state, crc_errors);
- speed.show(state, crc_errors);
- accel.show(state, crc_errors);
- }
-
- public AltosLanded() {
- layout = new GridBagLayout();
-
- label_font = new Font("Dialog", Font.PLAIN, 22);
- value_font = new Font("Monospaced", Font.PLAIN, 22);
- setLayout(layout);
-
- /* Elements in descent display */
- bearing = new Bearing(layout, 0);
- distance = new Distance(layout, 1);
- lat = new Lat(layout, 2);
- lon = new Lon(layout, 3);
- height = new Height(layout, 4);
- speed = new Speed(layout, 5);
- accel = new Accel(layout, 6);
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosLed extends JLabel {
- ImageIcon on, off;
-
- ImageIcon create_icon(String path) {
- java.net.URL imgURL = AltosUI.class.getResource(path);
- if (imgURL != null)
- return new ImageIcon(imgURL);
- System.err.printf("Cannot find icon \"%s\"\n", path);
- return null;
- }
-
- public void set(boolean set) {
- if (set)
- setIcon(on);
- else
- setIcon(off);
- }
-
- public AltosLed(String on_path, String off_path) {
- on = create_icon(on_path);
- off = create_icon(off_path);
- setIcon(off);
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosLights extends JComponent {
-
- GridBagLayout gridbag;
-
- AltosLed red, green;
-
- ImageIcon create_icon(String path, String description) {
- java.net.URL imgURL = AltosUI.class.getResource(path);
- if (imgURL != null)
- return new ImageIcon(imgURL, description);
- System.err.printf("Cannot find icon \"%s\"\n", path);
- return null;
- }
-
- public void set (boolean on) {
- if (on) {
- red.set(false);
- green.set(true);
- } else {
- red.set(true);
- green.set(false);
- }
- }
-
- public AltosLights() {
- GridBagConstraints c;
- gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- c = new GridBagConstraints();
- red = new AltosLed("/redled.png", "/grayled.png");
- c.gridx = 0; c.gridy = 0;
- c.insets = new Insets (0, 5, 0, 5);
- gridbag.setConstraints(red, c);
- add(red);
- red.set(true);
- green = new AltosLed("/greenled.png", "/grayled.png");
- c.gridx = 1; c.gridy = 0;
- gridbag.setConstraints(green, c);
- add(green);
- green.set(false);
- }
-}
+++ /dev/null
-/*
- * 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;
-
-public class AltosLine {
- public String line;
-
- public AltosLine() {
- line = null;
- }
-
- public AltosLine(String s) {
- line = s;
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.io.*;
-import java.lang.*;
-import java.util.*;
-import java.text.ParseException;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/*
- * This creates a thread to capture telemetry data and write it to
- * a log file
- */
-class AltosLog implements Runnable {
-
- LinkedBlockingQueue<AltosLine> input_queue;
- LinkedBlockingQueue<String> pending_queue;
- int serial;
- int flight;
- FileWriter log_file;
- Thread log_thread;
-
- private void close_log_file() {
- if (log_file != null) {
- try {
- log_file.close();
- } catch (IOException io) {
- }
- log_file = null;
- }
- }
-
- void close() {
- close_log_file();
- if (log_thread != null) {
- log_thread.interrupt();
- log_thread = null;
- }
- }
-
- boolean open (AltosTelemetry telem) throws IOException {
- AltosFile a = new AltosFile(telem);
-
- log_file = new FileWriter(a, true);
- if (log_file != null) {
- while (!pending_queue.isEmpty()) {
- try {
- String s = pending_queue.take();
- log_file.write(s);
- log_file.write('\n');
- } catch (InterruptedException ie) {
- }
- }
- log_file.flush();
- }
- return log_file != null;
- }
-
- public void run () {
- try {
- for (;;) {
- AltosLine line = input_queue.take();
- if (line.line == null)
- continue;
- try {
- AltosTelemetry telem = new AltosTelemetry(line.line);
- if (telem.serial != serial || telem.flight != flight || log_file == null) {
- close_log_file();
- serial = telem.serial;
- flight = telem.flight;
- open(telem);
- }
- } catch (ParseException pe) {
- } catch (AltosCRCException ce) {
- }
- if (log_file != null) {
- log_file.write(line.line);
- log_file.write('\n');
- log_file.flush();
- } else
- pending_queue.put(line.line);
- }
- } catch (InterruptedException ie) {
- } catch (IOException ie) {
- }
- close();
- }
-
- public AltosLog (AltosSerial s) {
- pending_queue = new LinkedBlockingQueue<String> ();
- input_queue = new LinkedBlockingQueue<AltosLine> ();
- s.add_monitor(input_queue);
- serial = -1;
- flight = -1;
- log_file = null;
- log_thread = new Thread(this);
- log_thread.start();
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosPad extends JComponent implements AltosFlightDisplay {
- GridBagLayout layout;
-
- public class LaunchStatus {
- JLabel label;
- JTextField value;
- AltosLights lights;
-
- void show(AltosState state, int crc_errors) {}
- void reset() {
- value.setText("");
- lights.set(false);
- }
-
- public LaunchStatus (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.weighty = 1;
-
- lights = new AltosLights();
- c.gridx = 0; c.gridy = y;
- c.anchor = GridBagConstraints.CENTER;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(lights, c);
- add(lights);
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 2; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
-
- }
- }
-
- public class LaunchValue {
- JLabel label;
- JTextField value;
- void show(AltosState state, int crc_errors) {}
-
- void reset() {
- value.setText("");
- }
- public LaunchValue (GridBagLayout layout, int y, String text) {
- GridBagConstraints c = new GridBagConstraints();
- c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
- c.weighty = 1;
-
- label = new JLabel(text);
- label.setFont(Altos.label_font);
- label.setHorizontalAlignment(SwingConstants.LEFT);
- c.gridx = 1; c.gridy = y;
- c.anchor = GridBagConstraints.WEST;
- c.fill = GridBagConstraints.VERTICAL;
- c.weightx = 0;
- layout.setConstraints(label, c);
- add(label);
-
- value = new JTextField(Altos.text_width);
- value.setFont(Altos.value_font);
- value.setHorizontalAlignment(SwingConstants.RIGHT);
- c.gridx = 2; c.gridy = y;
- c.anchor = GridBagConstraints.EAST;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- layout.setConstraints(value, c);
- add(value);
- }
- }
-
- class Battery extends LaunchStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.battery));
- lights.set(state.battery > 3.7);
- }
- public Battery (GridBagLayout layout, int y) {
- super(layout, y, "Battery Voltage");
- }
- }
-
- Battery battery;
-
- class Apogee extends LaunchStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.drogue_sense));
- lights.set(state.drogue_sense > 3.2);
- }
- public Apogee (GridBagLayout layout, int y) {
- super(layout, y, "Apogee Igniter Voltage");
- }
- }
-
- Apogee apogee;
-
- class Main extends LaunchStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.2f V", state.main_sense));
- lights.set(state.main_sense > 3.2);
- }
- public Main (GridBagLayout layout, int y) {
- super(layout, y, "Main Igniter Voltage");
- }
- }
-
- Main main;
-
- class GPSLocked extends LaunchStatus {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4d sats", state.gps.nsat));
- lights.set(state.gps.locked);
- }
- public GPSLocked (GridBagLayout layout, int y) {
- super (layout, y, "GPS Locked");
- }
- }
-
- GPSLocked gps_locked;
-
- class GPSReady extends LaunchStatus {
- void show (AltosState state, int crc_errors) {
- if (state.gps_ready)
- value.setText("Ready");
- else
- value.setText(String.format("Waiting %d", state.gps_waiting));
- lights.set(state.gps_ready);
- }
- public GPSReady (GridBagLayout layout, int y) {
- super (layout, y, "GPS Ready");
- }
- }
-
- GPSReady gps_ready;
-
- String pos(double p, String pos, String neg) {
- String h = pos;
- if (p < 0) {
- h = neg;
- p = -p;
- }
- int deg = (int) Math.floor(p);
- double min = (p - Math.floor(p)) * 60.0;
- return String.format("%s %4d° %9.6f", h, deg, min);
- }
-
- class PadLat extends LaunchValue {
- void show (AltosState state, int crc_errors) {
- value.setText(pos(state.pad_lat,"N", "S"));
- }
- public PadLat (GridBagLayout layout, int y) {
- super (layout, y, "Pad Latitude");
- }
- }
-
- PadLat pad_lat;
-
- class PadLon extends LaunchValue {
- void show (AltosState state, int crc_errors) {
- value.setText(pos(state.pad_lon,"E", "W"));
- }
- public PadLon (GridBagLayout layout, int y) {
- super (layout, y, "Pad Longitude");
- }
- }
-
- PadLon pad_lon;
-
- class PadAlt extends LaunchValue {
- void show (AltosState state, int crc_errors) {
- value.setText(String.format("%4.0f m", state.pad_alt));
- }
- public PadAlt (GridBagLayout layout, int y) {
- super (layout, y, "Pad Altitude");
- }
- }
-
- PadAlt pad_alt;
-
- public void reset() {
- battery.reset();
- apogee.reset();
- main.reset();
- gps_locked.reset();
- gps_ready.reset();
- pad_lat.reset();
- pad_lon.reset();
- pad_alt.reset();
- }
-
- public void show(AltosState state, int crc_errors) {
- battery.show(state, crc_errors);
- apogee.show(state, crc_errors);
- main.show(state, crc_errors);
- gps_locked.show(state, crc_errors);
- gps_ready.show(state, crc_errors);
- pad_lat.show(state, crc_errors);
- pad_lon.show(state, crc_errors);
- pad_alt.show(state, crc_errors);
- }
-
- public AltosPad() {
- layout = new GridBagLayout();
-
- setLayout(layout);
-
- /* Elements in pad display:
- *
- * Battery voltage
- * Igniter continuity
- * GPS lock status
- * GPS ready status
- * GPS location
- * Pad altitude
- * RSSI
- */
- battery = new Battery(layout, 0);
- apogee = new Apogee(layout, 1);
- main = new Main(layout, 2);
- gps_locked = new GPSLocked(layout, 3);
- gps_ready = new GPSReady(layout, 4);
- pad_lat = new PadLat(layout, 5);
- pad_lon = new PadLon(layout, 6);
- pad_alt = new PadAlt(layout, 7);
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.lang.*;
-
-public class AltosParse {
- static boolean isdigit(char c) {
- return '0' <= c && c <= '9';
- }
-
- static int parse_int(String v) throws ParseException {
- try {
- return Altos.fromdec(v);
- } catch (NumberFormatException e) {
- throw new ParseException("error parsing int " + v, 0);
- }
- }
-
- static int parse_hex(String v) throws ParseException {
- try {
- return Altos.fromhex(v);
- } catch (NumberFormatException e) {
- throw new ParseException("error parsing hex " + v, 0);
- }
- }
-
- static double parse_double(String v) throws ParseException {
- try {
- return Double.parseDouble(v);
- } catch (NumberFormatException e) {
- throw new ParseException("error parsing double " + v, 0);
- }
- }
-
- static double parse_coord(String coord) throws ParseException {
- String[] dsf = coord.split("\\D+");
-
- if (dsf.length != 3) {
- throw new ParseException("error parsing coord " + coord, 0);
- }
- int deg = parse_int(dsf[0]);
- int min = parse_int(dsf[1]);
- int frac = parse_int(dsf[2]);
-
- double r = deg + (min + frac / 10000.0) / 60.0;
- if (coord.endsWith("S") || coord.endsWith("W"))
- r = -r;
- return r;
- }
-
- static String strip_suffix(String v, String suffix) {
- if (v.endsWith(suffix))
- return v.substring(0, v.length() - suffix.length());
- return v;
- }
-
- static void word(String v, String m) throws ParseException {
- if (!v.equals(m)) {
- throw new ParseException("error matching '" + v + "' '" + m + "'", 0);
- }
- }
-}
+++ /dev/null
-/*
- * 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.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.awt.Component;
-import javax.swing.*;
-import javax.swing.filechooser.FileSystemView;
-
-class AltosPreferences {
- static Preferences preferences;
-
- /* logdir preference name */
- final static String logdirPreference = "LOGDIR";
-
- /* channel preference name */
- final static String channelPreferenceFormat = "CHANNEL-%d";
-
- /* voice preference name */
- final static String voicePreference = "VOICE";
-
- /* callsign preference name */
- final static String callsignPreference = "CALLSIGN";
-
- /* firmware directory preference name */
- final static String firmwaredirPreference = "FIRMWARE";
-
- /* Default logdir is ~/TeleMetrum */
- final static String logdirName = "TeleMetrum";
-
- /* UI Component to pop dialogs up */
- static Component component;
-
- /* Log directory */
- static File logdir;
-
- /* Channel (map serial to channel) */
- static Hashtable<Integer, Integer> channels;
-
- /* Voice preference */
- static boolean voice;
-
- /* Callsign preference */
- static String callsign;
-
- /* Firmware directory */
- static File firmwaredir;
-
- public static void init(Component ui) {
- preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
-
- component = ui;
-
- /* Initialize logdir from preferences */
- String logdir_string = preferences.get(logdirPreference, null);
- if (logdir_string != null)
- logdir = new File(logdir_string);
- else {
- /* Use the file system view default directory */
- logdir = new File(FileSystemView.getFileSystemView().getDefaultDirectory(), logdirName);
- if (!logdir.exists())
- logdir.mkdirs();
- }
-
- channels = new Hashtable<Integer,Integer>();
-
- voice = preferences.getBoolean(voicePreference, true);
-
- callsign = preferences.get(callsignPreference,"N0CALL");
-
- String firmwaredir_string = preferences.get(firmwaredirPreference, null);
- if (firmwaredir_string != null)
- firmwaredir = new File(firmwaredir_string);
- else
- firmwaredir = null;
- }
-
- static void flush_preferences() {
- try {
- preferences.flush();
- } catch (BackingStoreException ee) {
- JOptionPane.showMessageDialog(component,
- preferences.absolutePath(),
- "Cannot save prefernces",
- JOptionPane.ERROR_MESSAGE);
- }
- }
-
- public static void set_logdir(File new_logdir) {
- logdir = new_logdir;
- synchronized (preferences) {
- preferences.put(logdirPreference, logdir.getPath());
- flush_preferences();
- }
- }
-
- private static boolean check_dir(File dir) {
- if (!dir.exists()) {
- if (!dir.mkdirs()) {
- JOptionPane.showMessageDialog(component,
- dir.getName(),
- "Cannot create directory",
- JOptionPane.ERROR_MESSAGE);
- return false;
- }
- } else if (!dir.isDirectory()) {
- JOptionPane.showMessageDialog(component,
- dir.getName(),
- "Is not a directory",
- JOptionPane.ERROR_MESSAGE);
- return false;
- }
- return true;
- }
-
- /* Configure the log directory. This is where all telemetry and eeprom files
- * will be written to, and where replay will look for telemetry files
- */
- public static void ConfigureLog() {
- JFileChooser logdir_chooser = new JFileChooser(logdir.getParentFile());
-
- logdir_chooser.setDialogTitle("Configure Data Logging Directory");
- logdir_chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
-
- if (logdir_chooser.showDialog(component, "Select Directory") == JFileChooser.APPROVE_OPTION) {
- File dir = logdir_chooser.getSelectedFile();
- if (check_dir(dir))
- set_logdir(dir);
- }
- }
-
- public static File logdir() {
- return logdir;
- }
-
- public static void set_channel(int serial, int new_channel) {
- channels.put(serial, new_channel);
- synchronized (preferences) {
- preferences.putInt(String.format(channelPreferenceFormat, serial), new_channel);
- flush_preferences();
- }
- }
-
- public static int channel(int serial) {
- if (channels.containsKey(serial))
- return channels.get(serial);
- int channel = preferences.getInt(String.format(channelPreferenceFormat, serial), 0);
- channels.put(serial, channel);
- return channel;
- }
-
- public static void set_voice(boolean new_voice) {
- voice = new_voice;
- synchronized (preferences) {
- preferences.putBoolean(voicePreference, voice);
- flush_preferences();
- }
- }
-
- public static boolean voice() {
- return voice;
- }
-
- public static void set_callsign(String new_callsign) {
- callsign = new_callsign;
- synchronized(preferences) {
- preferences.put(callsignPreference, callsign);
- flush_preferences();
- }
- }
-
- public static String callsign() {
- return callsign;
- }
-
- public static void set_firmwaredir(File new_firmwaredir) {
- firmwaredir = new_firmwaredir;
- synchronized (preferences) {
- preferences.put(firmwaredirPreference, firmwaredir.getPath());
- flush_preferences();
- }
- }
-
- public static File firmwaredir() {
- return firmwaredir;
- }
-}
+++ /dev/null
-/*
- * 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.io.*;
-import java.util.*;
-import java.text.*;
-
-public class AltosReader {
- public AltosRecord read() throws IOException, ParseException { return null; }
- public void close() { }
- public void write_comments(PrintStream out) { }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.util.HashMap;
-import java.io.*;
-
-public class AltosRecord {
- int version;
- String callsign;
- int serial;
- int flight;
- int rssi;
- int status;
- int state;
- int tick;
- int accel;
- int pres;
- int temp;
- int batt;
- int drogue;
- int main;
- int flight_accel;
- int ground_accel;
- int flight_vel;
- int flight_pres;
- int ground_pres;
- int accel_plus_g;
- int accel_minus_g;
- AltosGPS gps;
-
- double time; /* seconds since boost */
-
- /*
- * Values for our MP3H6115A pressure sensor
- *
- * From the data sheet:
- *
- * Pressure range: 15-115 kPa
- * Voltage at 115kPa: 2.82
- * Output scale: 27mV/kPa
- *
- *
- * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
- * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
- */
-
- static final double counts_per_kPa = 27 * 2047 / 3300;
- static final double counts_at_101_3kPa = 1674.0;
-
- static double
- barometer_to_pressure(double count)
- {
- return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
- }
-
- public double raw_pressure() {
- return barometer_to_pressure(pres);
- }
-
- public double filtered_pressure() {
- return barometer_to_pressure(flight_pres);
- }
-
- public double ground_pressure() {
- return barometer_to_pressure(ground_pres);
- }
-
- public double filtered_altitude() {
- return AltosConvert.pressure_to_altitude(filtered_pressure());
- }
-
- public double raw_altitude() {
- return AltosConvert.pressure_to_altitude(raw_pressure());
- }
-
- public double ground_altitude() {
- return AltosConvert.pressure_to_altitude(ground_pressure());
- }
-
- public double filtered_height() {
- return filtered_altitude() - ground_altitude();
- }
-
- public double raw_height() {
- return raw_altitude() - ground_altitude();
- }
-
- public double battery_voltage() {
- return AltosConvert.cc_battery_to_voltage(batt);
- }
-
- public double main_voltage() {
- return AltosConvert.cc_ignitor_to_voltage(main);
- }
-
- public double drogue_voltage() {
- return AltosConvert.cc_ignitor_to_voltage(drogue);
- }
-
- /* Value for the CC1111 built-in temperature sensor
- * Output voltage at 0°C = 0.755V
- * Coefficient = 0.00247V/°C
- * Reference voltage = 1.25V
- *
- * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
- * = (value - 19791.268) / 32768 * 1.25 / 0.00247
- */
-
- static double
- thermometer_to_temperature(double thermo)
- {
- return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
- }
-
- public double temperature() {
- return thermometer_to_temperature(temp);
- }
-
- double accel_counts_per_mss() {
- double counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
-
- return counts_per_g / 9.80665;
- }
- public double acceleration() {
- return (ground_accel - accel) / accel_counts_per_mss();
- }
-
- public double accel_speed() {
- double speed = flight_vel / (accel_counts_per_mss() * 100.0);
- return speed;
- }
-
- public String state() {
- return Altos.state_name(state);
- }
-
- public static String gets(FileInputStream s) throws IOException {
- int c;
- String line = "";
-
- while ((c = s.read()) != -1) {
- if (c == '\r')
- continue;
- if (c == '\n') {
- return line;
- }
- line = line + (char) c;
- }
- return null;
- }
-
- public AltosRecord(AltosRecord old) {
- version = old.version;
- callsign = old.callsign;
- serial = old.serial;
- flight = old.flight;
- rssi = old.rssi;
- status = old.status;
- state = old.state;
- tick = old.tick;
- accel = old.accel;
- pres = old.pres;
- temp = old.temp;
- batt = old.batt;
- drogue = old.drogue;
- main = old.main;
- flight_accel = old.flight_accel;
- ground_accel = old.ground_accel;
- flight_vel = old.flight_vel;
- flight_pres = old.flight_pres;
- ground_pres = old.ground_pres;
- accel_plus_g = old.accel_plus_g;
- accel_minus_g = old.accel_minus_g;
- gps = new AltosGPS(old.gps);
- }
-
- public AltosRecord() {
- version = 0;
- callsign = "N0CALL";
- serial = 0;
- flight = 0;
- rssi = 0;
- status = 0;
- state = Altos.ao_flight_startup;
- tick = 0;
- accel = 0;
- pres = 0;
- temp = 0;
- batt = 0;
- drogue = 0;
- main = 0;
- flight_accel = 0;
- ground_accel = 0;
- flight_vel = 0;
- flight_pres = 0;
- ground_pres = 0;
- accel_plus_g = 0;
- accel_minus_g = 0;
- gps = new AltosGPS();
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public abstract class AltosRecordIterable implements Iterable<AltosRecord> {
- public abstract Iterator<AltosRecord> iterator();
- public void write_comments(PrintStream out) { }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/*
- * Open an existing telemetry file and replay it in realtime
- */
-
-public class AltosReplayReader extends AltosFlightReader {
- Iterator<AltosRecord> iterator;
-
- public AltosRecord read() {
- if (iterator.hasNext())
- return iterator.next();
- return null;
- }
-
- public void close (boolean interrupted) {
- }
-
- void update(AltosState state) throws InterruptedException {
- /* Make it run in realtime after the rocket leaves the pad */
- if (state.state > Altos.ao_flight_pad)
- Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
- }
-
- public AltosReplayReader(Iterator<AltosRecord> in_iterator, String in_name) {
- iterator = in_iterator;
- name = in_name;
- }
-}
+++ /dev/null
-/*
- * 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.io.*;
-
-public class AltosRomconfig {
- public boolean valid;
- public int version;
- public int check;
- public int serial_number;
- public int radio_calibration;
-
- static int get_int(byte[] bytes, int start, int len) {
- int v = 0;
- int o = 0;
- while (len > 0) {
- v = v | ((((int) bytes[start]) & 0xff) << o);
- start++;
- len--;
- o += 8;
- }
- return v;
- }
-
- static void put_int(int value, byte[] bytes, int start, int len) {
- while (len > 0) {
- bytes[start] = (byte) (value & 0xff);
- start++;
- len--;
- value >>= 8;
- }
- }
-
- static void put_string(String value, byte[] bytes, int start) {
- for (int i = 0; i < value.length(); i++)
- bytes[start + i] = (byte) value.charAt(i);
- }
-
- static final int AO_USB_DESC_STRING = 3;
-
- static void put_usb_serial(int value, byte[] bytes, int start) {
- int offset = start + 0xa;
- int string_num = 0;
-
- while (offset < bytes.length && bytes[offset] != 0) {
- if (bytes[offset + 1] == AO_USB_DESC_STRING) {
- ++string_num;
- if (string_num == 4)
- break;
- }
- offset += ((int) bytes[offset]) & 0xff;
- }
- if (offset >= bytes.length || bytes[offset] == 0)
- return;
- int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
- String fmt = String.format("%%0%dd", len);
-
- String s = String.format(fmt, value);
- if (s.length() != len) {
- System.out.printf("weird usb length issue %s isn't %d\n",
- s, len);
- return;
- }
- for (int i = 0; i < len; i++) {
- bytes[offset + 2 + i*2] = (byte) s.charAt(i);
- bytes[offset + 2 + i*2+1] = 0;
- }
- }
-
- public AltosRomconfig(byte[] bytes, int offset) {
- version = get_int(bytes, offset + 0, 2);
- check = get_int(bytes, offset + 2, 2);
- if (check == (~version & 0xffff)) {
- switch (version) {
- case 2:
- case 1:
- serial_number = get_int(bytes, offset + 4, 2);
- radio_calibration = get_int(bytes, offset + 6, 4);
- valid = true;
- break;
- }
- }
- }
-
- public AltosRomconfig(AltosHexfile hexfile) {
- this(hexfile.data, 0xa0 - hexfile.address);
- }
-
- public void write(byte[] bytes, int offset) throws IOException {
- if (!valid)
- throw new IOException("rom configuration invalid");
-
- if (offset < 0 || bytes.length < offset + 10)
- throw new IOException("image cannot contain rom config");
-
- AltosRomconfig existing = new AltosRomconfig(bytes, offset);
- if (!existing.valid)
- throw new IOException("image does not contain existing rom config");
-
- switch (existing.version) {
- case 2:
- put_usb_serial(serial_number, bytes, offset);
- case 1:
- put_int(serial_number, bytes, offset + 4, 2);
- put_int(radio_calibration, bytes, offset + 6, 4);
- break;
- }
- }
-
- public void write (AltosHexfile hexfile) throws IOException {
- write(hexfile.data, 0xa0 - hexfile.address);
- AltosRomconfig check = new AltosRomconfig(hexfile);
- if (!check.valid())
- throw new IOException("writing new rom config failed\n");
- }
-
- public AltosRomconfig(int in_serial_number, int in_radio_calibration) {
- valid = true;
- version = 1;
- check = (~version & 0xffff);
- serial_number = in_serial_number;
- radio_calibration = in_radio_calibration;
- }
-
- public boolean valid() {
- return valid && serial_number != 0;
- }
-
- public AltosRomconfig() {
- valid = false;
- }
-}
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import javax.swing.event.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-
-public class AltosRomconfigUI
- extends JDialog
- implements ActionListener
-{
- Container pane;
- Box box;
- JLabel serial_label;
- JLabel radio_calibration_label;
-
- JFrame owner;
- JTextField serial_value;
- JTextField radio_calibration_value;
-
- JButton ok;
- JButton cancel;
-
- /* Build the UI using a grid bag */
- public AltosRomconfigUI(JFrame in_owner) {
- super (in_owner, "Configure TeleMetrum Rom Values", true);
-
- owner = in_owner;
- GridBagConstraints c;
-
- Insets il = new Insets(4,4,4,4);
- Insets ir = new Insets(4,4,4,4);
-
- pane = getContentPane();
- pane.setLayout(new GridBagLayout());
-
- /* Serial */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 0;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- serial_label = new JLabel("Serial:");
- pane.add(serial_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 3; c.gridy = 0;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- serial_value = new JTextField("0");
- pane.add(serial_value, c);
-
- /* Radio calibration value */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 1;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = il;
- c.ipady = 5;
- radio_calibration_label = new JLabel("Radio Calibration:");
- pane.add(radio_calibration_label, c);
-
- c = new GridBagConstraints();
- c.gridx = 3; c.gridy = 1;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.HORIZONTAL;
- c.weightx = 1;
- c.anchor = GridBagConstraints.LINE_START;
- c.insets = ir;
- c.ipady = 5;
- radio_calibration_value = new JTextField("1186611");
- pane.add(radio_calibration_value, c);
-
- /* Buttons */
- c = new GridBagConstraints();
- c.gridx = 0; c.gridy = 2;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.insets = il;
- ok = new JButton("OK");
- pane.add(ok, c);
- ok.addActionListener(this);
- ok.setActionCommand("ok");
-
- c = new GridBagConstraints();
- c.gridx = 3; c.gridy = 2;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.CENTER;
- c.insets = il;
- cancel = new JButton("Cancel");
- pane.add(cancel, c);
- cancel.addActionListener(this);
- cancel.setActionCommand("cancel");
-
- pack();
- setLocationRelativeTo(owner);
- }
-
- boolean selected;
-
- /* Listen for events from our buttons */
- public void actionPerformed(ActionEvent e) {
- String cmd = e.getActionCommand();
-
- if (cmd.equals("ok")) {
- AltosRomconfig romconfig = romconfig();
- if (romconfig == null || !romconfig.valid()) {
- JOptionPane.showMessageDialog(this,
- "Invalid serial number or radio calibration value",
- "Invalid rom configuration",
- JOptionPane.ERROR_MESSAGE);
- return;
- }
- selected = true;
- }
- setVisible(false);
- }
-
- int serial() {
- return Integer.parseInt(serial_value.getText());
- }
-
- void set_serial(int serial) {
- serial_value.setText(String.format("%d", serial));
- }
-
- int radio_calibration() {
- return Integer.parseInt(radio_calibration_value.getText());
- }
-
- void set_radio_calibration(int calibration) {
- radio_calibration_value.setText(String.format("%d", calibration));
- }
-
- public void set(AltosRomconfig config) {
- if (config != null && config.valid()) {
- set_serial(config.serial_number);
- set_radio_calibration(config.radio_calibration);
- }
- }
-
- AltosRomconfig romconfig() {
- try {
- return new AltosRomconfig(serial(), radio_calibration());
- } catch (NumberFormatException ne) {
- return null;
- }
- }
-
- public AltosRomconfig showDialog() {
- setVisible(true);
- if (selected)
- return romconfig();
- return null;
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * Deal with TeleDongle on a serial port
- */
-
-package altosui;
-
-import java.lang.*;
-import java.io.*;
-import java.util.concurrent.*;
-import java.util.*;
-
-import libaltosJNI.*;
-
-/*
- * 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.
- */
-
-public class AltosSerial implements Runnable {
-
- static List<String> devices_opened = Collections.synchronizedList(new LinkedList<String>());
-
- AltosDevice device;
- SWIGTYPE_p_altos_file altos;
- LinkedList<LinkedBlockingQueue<AltosLine>> monitors;
- LinkedBlockingQueue<AltosLine> reply_queue;
- Thread input_thread;
- String line;
- byte[] line_bytes;
- int line_count;
- boolean monitor_mode;
-
- public void run () {
- int c;
-
- try {
- for (;;) {
- c = libaltos.altos_getchar(altos, 0);
- if (Thread.interrupted())
- break;
- if (c == libaltosConstants.LIBALTOS_ERROR) {
- for (int e = 0; e < monitors.size(); e++) {
- LinkedBlockingQueue<AltosLine> q = monitors.get(e);
- q.put(new AltosLine());
- }
- reply_queue.put (new AltosLine());
- break;
- }
- if (c == libaltosConstants.LIBALTOS_TIMEOUT)
- continue;
- if (c == '\r')
- continue;
- synchronized(this) {
- if (c == '\n') {
- if (line_count != 0) {
- try {
- line = new String(line_bytes, 0, line_count, "UTF-8");
- } catch (UnsupportedEncodingException ue) {
- line = "";
- for (int i = 0; i < line_count; i++)
- line = line + line_bytes[i];
- }
- if (line.startsWith("VERSION") || line.startsWith("CRC")) {
- for (int e = 0; e < monitors.size(); e++) {
- LinkedBlockingQueue<AltosLine> q = monitors.get(e);
- q.put(new AltosLine (line));
- }
- } else {
-// System.out.printf("GOT: %s\n", line);
- reply_queue.put(new AltosLine (line));
- }
- line_count = 0;
- line = "";
- }
- } 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 void flush_output() {
- if (altos != null)
- libaltos.altos_flush(altos);
- }
-
- public void flush_input() {
- flush_output();
- boolean got_some;
- do {
- try {
- Thread.sleep(100);
- } catch (InterruptedException ie) {
- }
- got_some = !reply_queue.isEmpty();
- synchronized(this) {
- if (!"VERSION".startsWith(line) &&
- !line.startsWith("VERSION"))
- line = "";
- reply_queue.clear();
- }
- } while (got_some);
- }
-
- public String get_reply() throws InterruptedException {
- flush_output();
- AltosLine line = reply_queue.take();
- return line.line;
- }
-
- public String get_reply(int timeout) throws InterruptedException {
- flush_output();
- AltosLine line = reply_queue.poll(timeout, TimeUnit.MILLISECONDS);
- if (line == null)
- return null;
- return line.line;
- }
-
- public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
- set_monitor(true);
- monitors.add(q);
- }
-
- public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
- monitors.remove(q);
- if (monitors.isEmpty())
- set_monitor(false);
- }
-
- public void close() {
- if (altos != null) {
- libaltos.altos_close(altos);
- }
- if (input_thread != null) {
- try {
- input_thread.interrupt();
- input_thread.join();
- } catch (InterruptedException e) {
- }
- input_thread = null;
- }
- if (altos != null) {
- libaltos.altos_free(altos);
- altos = null;
- }
- synchronized (devices_opened) {
- devices_opened.remove(device.getPath());
- }
- }
-
- public void putc(char c) {
- if (altos != null)
- libaltos.altos_putchar(altos, c);
- }
-
- public void print(String data) {
-// System.out.printf("\"%s\" ", data);
- for (int i = 0; i < data.length(); i++)
- putc(data.charAt(i));
- }
-
- public void printf(String format, Object ... arguments) {
- print(String.format(format, arguments));
- }
-
- private void open() throws FileNotFoundException, AltosSerialInUseException {
- synchronized (devices_opened) {
- if (devices_opened.contains(device.getPath()))
- throw new AltosSerialInUseException(device);
- devices_opened.add(device.getPath());
- }
- altos = libaltos.altos_open(device);
- if (altos == null) {
- close();
- throw new FileNotFoundException(device.toShortString());
- }
- input_thread = new Thread(this);
- input_thread.start();
- print("~\nE 0\n");
- set_monitor(false);
- flush_output();
- }
-
- public void set_radio() {
- set_channel(AltosPreferences.channel(device.getSerial()));
- set_callsign(AltosPreferences.callsign());
- }
-
- public void set_channel(int channel) {
- if (altos != null) {
- if (monitor_mode)
- printf("m 0\nc r %d\nm 1\n", channel);
- else
- printf("c r %d\n", channel);
- flush_output();
- }
- }
-
- void set_monitor(boolean monitor) {
- monitor_mode = monitor;
- if (altos != null) {
- if (monitor)
- printf("m 1\n");
- else
- printf("m 0\n");
- flush_output();
- }
- }
-
- public void set_callsign(String callsign) {
- if (altos != null) {
- printf ("c c %s\n", callsign);
- flush_output();
- }
- }
-
- public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
- device = in_device;
- line = "";
- monitor_mode = false;
- monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();
- reply_queue = new LinkedBlockingQueue<AltosLine> ();
- open();
- }
-}
+++ /dev/null
-/*
- * 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 libaltosJNI.*;
-
-public class AltosSerialInUseException extends Exception {
- public altos_device device;
-
- public AltosSerialInUseException (altos_device in_device) {
- device = in_device;
- }
-}
+++ /dev/null
-/*
- * 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;
-
-public interface AltosSerialMonitor {
- void data(String data);
-}
+++ /dev/null
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * 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.awt.*;
-import java.awt.image.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.event.MouseInputAdapter;
-import javax.imageio.ImageIO;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.lang.Math;
-import java.awt.geom.Point2D;
-import java.awt.geom.Line2D;
-
-public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
- // preferred vertical step in a tile in naut. miles
- // will actually choose a step size between x and 2x, where this
- // is 1.5x
- static final double tile_size_nmi = 0.75;
-
- static final int px_size = 512;
-
- static final int MAX_TILE_DELTA = 100;
-
- private static Point2D.Double translatePoint(Point2D.Double p,
- Point2D.Double d)
- {
- return new Point2D.Double(p.x + d.x, p.y + d.y);
- }
-
- static class LatLng {
- public double lat, lng;
- public LatLng(double lat, double lng) {
- this.lat = lat;
- this.lng = lng;
- }
- }
-
- // based on google js
- // http://maps.gstatic.com/intl/en_us/mapfiles/api-3/2/10/main.js
- // search for fromLatLngToPoint and fromPointToLatLng
- private static Point2D.Double pt(LatLng latlng, int zoom) {
- double scale_x = 256/360.0 * Math.pow(2, zoom);
- double scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
- return pt(latlng, scale_x, scale_y);
- }
-
- private static Point2D.Double pt(LatLng latlng,
- double scale_x, double scale_y)
- {
- Point2D.Double res = new Point2D.Double();
- double e;
-
- res.x = latlng.lng * scale_x;
-
- e = Math.sin(Math.toRadians(latlng.lat));
- e = Math.max(e,-(1-1.0E-15));
- e = Math.min(e, 1-1.0E-15 );
-
- res.y = 0.5*Math.log((1+e)/(1-e))*-scale_y;
- return res;
- }
-
- static private LatLng latlng(Point2D.Double pt,
- double scale_x, double scale_y)
- {
- double lat, lng;
- double rads;
-
- lng = pt.x/scale_x;
- rads = 2 * Math.atan(Math.exp(-pt.y/scale_y));
- lat = Math.toDegrees(rads - Math.PI/2);
-
- return new LatLng(lat,lng);
- }
-
- int zoom;
- double scale_x, scale_y;
-
- private Point2D.Double pt(double lat, double lng) {
- return pt(new LatLng(lat, lng), scale_x, scale_y);
- }
-
- private LatLng latlng(double x, double y) {
- return latlng(new Point2D.Double(x,y), scale_x, scale_y);
- }
- private LatLng latlng(Point2D.Double pt) {
- return latlng(pt, scale_x, scale_y);
- }
-
- HashMap<Point,AltosSiteMapTile> mapTiles = new HashMap<Point,AltosSiteMapTile>();
- Point2D.Double centre;
-
- private Point2D.Double tileCoordOffset(Point p) {
- return new Point2D.Double(centre.x - p.x*px_size,
- centre.y - p.y * px_size);
- }
-
- private Point tileOffset(Point2D.Double p) {
- return new Point((int)Math.floor((centre.x+p.x)/px_size),
- (int)Math.floor((centre.y+p.y)/px_size));
- }
-
- private Point2D.Double getBaseLocation(double lat, double lng) {
- Point2D.Double locn, north_step;
-
- zoom = 2;
- // stupid loop structure to please Java's control flow analysis
- do {
- zoom++;
- scale_x = 256/360.0 * Math.pow(2, zoom);
- scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
- locn = pt(lat, lng);
- north_step = pt(lat+tile_size_nmi*4/3/60.0, lng);
- if (locn.y - north_step.y > px_size)
- break;
- } while (zoom < 22);
- locn.x = -px_size * Math.floor(locn.x/px_size);
- locn.y = -px_size * Math.floor(locn.y/px_size);
- return locn;
- }
-
- public void reset() {
- // nothing
- }
-
- private void bgLoadMap(final AltosSiteMapTile tile,
- final File pngfile, final String pngurl)
- {
- //System.out.printf("Loading/fetching map %s\n", pngfile);
- Thread thread = new Thread() {
- public void run() {
- ImageIcon res;
- res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl);
- if (res != null) {
- tile.loadMap(res);
- } else {
- System.out.printf("# Failed to fetch file %s\n", pngfile);
- System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl);
- }
- }
- };
- thread.start();
- }
-
- public static void prefetchMaps(double lat, double lng, int w, int h) {
- AltosPreferences.init(null);
-
- AltosSiteMap asm = new AltosSiteMap(true);
- asm.centre = asm.getBaseLocation(lat, lng);
-
- Point2D.Double p = new Point2D.Double();
- Point2D.Double p2;
- int dx = -w/2, dy = -h/2;
- for (int y = dy; y < h+dy; y++) {
- for (int x = dx; x < w+dx; x++) {
- LatLng map_latlng = asm.latlng(
- -asm.centre.x + x*px_size + px_size/2,
- -asm.centre.y + y*px_size + px_size/2);
- File pngfile = asm.MapFile(map_latlng.lat, map_latlng.lng);
- String pngurl = asm.MapURL(map_latlng.lat, map_latlng.lng);
- if (pngfile.exists()) {
- System.out.printf("Already have %s\n", pngfile);
- } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) {
- System.out.printf("Fetched map %s\n", pngfile);
- } else {
- System.out.printf("# Failed to fetch file %s\n", pngfile);
- System.out.printf(" wget -O '%s' ''\n", pngfile, pngurl);
- }
- }
- }
- }
-
- private void initMap(AltosSiteMapTile tile, Point offset) {
- Point2D.Double coord = tileCoordOffset(offset);
-
- LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y);
-
- File pngfile = MapFile(map_latlng.lat, map_latlng.lng);
- String pngurl = MapURL(map_latlng.lat, map_latlng.lng);
- bgLoadMap(tile, pngfile, pngurl);
- }
-
- private void initMaps(double lat, double lng) {
- centre = getBaseLocation(lat, lng);
-
- for (Point k : mapTiles.keySet()) {
- initMap(mapTiles.get(k), k);
- }
- }
-
- private File MapFile(double lat, double lng) {
- char chlat = lat < 0 ? 'S' : 'N';
- char chlng = lng < 0 ? 'E' : 'W';
- if (lat < 0) lat = -lat;
- if (lng < 0) lng = -lng;
- return new File(AltosPreferences.logdir(),
- String.format("map-%c%.6f,%c%.6f-%d.png",
- chlat, lat, chlng, lng, zoom));
- }
-
- private String MapURL(double lat, double lng) {
- return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=hybrid&format=png32", lat, lng, zoom, px_size, px_size);
- }
-
- boolean initialised = false;
- Point2D.Double last_pt = null;
- int last_state = -1;
- public void show(final AltosState state, final int crc_errors) {
- // if insufficient gps data, nothing to update
- if (state.gps == null)
- return;
- if (state.pad_lat == 0 && state.pad_lon == 0)
- return;
- if (!state.gps.locked) {
- if (state.gps.nsat < 4)
- return;
- }
-
- if (!initialised) {
- initMaps(state.pad_lat, state.pad_lon);
- initialised = true;
- }
-
- final Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
- if (last_pt == pt && last_state == state.state)
- return;
-
- if (last_pt == null) {
- last_pt = pt;
- }
- boolean in_any = false;
- for (Point offset : mapTiles.keySet()) {
- AltosSiteMapTile tile = mapTiles.get(offset);
- Point2D.Double ref, lref;
- ref = translatePoint(pt, tileCoordOffset(offset));
- lref = translatePoint(last_pt, tileCoordOffset(offset));
- tile.show(state, crc_errors, lref, ref);
- if (0 <= ref.x && ref.x < px_size)
- if (0 <= ref.y && ref.y < px_size)
- in_any = true;
- }
-
- Point offset = tileOffset(pt);
- if (!in_any) {
- Point2D.Double ref, lref;
- ref = translatePoint(pt, tileCoordOffset(offset));
- lref = translatePoint(last_pt, tileCoordOffset(offset));
-
- AltosSiteMapTile tile = createTile(offset);
- tile.show(state, crc_errors, lref, ref);
- initMap(tile, offset);
- finishTileLater(tile, offset);
- }
-
- scrollRocketToVisible(pt);
-
- if (offset != tileOffset(last_pt)) {
- ensureTilesAround(offset);
- }
-
- last_pt = pt;
- last_state = state.state;
- }
-
- private AltosSiteMapTile createTile(Point offset) {
- AltosSiteMapTile tile = new AltosSiteMapTile(px_size);
- mapTiles.put(offset, tile);
- return tile;
- }
- private void finishTileLater(final AltosSiteMapTile tile,
- final Point offset)
- {
- SwingUtilities.invokeLater( new Runnable() {
- public void run() {
- addTileAt(tile, offset);
- }
- } );
- }
-
- private void ensureTilesAround(Point base_offset) {
- for (int x = -1; x <= 1; x++) {
- for (int y = -1; y <= 1; y++) {
- Point offset = new Point(base_offset.x + x, base_offset.y + y);
- if (mapTiles.containsKey(offset))
- continue;
- AltosSiteMapTile tile = createTile(offset);
- initMap(tile, offset);
- finishTileLater(tile, offset);
- }
- }
- }
-
- private Point topleft = new Point(0,0);
- private void scrollRocketToVisible(Point2D.Double pt) {
- Rectangle r = comp.getVisibleRect();
- Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft));
- int dx = (int)copt.x - r.width/2 - r.x;
- int dy = (int)copt.y - r.height/2 - r.y;
- if (Math.abs(dx) > r.width/4 || Math.abs(dy) > r.height/4) {
- r.x += dx;
- r.y += dy;
- comp.scrollRectToVisible(r);
- }
- }
-
- private void addTileAt(AltosSiteMapTile tile, Point offset) {
- if (Math.abs(offset.x) >= MAX_TILE_DELTA ||
- Math.abs(offset.y) >= MAX_TILE_DELTA)
- {
- System.out.printf("Rocket too far away from pad (tile %d,%d)\n",
- offset.x, offset.y);
- return;
- }
-
- boolean review = false;
- Rectangle r = comp.getVisibleRect();
- if (offset.x < topleft.x) {
- r.x += (topleft.x - offset.x) * px_size;
- topleft.x = offset.x;
- review = true;
- }
- if (offset.y < topleft.y) {
- r.y += (topleft.y - offset.y) * px_size;
- topleft.y = offset.y;
- review = true;
- }
- GridBagConstraints c = new GridBagConstraints();
- c.anchor = GridBagConstraints.CENTER;
- c.fill = GridBagConstraints.BOTH;
- // put some space between the map tiles, debugging only
- // c.insets = new Insets(5, 5, 5, 5);
-
- c.gridx = offset.x + MAX_TILE_DELTA;
- c.gridy = offset.y + MAX_TILE_DELTA;
- layout.setConstraints(tile, c);
-
- comp.add(tile);
- if (review) {
- comp.scrollRectToVisible(r);
- }
- }
-
- private AltosSiteMap(boolean knowWhatYouAreDoing) {
- if (!knowWhatYouAreDoing) {
- throw new RuntimeException("Arggh.");
- }
- }
-
- JComponent comp = new JComponent() { };
- private GridBagLayout layout = new GridBagLayout();
-
- public AltosSiteMap() {
- GrabNDrag scroller = new GrabNDrag(comp);
-
- comp.setLayout(layout);
-
- for (int x = -1; x <= 1; x++) {
- for (int y = -1; y <= 1; y++) {
- Point offset = new Point(x, y);
- AltosSiteMapTile t = createTile(offset);
- addTileAt(t, offset);
- }
- }
- setViewportView(comp);
- setPreferredSize(new Dimension(500,200));
- }
-}
+++ /dev/null
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * 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.awt.*;
-import java.awt.image.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.imageio.ImageIO;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.net.URL;
-import java.net.URLConnection;
-
-public class AltosSiteMapCache extends JLabel {
- public static boolean fetchMap(File file, String url) {
- URL u;
-
- try {
- u = new URL(url);
- } catch (java.net.MalformedURLException e) {
- return false;
- }
-
- byte[] data;
- try {
- URLConnection uc = u.openConnection();
- int contentLength = uc.getContentLength();
- InputStream in = new BufferedInputStream(uc.getInputStream());
- int bytesRead = 0;
- int offset = 0;
- data = new byte[contentLength];
- while (offset < contentLength) {
- bytesRead = in.read(data, offset, data.length - offset);
- if (bytesRead == -1)
- break;
- offset += bytesRead;
- }
- in.close();
-
- if (offset != contentLength) {
- return false;
- }
- } catch (IOException e) {
- return false;
- }
-
- try {
- FileOutputStream out = new FileOutputStream(file);
- out.write(data);
- out.flush();
- out.close();
- } catch (FileNotFoundException e) {
- return false;
- } catch (IOException e) {
- if (file.exists()) {
- file.delete();
- }
- return false;
- }
- return true;
- }
-
- public static ImageIcon fetchAndLoadMap(File pngfile, String url) {
- if (!pngfile.exists()) {
- if (!fetchMap(pngfile, url)) {
- return null;
- }
- }
- return loadMap(pngfile, url);
- }
-
- public static ImageIcon loadMap(File pngfile, String url) {
- if (!pngfile.exists()) {
- return null;
- }
-
- try {
- return new ImageIcon(ImageIO.read(pngfile));
- } catch (IOException e) {
- System.out.printf("# IO error trying to load %s\n", pngfile);
- return null;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * 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.awt.*;
-import java.awt.image.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.imageio.ImageIO;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.lang.Math;
-import java.awt.geom.Point2D;
-import java.awt.geom.Line2D;
-
-public class AltosSiteMapTile extends JLayeredPane {
- JLabel mapLabel;
- JLabel draw;
- Graphics2D g2d;
-
- public void loadMap(ImageIcon icn) {
- mapLabel.setIcon(icn);
- }
-
- static Color stateColors[] = {
- Color.WHITE, // startup
- Color.WHITE, // idle
- Color.WHITE, // pad
- Color.RED, // boost
- Color.PINK, // fast
- Color.YELLOW, // coast
- Color.CYAN, // drogue
- Color.BLUE, // main
- Color.BLACK // landed
- };
-
- private boolean drawn_landed_circle = false;
- private boolean drawn_boost_circle = false;
- public synchronized void show(AltosState state, int crc_errors,
- Point2D.Double last_pt, Point2D.Double pt)
- {
- if (0 <= state.state && state.state < stateColors.length) {
- g2d.setColor(stateColors[state.state]);
- }
- g2d.draw(new Line2D.Double(last_pt, pt));
-
- if (state.state == 3 && !drawn_boost_circle) {
- drawn_boost_circle = true;
- g2d.setColor(Color.RED);
- g2d.drawOval((int)last_pt.x-5, (int)last_pt.y-5, 10, 10);
- g2d.drawOval((int)last_pt.x-20, (int)last_pt.y-20, 40, 40);
- g2d.drawOval((int)last_pt.x-35, (int)last_pt.y-35, 70, 70);
- }
- if (state.state == 8 && !drawn_landed_circle) {
- drawn_landed_circle = true;
- g2d.setColor(Color.BLACK);
- g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10);
- g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40);
- g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70);
- }
-
- repaint();
- }
-
- public static Graphics2D fillLabel(JLabel l, Color c, int px_size) {
- BufferedImage img = new BufferedImage(px_size, px_size,
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = img.createGraphics();
- g.setColor(c);
- g.fillRect(0, 0, px_size, px_size);
- l.setIcon(new ImageIcon(img));
- return g;
- }
-
- public AltosSiteMapTile(int px_size) {
- setPreferredSize(new Dimension(px_size, px_size));
-
- mapLabel = new JLabel();
- fillLabel(mapLabel, Color.GRAY, px_size);
- mapLabel.setOpaque(true);
- mapLabel.setBounds(0, 0, px_size, px_size);
- add(mapLabel, new Integer(0));
-
- draw = new JLabel();
- g2d = fillLabel(draw, new Color(127, 127, 127, 0), px_size);
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- draw.setBounds(0, 0, px_size, px_size);
- draw.setOpaque(false);
-
- add(draw, new Integer(1));
- }
-}
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * Track flight state from telemetry or eeprom data stream
- */
-
-package altosui;
-
-public class AltosState {
- AltosRecord data;
-
- /* derived data */
-
- long report_time;
-
- double time_change;
- int tick;
-
- int state;
- boolean landed;
- boolean ascent; /* going up? */
-
- double ground_altitude;
- double height;
- double speed;
- double acceleration;
- double battery;
- double temperature;
- double main_sense;
- double drogue_sense;
- double baro_speed;
-
- double max_height;
- double max_acceleration;
- double max_speed;
-
- AltosGPS gps;
-
- double pad_lat;
- double pad_lon;
- double pad_alt;
-
- static final int MIN_PAD_SAMPLES = 10;
-
- int npad;
- int ngps;
- int gps_waiting;
- boolean gps_ready;
-
- AltosGreatCircle from_pad;
- double elevation; /* from pad */
- double range; /* total distance */
-
- double gps_height;
-
- int speak_tick;
- double speak_altitude;
-
-
- void init (AltosRecord cur, AltosState prev_state) {
- int i;
- AltosRecord prev;
-
- data = cur;
-
- ground_altitude = data.ground_altitude();
- height = data.filtered_altitude() - ground_altitude;
-
- report_time = System.currentTimeMillis();
-
- acceleration = data.acceleration();
- speed = data.accel_speed();
- temperature = data.temperature();
- drogue_sense = data.drogue_voltage();
- main_sense = data.main_voltage();
- battery = data.battery_voltage();
- tick = data.tick;
- state = data.state;
-
- if (prev_state != null) {
-
- /* Preserve any existing gps data */
- npad = prev_state.npad;
- ngps = prev_state.ngps;
- gps = prev_state.gps;
- pad_lat = prev_state.pad_lat;
- pad_lon = prev_state.pad_lon;
- pad_alt = prev_state.pad_alt;
- max_height = prev_state.max_height;
- max_acceleration = prev_state.max_acceleration;
- max_speed = prev_state.max_speed;
-
- /* make sure the clock is monotonic */
- while (tick < prev_state.tick)
- tick += 65536;
-
- time_change = (tick - prev_state.tick) / 100.0;
-
- /* compute barometric speed */
-
- double height_change = height - prev_state.height;
- if (time_change > 0)
- baro_speed = (prev_state.baro_speed * 3 + (height_change / time_change)) / 4.0;
- else
- baro_speed = prev_state.baro_speed;
- } else {
- npad = 0;
- ngps = 0;
- gps = null;
- baro_speed = 0;
- time_change = 0;
- }
-
- if (state == Altos.ao_flight_pad) {
-
- /* Track consecutive 'good' gps reports, waiting for 10 of them */
- if (data.gps != null && data.gps.locked && data.gps.nsat >= 4)
- npad++;
- else
- npad = 0;
-
- /* Average GPS data while on the pad */
- if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
- if (ngps > 1) {
- /* filter pad position */
- pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0;
- pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0;
- pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0;
- } else {
- pad_lat = data.gps.lat;
- pad_lon = data.gps.lon;
- pad_alt = data.gps.alt;
- }
- ngps++;
- }
- }
-
- gps_waiting = MIN_PAD_SAMPLES - npad;
- if (gps_waiting < 0)
- gps_waiting = 0;
-
- gps_ready = gps_waiting == 0;
-
- ascent = (Altos.ao_flight_boost <= state &&
- state <= Altos.ao_flight_coast);
-
- /* Only look at accelerometer data on the way up */
- if (ascent && acceleration > max_acceleration)
- max_acceleration = acceleration;
- if (ascent && speed > max_speed)
- max_speed = speed;
-
- if (height > max_height)
- max_height = height;
- if (data.gps != null) {
- if (gps == null || !gps.locked || data.gps.locked)
- gps = data.gps;
- if (ngps > 0 && gps.locked) {
- from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon);
- }
- }
- elevation = 0;
- range = -1;
- if (ngps > 0) {
- gps_height = gps.alt - pad_alt;
- if (from_pad != null) {
- elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI;
- range = Math.sqrt(height * height + from_pad.distance * from_pad.distance);
- }
- } else {
- gps_height = 0;
- }
- }
-
- public AltosState(AltosRecord cur) {
- init(cur, null);
- }
-
- public AltosState (AltosRecord cur, AltosState prev) {
- init(cur, prev);
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.util.HashMap;
-
-/*
- * Telemetry data contents
- */
-
-
-/*
- * The telemetry data stream is a bit of a mess at present, with no consistent
- * formatting. In particular, the GPS data is formatted for viewing instead of parsing.
- * However, the key feature is that every telemetry line contains all of the information
- * necessary to describe the current rocket state, including the calibration values
- * for accelerometer and barometer.
- *
- * GPS unlocked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \
- * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \
- * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30
- *
- * GPS locked:
- *
- * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \
- * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \
- * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
- * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \
- * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \
- * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26
- */
-
-public class AltosTelemetry extends AltosRecord {
- public AltosTelemetry(String line) throws ParseException, AltosCRCException {
- String[] words = line.split("\\s+");
- int i = 0;
-
- if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
- i += 2;
- AltosParse.word(words[i++], "RSSI");
- rssi = AltosParse.parse_int(words[i++]);
- throw new AltosCRCException(rssi);
- }
- if (words[i].equals("CALL")) {
- version = 0;
- } else {
- AltosParse.word (words[i++], "VERSION");
- version = AltosParse.parse_int(words[i++]);
- }
-
- AltosParse.word (words[i++], "CALL");
- callsign = words[i++];
-
- AltosParse.word (words[i++], "SERIAL");
- serial = AltosParse.parse_int(words[i++]);
-
- if (version >= 2) {
- AltosParse.word (words[i++], "FLIGHT");
- flight = AltosParse.parse_int(words[i++]);
- } else
- flight = 0;
-
- AltosParse.word(words[i++], "RSSI");
- rssi = AltosParse.parse_int(words[i++]);
-
- /* Older telemetry data had mis-computed RSSI value */
- if (version <= 2)
- rssi = (rssi + 74) / 2 - 74;
-
- AltosParse.word(words[i++], "STATUS");
- status = AltosParse.parse_hex(words[i++]);
-
- AltosParse.word(words[i++], "STATE");
- state = Altos.state(words[i++]);
-
- tick = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "a:");
- accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "p:");
- pres = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "t:");
- temp = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "v:");
- batt = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "d:");
- drogue = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "m:");
- main = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fa:");
- flight_accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "ga:");
- ground_accel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fv:");
- flight_vel = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "fp:");
- flight_pres = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "gp:");
- ground_pres = AltosParse.parse_int(words[i++]);
-
- if (version >= 1) {
- AltosParse.word(words[i++], "a+:");
- accel_plus_g = AltosParse.parse_int(words[i++]);
-
- AltosParse.word(words[i++], "a-:");
- accel_minus_g = AltosParse.parse_int(words[i++]);
- } else {
- accel_plus_g = ground_accel;
- accel_minus_g = ground_accel + 530;
- }
-
- gps = new AltosGPS(words, i, version);
- }
-}
+++ /dev/null
-/*
- * 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.io.*;
-import java.util.*;
-import java.text.*;
-
-public class AltosTelemetryIterable extends AltosRecordIterable {
- LinkedList<AltosRecord> records;
-
- public Iterator<AltosRecord> iterator () {
- return records.iterator();
- }
-
- public AltosTelemetryIterable (FileInputStream input) {
- boolean saw_boost = false;
- int current_tick = 0;
- int boost_tick = 0;
-
- records = new LinkedList<AltosRecord> ();
-
- try {
- for (;;) {
- String line = AltosRecord.gets(input);
- if (line == null) {
- break;
- }
- try {
- AltosTelemetry record = new AltosTelemetry(line);
- if (record == null)
- break;
- if (records.isEmpty()) {
- current_tick = record.tick;
- } else {
- int tick = record.tick | (current_tick & ~ 0xffff);
- if (tick < current_tick - 0x1000)
- tick += 0x10000;
- current_tick = tick;
- record.tick = current_tick;
- }
- if (!saw_boost && record.state >= Altos.ao_flight_boost)
- {
- saw_boost = true;
- boost_tick = record.tick;
- }
- records.add(record);
- } catch (ParseException pe) {
- System.out.printf("parse exception %s\n", pe.getMessage());
- } catch (AltosCRCException ce) {
- System.out.printf("crc error\n");
- }
- }
- } catch (IOException io) {
- System.out.printf("io exception\n");
- }
-
- /* adjust all tick counts to be relative to boost time */
- for (AltosRecord r : this)
- r.time = (r.tick - boost_tick) / 100.0;
-
- try {
- input.close();
- } catch (IOException ie) {
- }
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.io.*;
-import java.util.concurrent.*;
-
-class AltosTelemetryReader extends AltosFlightReader {
- AltosDevice device;
- AltosSerial serial;
- AltosLog log;
-
- LinkedBlockingQueue<AltosLine> telem;
-
- AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException {
- AltosLine l = telem.take();
- if (l.line == null)
- throw new IOException("IO error");
- return new AltosTelemetry(l.line);
- }
-
- void close(boolean interrupted) {
- serial.remove_monitor(telem);
- log.close();
- serial.close();
- }
-
- void set_channel(int channel) {
- serial.set_channel(channel);
- AltosPreferences.set_channel(device.getSerial(), channel);
- }
-
- public AltosTelemetryReader (AltosDevice in_device)
- throws FileNotFoundException, AltosSerialInUseException, IOException {
- device = in_device;
- serial = new AltosSerial(device);
- log = new AltosLog(serial);
- name = device.toShortString();
-
- telem = new LinkedBlockingQueue<AltosLine>();
- serial.set_radio();
- serial.add_monitor(telem);
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
-<plist version="0.9">
-<dict>
- <key>CFBundleName</key>
- <string>altosui</string>
- <key>CFBundleVersion</key>
- <string>100.0</string>
- <key>CFBundleAllowMixedLocalizations</key>
- <string>true</string>
- <key>CFBundleExecutable</key>
- <string>JavaApplicationStub</string>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleGetInfoString</key>
- <string>AltOS UI version 0.7</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleIconFile</key>
- <string>AltosUIIcon.icns</string>
- <key>Java</key>
- <dict>
- <key>MainClass</key>
- <string>altosui.AltosUI</string>
- <key>JVMVersion</key>
- <string>1.5+</string>
- <key>ClassPath</key>
- <array>
- <string>$JAVAROOT/altosui.jar</string>
- <string>$JAVAROOT/freetts.jar</string>
- </array>
- </dict>
-</dict>
-</plist>
+++ /dev/null
-/*
- * 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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.prefs.*;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import libaltosJNI.*;
-
-public class AltosUI extends JFrame {
- public AltosVoice voice = new AltosVoice();
-
- public static boolean load_library(Frame frame) {
- if (!AltosDevice.load_library()) {
- JOptionPane.showMessageDialog(frame,
- String.format("No AltOS library in \"%s\"",
- System.getProperty("java.library.path","<undefined>")),
- "Cannot load device access library",
- JOptionPane.ERROR_MESSAGE);
- return false;
- }
- return true;
- }
-
- void telemetry_window(AltosDevice device) {
- try {
- AltosFlightReader reader = new AltosTelemetryReader(device);
- if (reader != null)
- new AltosFlightUI(voice, reader, device.getSerial());
- } catch (FileNotFoundException ee) {
- JOptionPane.showMessageDialog(AltosUI.this,
- String.format("Cannot open device \"%s\"",
- device.toShortString()),
- "Cannot open target device",
- JOptionPane.ERROR_MESSAGE);
- } catch (AltosSerialInUseException si) {
- JOptionPane.showMessageDialog(AltosUI.this,
- String.format("Device \"%s\" already in use",
- device.toShortString()),
- "Device in use",
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException ee) {
- JOptionPane.showMessageDialog(AltosUI.this,
- device.toShortString(),
- "Unkonwn I/O error",
- JOptionPane.ERROR_MESSAGE);
- }
- }
-
- Container pane;
- GridBagLayout gridbag;
-
- JButton addButton(int x, int y, String label) {
- GridBagConstraints c;
- JButton b;
-
- c = new GridBagConstraints();
- c.gridx = x; c.gridy = y;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 1;
- c.weighty = 1;
- b = new JButton(label);
-
- Dimension ps = b.getPreferredSize();
-
- gridbag.setConstraints(b, c);
- add(b, c);
- return b;
- }
-
- public AltosUI() {
-
- load_library(null);
-
- java.net.URL imgURL = AltosUI.class.getResource("/altus-metrum-16x16.jpg");
- if (imgURL != null)
- setIconImage(new ImageIcon(imgURL).getImage());
-
- AltosPreferences.init(this);
-
- pane = getContentPane();
- gridbag = new GridBagLayout();
- pane.setLayout(gridbag);
-
- JButton b;
-
- b = addButton(0, 0, "Monitor Flight");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ConnectToDevice();
- }
- });
- b = addButton(1, 0, "Save Flight Data");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- SaveFlightData();
- }
- });
- b = addButton(2, 0, "Replay Flight");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- Replay();
- }
- });
- b = addButton(3, 0, "Graph Data");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- GraphData();
- }
- });
- b = addButton(4, 0, "Export Data");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ExportData();
- }
- });
- b = addButton(0, 1, "Configure TeleMetrum");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ConfigureTeleMetrum();
- }
- });
-
- b = addButton(1, 1, "Configure AltosUI");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ConfigureAltosUI();
- }
- });
-
- b = addButton(2, 1, "Flash Image");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- FlashImage();
- }
- });
-
- b = addButton(3, 1, "Fire Igniter");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- FireIgniter();
- }
- });
-
- b = addButton(4, 1, "Quit");
- b.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- System.exit(0);
- }
- });
-
- setTitle("AltOS");
-
- pane.doLayout();
- pane.validate();
-
- doLayout();
- validate();
-
- setVisible(true);
-
- Insets i = getInsets();
- Dimension ps = rootPane.getPreferredSize();
- ps.width += i.left + i.right;
- ps.height += i.top + i.bottom;
- setPreferredSize(ps);
- setSize(ps);
- setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- System.exit(0);
- }
- });
- }
-
- private void ConnectToDevice() {
- AltosDevice device = AltosDeviceDialog.show(AltosUI.this,
- AltosDevice.product_basestation);
-
- if (device != null)
- telemetry_window(device);
- }
-
- void ConfigureCallsign() {
- String result;
- result = JOptionPane.showInputDialog(AltosUI.this,
- "Configure Callsign",
- AltosPreferences.callsign());
- if (result != null)
- AltosPreferences.set_callsign(result);
- }
-
- void ConfigureTeleMetrum() {
- new AltosConfig(AltosUI.this);
- }
-
- void FlashImage() {
- new AltosFlashUI(AltosUI.this);
- }
-
- void FireIgniter() {
- new AltosIgniteUI(AltosUI.this);
- }
-
- /*
- * Replay a flight from telemetry data
- */
- private void Replay() {
- AltosDataChooser chooser = new AltosDataChooser(
- AltosUI.this);
-
- AltosRecordIterable iterable = chooser.runDialog();
- if (iterable != null) {
- AltosFlightReader reader = new AltosReplayReader(iterable.iterator(),
- chooser.filename());
- new AltosFlightUI(voice, reader);
- }
- }
-
- /* Connect to TeleMetrum, either directly or through
- * a TeleDongle over the packet link
- */
- private void SaveFlightData() {
- new AltosEepromDownload(AltosUI.this);
- }
-
- /* Load a flight log file and write out a CSV file containing
- * all of the data in standard units
- */
-
- private void ExportData() {
- AltosDataChooser chooser;
- chooser = new AltosDataChooser(this);
- AltosRecordIterable record_reader = chooser.runDialog();
- if (record_reader == null)
- return;
- new AltosCSVUI(AltosUI.this, record_reader, chooser.file());
- }
-
- /* Load a flight log CSV file and display a pretty graph.
- */
-
- private void GraphData() {
- AltosDataChooser chooser;
- chooser = new AltosDataChooser(this);
- AltosRecordIterable record_reader = chooser.runDialog();
- if (record_reader == null)
- return;
- new AltosGraphUI(record_reader);
- }
-
- private void ConfigureAltosUI() {
- new AltosConfigureUI(AltosUI.this, voice);
- }
-
- static AltosRecordIterable open_logfile(String filename) {
- File file = new File (filename);
- try {
- FileInputStream in;
-
- in = new FileInputStream(file);
- if (filename.endsWith("eeprom"))
- return new AltosEepromIterable(in);
- else
- return new AltosTelemetryIterable(in);
- } catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
- return null;
- }
- }
-
- static AltosWriter open_csv(String filename) {
- File file = new File (filename);
- try {
- return new AltosCSV(file);
- } catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
- return null;
- }
- }
-
- static AltosWriter open_kml(String filename) {
- File file = new File (filename);
- try {
- return new AltosKML(file);
- } catch (FileNotFoundException fe) {
- System.out.printf("Cannot open '%s'\n", filename);
- return null;
- }
- }
-
- static final int process_csv = 1;
- static final int process_kml = 2;
-
- static void process_file(String input, int process) {
- AltosRecordIterable iterable = open_logfile(input);
- if (iterable == null)
- return;
- if (process == 0)
- process = process_csv;
- if ((process & process_csv) != 0) {
- String output = Altos.replace_extension(input,".csv");
- System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
- if (input.equals(output)) {
- System.out.printf("Not processing '%s'\n", input);
- } else {
- AltosWriter writer = open_csv(output);
- if (writer != null) {
- writer.write(iterable);
- writer.close();
- }
- }
- }
- if ((process & process_kml) != 0) {
- String output = Altos.replace_extension(input,".kml");
- System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
- if (input.equals(output)) {
- System.out.printf("Not processing '%s'\n", input);
- } else {
- AltosWriter writer = open_kml(output);
- if (writer == null)
- return;
- writer.write(iterable);
- writer.close();
- }
- }
- }
-
- public static void main(final String[] args) {
- int process = 0;
- /* Handle batch-mode */
- if (args.length == 1 && args[0].equals("--help")) {
- System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
- System.out.printf(" Options:\n");
- System.out.printf(" --fetchmaps <lat> <lon>\tpre-fetch maps for site map view\n");
- System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
- System.out.printf(" --csv\tgenerate comma separated output for spreadsheets, etc\n");
- System.out.printf(" --kml\tgenerate KML output for use with Google Earth\n");
- } else if (args.length == 3 && args[0].equals("--fetchmaps")) {
- double lat = Double.parseDouble(args[1]);
- double lon = Double.parseDouble(args[2]);
- AltosSiteMap.prefetchMaps(lat, lon, 5, 5);
- } else if (args.length == 2 && args[0].equals("--replay")) {
- String filename = args[1];
- FileInputStream in;
- try {
- in = new FileInputStream(filename);
- } catch (Exception e) {
- System.out.printf("Failed to open file '%s'\n", filename);
- return;
- }
- AltosRecordIterable recs;
- AltosReplayReader reader;
- if (filename.endsWith("eeprom")) {
- recs = new AltosEepromIterable(in);
- } else {
- recs = new AltosTelemetryIterable(in);
- }
- reader = new AltosReplayReader(recs.iterator(), filename);
- AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader);
- flight_ui.set_exit_on_close();
- return;
- } else if (args.length > 0) {
- for (int i = 0; i < args.length; i++) {
- if (args[i].equals("--kml"))
- process |= process_kml;
- else if (args[i].equals("--csv"))
- process |= process_csv;
- else
- process_file(args[i], process);
- }
- } else {
- AltosUI altosui = new AltosUI();
- altosui.setVisible(true);
-
- AltosDevice[] devices = AltosDevice.list(AltosDevice.product_basestation);
- for (int i = 0; i < devices.length; i++)
- altosui.telemetry_window(devices[i]);
- }
- }
-}
+++ /dev/null
-/*
- * 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 com.sun.speech.freetts.Voice;
-import com.sun.speech.freetts.VoiceManager;
-import com.sun.speech.freetts.audio.JavaClipAudioPlayer;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class AltosVoice implements Runnable {
- VoiceManager voice_manager;
- Voice voice;
- LinkedBlockingQueue<String> phrases;
- Thread thread;
- boolean busy;
-
- final static String voice_name = "kevin16";
-
- public void run() {
- try {
- for (;;) {
- String s = phrases.take();
- voice.speak(s);
- synchronized(this) {
- if (phrases.isEmpty()) {
- busy = false;
- notifyAll();
- }
- }
- }
- } catch (InterruptedException e) {
- }
- }
-
- public synchronized void drain() throws InterruptedException {
- while (busy)
- wait();
- }
-
- public void speak_always(String s) {
- try {
- if (voice != null) {
- synchronized(this) {
- busy = true;
- phrases.put(s);
- }
- }
- } catch (InterruptedException e) {
- }
- }
-
- public void speak(String s) {
- if (AltosPreferences.voice())
- speak_always(s);
- }
-
- public void speak(String format, Object... parameters) {
- speak(String.format(format, parameters));
- }
-
- public AltosVoice () {
- busy = false;
- voice_manager = VoiceManager.getInstance();
- voice = voice_manager.getVoice(voice_name);
- if (voice != null) {
- voice.allocate();
- phrases = new LinkedBlockingQueue<String> ();
- thread = new Thread(this);
- thread.start();
- } else {
- System.out.printf("Voice manager failed to open %s\n", voice_name);
- Voice[] voices = voice_manager.getVoices();
- System.out.printf("Available voices:\n");
- for (int i = 0; i < voices.length; i++) {
- System.out.println(" " + voices[i].getName()
- + " (" + voices[i].getDomain() + " domain)");
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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.text.*;
-import java.util.*;
-
-public interface AltosWriter {
-
- public void write(AltosRecord record);
-
- public void write(AltosRecordIterable iterable);
-
- public void close();
-}
+++ /dev/null
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * 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.awt.*;
-import java.awt.image.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.event.MouseInputAdapter;
-import javax.imageio.ImageIO;
-import javax.swing.table.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-
-class GrabNDrag extends MouseInputAdapter {
- private JComponent scroll;
- private Point startPt = new Point();
-
- public GrabNDrag(JComponent scroll) {
- this.scroll = scroll;
- scroll.addMouseMotionListener(this);
- scroll.addMouseListener(this);
- scroll.setAutoscrolls(true);
- }
-
- public void mousePressed(MouseEvent e) {
- startPt.setLocation(e.getPoint());
- }
- public void mouseDragged(MouseEvent e) {
- int xd = e.getX() - startPt.x;
- int yd = e.getY() - startPt.y;
-
- Rectangle r = scroll.getVisibleRect();
- r.x -= xd;
- r.y -= yd;
- scroll.scrollRectToVisible(r);
- }
-}
+++ /dev/null
-#\r
-# InstDrv Example, (c) 2003 Jan Kiszka (Jan Kiszka@web.de)\r
-#\r
-\r
-Name "InstDrv.dll test"\r
-\r
-OutFile "InstDrv-Test.exe"\r
-\r
-ShowInstDetails show\r
-\r
-ComponentText "InstDrv Plugin Usage Example"\r
-\r
-Page components\r
-Page instfiles\r
-\r
-Section "Install a Driver" InstDriver\r
- InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
- Pop $0\r
- DetailPrint "InitDriverSetup: $0"\r
-\r
- InstDrv::DeleteOemInfFiles /NOUNLOAD\r
- Pop $0\r
- DetailPrint "DeleteOemInfFiles: $0"\r
- StrCmp $0 "00000000" PrintInfNames ContInst1\r
-\r
- PrintInfNames:\r
- Pop $0\r
- DetailPrint "Deleted $0"\r
- Pop $0\r
- DetailPrint "Deleted $0"\r
-\r
- ContInst1:\r
- InstDrv::CreateDevice /NOUNLOAD\r
- Pop $0\r
- DetailPrint "CreateDevice: $0"\r
-\r
- SetOutPath $TEMP\r
- File "ircomm2k.inf"\r
- File "ircomm2k.sys"\r
-\r
- InstDrv::InstallDriver /NOUNLOAD "$TEMP\ircomm2k.inf"\r
- Pop $0\r
- DetailPrint "InstallDriver: $0"\r
- StrCmp $0 "00000000" PrintReboot ContInst2\r
-\r
- PrintReboot:\r
- Pop $0\r
- DetailPrint "Reboot: $0"\r
-\r
- ContInst2:\r
- InstDrv::CountDevices\r
- Pop $0\r
- DetailPrint "CountDevices: $0"\r
-SectionEnd\r
-\r
-Section "Uninstall the driver again" UninstDriver\r
- InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"\r
- Pop $0\r
- DetailPrint "InitDriverSetup: $0"\r
-\r
- InstDrv::DeleteOemInfFiles /NOUNLOAD\r
- Pop $0\r
- DetailPrint "DeleteOemInfFiles: $0"\r
- StrCmp $0 "00000000" PrintInfNames ContUninst1\r
-\r
- PrintInfNames:\r
- Pop $0\r
- DetailPrint "Deleted $0"\r
- Pop $0\r
- DetailPrint "Deleted $0"\r
-\r
- ContUninst1:\r
- InstDrv::RemoveAllDevices\r
- Pop $0\r
- DetailPrint "RemoveAllDevices: $0"\r
- StrCmp $0 "00000000" PrintReboot ContUninst2\r
-\r
- PrintReboot:\r
- Pop $0\r
- DetailPrint "Reboot: $0"\r
-\r
- ContUninst2:\r
- Delete "$SYSDIR\system32\ircomm2k.sys"\r
-SectionEnd
\ No newline at end of file
+++ /dev/null
-/*\r
-\r
-InstDrv.dll - Installs or Removes Device Drivers\r
-\r
-Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
-\r
-This software is provided 'as-is', without any express or implied\r
-warranty. In no event will the authors be held liable for any damages\r
-arising from the use of this software.\r
-\r
-Permission is granted to anyone to use this software for any purpose,\r
-including commercial applications, and to alter it and redistribute\r
-it freely, subject to the following restrictions:\r
-\r
-1. The origin of this software must not be misrepresented; \r
- you must not claim that you wrote the original software.\r
- If you use this software in a product, an acknowledgment in the\r
- product documentation would be appreciated but is not required.\r
-2. Altered versions must be plainly marked as such,\r
- and must not be misrepresented as being the original software.\r
-3. This notice may not be removed or altered from any distribution.\r
-\r
-*/\r
-\r
-\r
-#include <windows.h>\r
-#include <setupapi.h>\r
-#include <newdev.h>\r
-#include "../exdll/exdll.h"\r
-\r
-\r
-char paramBuf[1024];\r
-GUID devClass;\r
-char hwIdBuf[1024];\r
-int initialized = 0;\r
-\r
-\r
-\r
-void* memset(void* dst, int val, unsigned int len)\r
-{\r
- while (len-- > 0)\r
- *((char *)dst)++ = val;\r
-\r
- return NULL;\r
-}\r
-\r
-\r
-\r
-void* memcpy(void* dst, const void* src, unsigned int len)\r
-{\r
- while (len-- > 0)\r
- *((char *)dst)++ = *((char *)src)++;\r
-\r
- return NULL;\r
-}\r
-\r
-\r
-\r
-int HexCharToInt(char c)\r
-{\r
- if ((c >= '0') && (c <= '9'))\r
- return c - '0';\r
- else if ((c >= 'a') && (c <= 'f'))\r
- return c - 'a' + 10;\r
- else if ((c >= 'A') && (c <= 'F'))\r
- return c - 'A' + 10;\r
- else\r
- return -1;\r
-}\r
-\r
-\r
-\r
-BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)\r
-{\r
- int i, val;\r
-\r
-\r
- for (i = width - 4; i >= 0; i -= 4)\r
- {\r
- val = HexCharToInt(*str++);\r
- if (val < 0)\r
- return FALSE;\r
- *(unsigned int *)valBuf += val << i;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-\r
-BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)\r
-{\r
- int i;\r
-\r
-\r
- memset(pGuid, 0, sizeof(GUID));\r
-\r
- if (*guidStr++ != '{')\r
- return FALSE;\r
-\r
- if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))\r
- return FALSE;\r
- guidStr += 8;\r
-\r
- if (*guidStr++ != '-')\r
- return FALSE;\r
-\r
- if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))\r
- return FALSE;\r
- guidStr += 4;\r
-\r
- if (*guidStr++ != '-')\r
- return FALSE;\r
-\r
- if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))\r
- return FALSE;\r
- guidStr += 4;\r
-\r
- if (*guidStr++ != '-')\r
- return FALSE;\r
-\r
- for (i = 0; i < 2; i++)\r
- {\r
- if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
- return FALSE;\r
- guidStr += 2;\r
- }\r
-\r
- if (*guidStr++ != '-')\r
- return FALSE;\r
-\r
- for (i = 2; i < 8; i++)\r
- {\r
- if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
- return FALSE;\r
- guidStr += 2;\r
- }\r
-\r
- if (*guidStr++ != '}')\r
- return FALSE;\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-\r
-DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)\r
-{\r
- DWORD buffersize = 0;\r
- LPTSTR buffer = NULL;\r
- DWORD dataType;\r
- DWORD result;\r
-\r
-\r
- while (1)\r
- {\r
- if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))\r
- {\r
- result = GetLastError();\r
- break;\r
- }\r
-\r
- GetDeviceRegistryProperty:\r
- if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,\r
- &dataType, (PBYTE)buffer, buffersize,\r
- &buffersize))\r
- {\r
- result = GetLastError();\r
-\r
- if (result == ERROR_INSUFFICIENT_BUFFER)\r
- {\r
- if (buffer != NULL)\r
- LocalFree(buffer);\r
-\r
- buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);\r
-\r
- if (buffer == NULL)\r
- break;\r
-\r
- goto GetDeviceRegistryProperty;\r
- }\r
- else if (result == ERROR_INVALID_DATA)\r
- continue; // ignore invalid entries\r
- else\r
- break; // break on other errors\r
- }\r
-\r
- if (lstrcmpi(buffer, hwIdBuf) == 0)\r
- {\r
- result = 0;\r
- break;\r
- }\r
- }\r
-\r
- if (buffer != NULL)\r
- LocalFree(buffer);\r
-\r
- return result;\r
-}\r
-\r
-\r
-\r
-DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,\r
- HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,\r
- DWORD *pIndex, DWORD flags)\r
-{\r
- DWORD result;\r
-\r
-\r
- *pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);\r
- if (*pDevInfoSet == INVALID_HANDLE_VALUE)\r
- return GetLastError();\r
-\r
- pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);\r
- *pIndex = 0;\r
-\r
- result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);\r
-\r
- if (result != 0)\r
- SetupDiDestroyDeviceInfoList(*pDevInfoSet);\r
-\r
- return result;\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::InitDriverSetup devClass drvHWID\r
- *\r
- * devClass - GUID of the driver's device setup class\r
- * drvHWID - Hardware ID of the supported device\r
- *\r
- * Return:\r
- * result - error message, empty on success\r
- */\r
-void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- EXDLL_INIT();\r
-\r
- /* convert class GUID */\r
- popstring(paramBuf);\r
-\r
- if (!StringToGUID(paramBuf, &devClass))\r
- {\r
- popstring(paramBuf);\r
- pushstring("Invalid GUID!");\r
- return;\r
- }\r
-\r
- /* get hardware ID */\r
- memset(hwIdBuf, 0, sizeof(hwIdBuf));\r
- popstring(hwIdBuf);\r
-\r
- initialized = 1;\r
- pushstring("");\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::CountDevices\r
- *\r
- * Return:\r
- * result - Number of installed devices the driver supports\r
- */\r
-void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- HDEVINFO devInfoSet;\r
- SP_DEVINFO_DATA devInfoData;\r
- int count = 0;\r
- char countBuf[16];\r
- DWORD index;\r
- DWORD result;\r
-\r
-\r
- EXDLL_INIT();\r
-\r
- if (!initialized)\r
- {\r
- pushstring("Fatal error!");\r
- return;\r
- }\r
-\r
- result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,\r
- &index, DIGCF_PRESENT);\r
- if (result != 0)\r
- {\r
- pushstring("0");\r
- return;\r
- }\r
-\r
- do\r
- {\r
- count++;\r
- } while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);\r
-\r
- SetupDiDestroyDeviceInfoList(devInfoSet);\r
-\r
- wsprintf(countBuf, "%d", count);\r
- pushstring(countBuf);\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::CreateDevice\r
- *\r
- * Return:\r
- * result - Windows error code\r
- */\r
-void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- HDEVINFO devInfoSet;\r
- SP_DEVINFO_DATA devInfoData;\r
- DWORD result = 0;\r
- char resultBuf[16];\r
-\r
-\r
- EXDLL_INIT();\r
-\r
- if (!initialized)\r
- {\r
- pushstring("Fatal error!");\r
- return;\r
- }\r
-\r
- devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);\r
- if (devInfoSet == INVALID_HANDLE_VALUE)\r
- {\r
- wsprintf(resultBuf, "%08X", GetLastError());\r
- pushstring(resultBuf);\r
- return;\r
- }\r
-\r
- devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r
- if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,\r
- hwndParent, DICD_GENERATE_ID, &devInfoData))\r
- {\r
- result = GetLastError();\r
- goto InstallCleanup;\r
- }\r
-\r
- if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,\r
- hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR))) \r
- {\r
- result = GetLastError();\r
- goto InstallCleanup;\r
- }\r
-\r
- if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))\r
- result = GetLastError();\r
-\r
- InstallCleanup:\r
- SetupDiDestroyDeviceInfoList(devInfoSet);\r
-\r
- wsprintf(resultBuf, "%08X", result);\r
- pushstring(resultBuf);\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::InstallDriver infPath\r
- *\r
- * Return:\r
- * result - Windows error code\r
- * reboot - non-zero if reboot is required\r
- */\r
-void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- char resultBuf[16];\r
- BOOL reboot;\r
-\r
-\r
- EXDLL_INIT();\r
- popstring(paramBuf);\r
-\r
- if (!initialized)\r
- {\r
- pushstring("Fatal error!");\r
- return;\r
- }\r
-\r
- if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,\r
- INSTALLFLAG_FORCE, &reboot))\r
- {\r
- wsprintf(resultBuf, "%08X", GetLastError());\r
- pushstring(resultBuf);\r
- }\r
- else\r
- {\r
- wsprintf(resultBuf, "%d", reboot);\r
- pushstring(resultBuf);\r
- pushstring("00000000");\r
- }\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::DeleteOemInfFiles\r
- *\r
- * Return:\r
- * result - Windows error code\r
- * oeminf - Path of the deleted devices setup file (oemXX.inf)\r
- * oempnf - Path of the deleted devices setup file (oemXX.pnf)\r
- */\r
-void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- HDEVINFO devInfo;\r
- SP_DEVINFO_DATA devInfoData;\r
- SP_DRVINFO_DATA drvInfoData;\r
- SP_DRVINFO_DETAIL_DATA drvInfoDetail;\r
- DWORD index;\r
- DWORD result;\r
- char resultBuf[16];\r
-\r
-\r
- if (!initialized)\r
- {\r
- pushstring("Fatal error!");\r
- return;\r
- }\r
-\r
- result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
- if (result != 0)\r
- goto Cleanup1;\r
-\r
- if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))\r
- {\r
- result = GetLastError();\r
- goto Cleanup2;\r
- }\r
-\r
- drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);\r
- drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);\r
-\r
- if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))\r
- {\r
- result = GetLastError();\r
- goto Cleanup3;\r
- }\r
-\r
- if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,\r
- &drvInfoDetail, sizeof(drvInfoDetail), NULL))\r
- {\r
- result = GetLastError();\r
-\r
- if (result != ERROR_INSUFFICIENT_BUFFER)\r
- goto Cleanup3;\r
-\r
- result = 0;\r
- }\r
-\r
- pushstring(drvInfoDetail.InfFileName);\r
- if (!DeleteFile(drvInfoDetail.InfFileName))\r
- result = GetLastError();\r
- else\r
- {\r
- index = lstrlen(drvInfoDetail.InfFileName);\r
- if (index > 3)\r
- {\r
- lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");\r
- pushstring(drvInfoDetail.InfFileName);\r
- if (!DeleteFile(drvInfoDetail.InfFileName))\r
- result = GetLastError();\r
- }\r
- }\r
-\r
- Cleanup3:\r
- SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);\r
-\r
- Cleanup2:\r
- SetupDiDestroyDeviceInfoList(devInfo);\r
-\r
- Cleanup1:\r
- wsprintf(resultBuf, "%08X", result);\r
- pushstring(resultBuf);\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::RemoveAllDevices\r
- *\r
- * Return:\r
- * result - Windows error code\r
- * reboot - non-zero if reboot is required\r
- */\r
-void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- HDEVINFO devInfo;\r
- SP_DEVINFO_DATA devInfoData;\r
- DWORD index;\r
- DWORD result;\r
- char resultBuf[16];\r
- BOOL reboot = FALSE;\r
- SP_DEVINSTALL_PARAMS instParams;\r
-\r
-\r
- EXDLL_INIT();\r
-\r
- if (!initialized)\r
- {\r
- pushstring("Fatal error!");\r
- return;\r
- }\r
-\r
- result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
- if (result != 0)\r
- goto Cleanup1;\r
-\r
- do\r
- {\r
- if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))\r
- {\r
- result = GetLastError();\r
- break;\r
- }\r
-\r
- instParams.cbSize = sizeof(instParams);\r
- if (!reboot &&\r
- SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&\r
- ((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))\r
- {\r
- reboot = TRUE;\r
- }\r
-\r
- result = FindNextDevice(devInfo, &devInfoData, &index);\r
- } while (result == 0);\r
-\r
- SetupDiDestroyDeviceInfoList(devInfo);\r
-\r
- Cleanup1:\r
- if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))\r
- {\r
- wsprintf(resultBuf, "%d", reboot);\r
- pushstring(resultBuf);\r
- pushstring("00000000");\r
- }\r
- else\r
- {\r
- wsprintf(resultBuf, "%08X", result);\r
- pushstring(resultBuf);\r
- }\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::StartSystemService serviceName\r
- *\r
- * Return:\r
- * result - Windows error code\r
- */\r
-void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- SC_HANDLE managerHndl;\r
- SC_HANDLE svcHndl;\r
- SERVICE_STATUS svcStatus;\r
- DWORD oldCheckPoint;\r
- DWORD result;\r
- char resultBuf[16];\r
-\r
-\r
- EXDLL_INIT();\r
- popstring(paramBuf);\r
-\r
- managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
- if (managerHndl == NULL)\r
- {\r
- result = GetLastError();\r
- goto Cleanup1;\r
- }\r
-\r
- svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);\r
- if (svcHndl == NULL)\r
- {\r
- result = GetLastError();\r
- goto Cleanup2;\r
- }\r
-\r
- if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))\r
- {\r
- result = GetLastError();\r
- goto Cleanup3;\r
- }\r
-\r
- while (svcStatus.dwCurrentState == SERVICE_START_PENDING)\r
- {\r
- oldCheckPoint = svcStatus.dwCheckPoint;\r
-\r
- Sleep(svcStatus.dwWaitHint);\r
-\r
- if (!QueryServiceStatus(svcHndl, &svcStatus))\r
- {\r
- result = GetLastError();\r
- break;\r
- }\r
-\r
- if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
- {\r
- if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&\r
- (svcStatus.dwWin32ExitCode != 0))\r
- result = svcStatus.dwWin32ExitCode;\r
- else\r
- result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
- }\r
- }\r
-\r
- if (svcStatus.dwCurrentState == SERVICE_RUNNING)\r
- result = 0;\r
-\r
- Cleanup3:\r
- CloseServiceHandle(svcHndl);\r
-\r
- Cleanup2:\r
- CloseServiceHandle(managerHndl);\r
-\r
- Cleanup1:\r
- wsprintf(resultBuf, "%08X", result);\r
- pushstring(resultBuf);\r
-}\r
-\r
-\r
-\r
-/*\r
- * InstDrv::StopSystemService serviceName\r
- *\r
- * Return:\r
- * result - Windows error code\r
- */\r
-void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
-{\r
- SC_HANDLE managerHndl;\r
- SC_HANDLE svcHndl;\r
- SERVICE_STATUS svcStatus;\r
- DWORD oldCheckPoint;\r
- DWORD result;\r
- char resultBuf[16];\r
-\r
-\r
- EXDLL_INIT();\r
- popstring(paramBuf);\r
-\r
- managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
- if (managerHndl == NULL)\r
- {\r
- result = GetLastError();\r
- goto Cleanup1;\r
- }\r
-\r
- svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);\r
- if (svcHndl == NULL)\r
- {\r
- result = GetLastError();\r
- goto Cleanup2;\r
- }\r
-\r
- if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))\r
- {\r
- result = GetLastError();\r
- goto Cleanup3;\r
- }\r
-\r
- while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)\r
- {\r
- oldCheckPoint = svcStatus.dwCheckPoint;\r
-\r
- Sleep(svcStatus.dwWaitHint);\r
-\r
- if (!QueryServiceStatus(svcHndl, &svcStatus))\r
- {\r
- result = GetLastError();\r
- break;\r
- }\r
-\r
- if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
- {\r
- result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
- break;\r
- }\r
- }\r
-\r
- if (svcStatus.dwCurrentState == SERVICE_STOPPED)\r
- result = 0;\r
-\r
- Cleanup3:\r
- CloseServiceHandle(svcHndl);\r
-\r
- Cleanup2:\r
- CloseServiceHandle(managerHndl);\r
-\r
- Cleanup1:\r
- wsprintf(resultBuf, "%08X", result);\r
- pushstring(resultBuf);\r
-}\r
-\r
-\r
-\r
-BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)\r
-{\r
- return TRUE;\r
-}\r
+++ /dev/null
-# Microsoft Developer Studio Project File - Name="InstDrv" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** NICHT BEARBEITEN **\r
-\r
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
-\r
-CFG=InstDrv - Win32 Debug\r
-!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE\r
-!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "InstDrv.mak".\r
-!MESSAGE \r
-!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben\r
-!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "InstDrv.mak" CFG="InstDrv - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Für die Konfiguration stehen zur Auswahl:\r
-!MESSAGE \r
-!MESSAGE "InstDrv - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE "InstDrv - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-MTL=midl.exe\r
-RSC=rc.exe\r
-\r
-!IF "$(CFG)" == "InstDrv - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release"\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 1\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O1 /I "C:\Programme\WINDDK\3790\inc\ddk\w2k" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /FD /c\r
-# SUBTRACT CPP /YX\r
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x407 /d "NDEBUG"\r
-# ADD RSC /l 0x407 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib setupapi.lib newdev.lib /nologo /entry:"_DllMainCRTStartup" /dll /machine:I386 /nodefaultlib /out:"../../Plugins/InstDrv.dll" /libpath:"C:\Programme\WINDDK\3790\lib\w2k\i386" /opt:nowin98\r
-# SUBTRACT LINK32 /pdb:none\r
-\r
-!ELSEIF "$(CFG)" == "InstDrv - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug"\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /GZ /c\r
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x407 /d "_DEBUG"\r
-# ADD RSC /l 0x407 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"_DllMainCRTStartup" /dll /debug /machine:I386 /pdbtype:sept\r
-# SUBTRACT LINK32 /nodefaultlib\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "InstDrv - Win32 Release"\r
-# Name "InstDrv - Win32 Debug"\r
-# Begin Group "Quellcodedateien"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\InstDrv.c\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header-Dateien"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# End Group\r
-# Begin Group "Ressourcendateien"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
+++ /dev/null
-Microsoft Developer Studio Workspace File, Format Version 6.00\r
-# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN!\r
-\r
-###############################################################################\r
-\r
-Project: "InstDrv"=.\InstDrv.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Global:\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<3>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
+++ /dev/null
-InstDrv.dll version 0.2 - Installs or Removes Device Drivers\r
-------------------------------------------------------------\r
-\r
-\r
-The plugin helps you to create NSIS scripts for installing device drivers or\r
-removing them again. It can count installed device instances, create new ones\r
-or delete all supported device. InstDrv works on Windows 2000 or later.\r
-\r
-\r
-\r
-InstDrv::InitDriverSetup devClass drvHWID\r
-Return: result\r
-\r
-To start processing a driver, first call this function. devClass is the GUID\r
-of the device class the driver supports, drvHWID is the device hardware ID. If\r
-you don't know what these terms mean, you may want to take a look at the\r
-Windows DDK. This function returns an empty string on success, otherwise an\r
-error message.\r
-\r
-InitDriverSetup has to be called every time after the plugin dll has been\r
-(re-)loaded, or if you want to switch to a different driver.\r
-\r
-\r
-\r
-InstDrv::CountDevices\r
-Return: number\r
-\r
-This call returns the number of installed and supported devices of the driver.\r
-\r
-\r
-\r
-InstDrv::CreateDevice\r
-Return: result\r
-\r
-To create a new deviced node which the driver has to support, use this\r
-function. You may even call it multiple times for more than one instance. The\r
-return value is the Windows error code (in hex). Use CreateDevice before\r
-installing or updating the driver itself.\r
-\r
-\r
-\r
-InstDrv::InstallDriver infPath\r
-Return: result\r
- reboot\r
-\r
-InstallDriver installs or updates a device driver as specified in the .inf\r
-setup script. It returns a Windows error code (in hex) and, on success, a flag\r
-signalling if a system reboot is required.\r
-\r
-\r
-\r
-InstDrv::DeleteOemInfFiles\r
-Return: result\r
- oeminf\r
- oempnf\r
-\r
-DeleteOemInfFiles tries to clean up the Windows inf directory by deleting the\r
-oemXX.inf and oemXX.pnf files associated with the drivers. It returns a\r
-Windows error code (in hex) and, on success, the names of the deleted files.\r
-This functions requires that at least one device instance is still present.\r
-So, call it before you remove the devices itself. You should also call it\r
-before updating a driver. This avoids that the inf directory gets slowly\r
-messed up with useless old setup scripts (which does NOT really accelerate\r
-Windows). The error code which comes up when no device is installed is\r
-"00000103".\r
-\r
-\r
-\r
-InstDrv::RemoveAllDevices\r
-Return: result\r
- reboot\r
-\r
-This functions deletes all devices instances the driver supported. It returns\r
-a Windows error code (in hex) and, on success, a flag signalling if the system\r
-needs to be rebooted. You additionally have to remove the driver binaries from\r
-the system paths.\r
-\r
-\r
-\r
-InstDrv::StartSystemService serviceName\r
-Return: result\r
-\r
-Call this function to start the provided system service. The function blocks\r
-until the service is started or the system reported a timeout. The return value\r
-is the Windows error code (in hex).\r
-\r
-\r
-\r
-InstDrv::StopSystemService serviceName\r
-Return: result\r
-\r
-This function tries to stop the provided system service. It blocks until the\r
-service has been shut down or the system reported a timeout. The return value\r
-is the Windows error code (in hex).\r
-\r
-\r
-\r
-Example.nsi\r
-\r
-The example script installs or removes the virtual COM port driver of IrCOMM2k\r
-(2.0.0-alpha8, see www.ircomm2k.de/english). The driver and its setup script\r
-are only included for demonstration purposes, they do not work without the\r
-rest of IrCOMM2k (but they also do not cause any harm).\r
-\r
-\r
-\r
-Building the Source Code\r
-\r
-To build the plugin from the source code, some include files and libraries\r
-which come with the Windows DDK are required.\r
-\r
-\r
-\r
-History\r
-\r
- 0.2 - fixed bug when calling InitDriverSetup the second time\r
- - added StartSystemService and StopSystemService\r
-\r
- 0.1 - first release\r
-\r
-\r
-\r
-License\r
-\r
-Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
-\r
-This software is provided 'as-is', without any express or implied\r
-warranty. In no event will the authors be held liable for any damages\r
-arising from the use of this software.\r
-\r
-Permission is granted to anyone to use this software for any purpose,\r
-including commercial applications, and to alter it and redistribute\r
-it freely, subject to the following restrictions:\r
-\r
-1. The origin of this software must not be misrepresented; \r
- you must not claim that you wrote the original software.\r
- If you use this software in a product, an acknowledgment in the\r
- product documentation would be appreciated but is not required.\r
-2. Altered versions must be plainly marked as such,\r
- and must not be misrepresented as being the original software.\r
-3. This notice may not be removed or altered from any distribution.\r
+++ /dev/null
-; IrCOMM2k.inf\r
-;\r
-; Installation file for the Virtual Infrared-COM-Port\r
-;\r
-; (c) Copyright 2001, 2002 Jan Kiszka \r
-;\r
-\r
-[Version]\r
-Signature="$Windows NT$"\r
-Provider=%JK%\r
-Class=Ports\r
-ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318}\r
-;DriverVer=03/26/2002,1.2.1.0\r
-\r
-[DestinationDirs]\r
-IrCOMM2k.Copy2Drivers = 12\r
-IrCOMM2k.Copy2Winnt = 10\r
-IrCOMM2k.Copy2System32 = 11\r
-IrCOMM2k.Copy2Help = 18\r
-\r
-\r
-;\r
-; Driver information\r
-;\r
-\r
-[Manufacturer]\r
-%JK% = JK.Mfg\r
-\r
-[JK.Mfg]\r
-%JK.DeviceDescIrCOMM% = IrCOMM2k_inst,IrCOMM2k\r
-\r
-\r
-;\r
-; General installation section\r
-;\r
-\r
-[IrCOMM2k_inst]\r
-CopyFiles = IrCOMM2k.Copy2Drivers ;,IrCOMM2k.Copy2System32,IrCOMM2k.Copy2Help,IrCOMM2k.Copy2Winnt\r
-;AddReg = IrCOMM2k_inst_AddReg\r
-\r
-\r
-;\r
-; File sections\r
-;\r
-\r
-[IrCOMM2k.Copy2Drivers]\r
-ircomm2k.sys,,,2\r
-\r
-;[IrCOMM2k.Copy2System32]\r
-;ircomm2k.exe,,,2\r
-;ircomm2k.dll,,,2\r
-\r
-;[IrCOMM2k.Copy2Help]\r
-;ircomm2k.hlp,,,2\r
-\r
-;[IrCOMM2k.Copy2Winnt]\r
-;IrCOMM2k-Setup.exe,Setup.exe,,2\r
-\r
-\r
-;\r
-; Service Installation\r
-;\r
-\r
-[IrCOMM2k_inst.Services]\r
-AddService = IrCOMM2k,0x00000002,IrCOMM2k_DriverService_Inst,IrCOMM2k_DriverEventLog_Inst\r
-;AddService = IrCOMM2kSvc,,IrCOMM2k_Service_Inst\r
-\r
-[IrCOMM2k_DriverService_Inst]\r
-DisplayName = %IrCOMM2k.DrvName%\r
-ServiceType = 1 ; SERVICE_KERNEL_DRIVER\r
-StartType = 3 ; SERVICE_DEMAND_START\r
-ErrorControl = 0 ; SERVICE_ERROR_IGNORE\r
-ServiceBinary = %12%\ircomm2k.sys\r
-\r
-;[IrCOMM2k_Service_Inst]\r
-;DisplayName = %IrCOMM2k.SvcName%\r
-;Description = %IrCOMM2k.SvcDesc%\r
-;ServiceType = 0x00000120 ; SERVICE_WIN32_SHARE_PROCESS, SERVICE_INTERACTIVE_PROCESS\r
-;StartType = 2 ; SERVICE_AUTO_START\r
-;ErrorControl = 0 ; SERVICE_ERROR_IGNORE\r
-;ServiceBinary = %11%\ircomm2k.exe\r
-;Dependencies = IrCOMM2k\r
-;AddReg = IrCOMM2kSvcAddReg\r
-\r
-\r
-[IrCOMM2k_inst.nt.HW]\r
-AddReg=IrCOMM2kHwAddReg\r
-\r
-[IrCOMM2kHwAddReg]\r
-HKR,,PortSubClass,REG_BINARY,0x00000001\r
-;HKR,,TimeoutScaling,REG_DWORD,0x00000001\r
-;HKR,,StatusLines,REG_DWORD,0x00000000\r
-\r
-;[IrCOMM2k_inst_AddReg]\r
-;HKR,,EnumPropPages32,,"ircomm2k.dll,IrCOMM2kPropPageProvider"\r
-;HKLM,%UNINSTALL_KEY%,DisplayIcon,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
-;HKLM,%UNINSTALL_KEY%,DisplayName,,"IrCOMM2k 1.2.1 "\r
-;HKLM,%UNINSTALL_KEY%,DisplayVersion,,"1.2.1"\r
-;HKLM,%UNINSTALL_KEY%,HelpLink,,"http://www.ircomm2k.de"\r
-;HKLM,%UNINSTALL_KEY%,Publisher,,%JK%\r
-;HKLM,%UNINSTALL_KEY%,UninstallString,0x00020000,"%windir%\IrCOMM2k-Setup.exe"\r
-\r
-;[IrCOMM2kSvcAddReg]\r
-;HKR,Parameters,ActiveConnectOnly,REG_DWORD,0x00000000\r
-\r
-\r
-[IrCOMM2k_DriverEventLog_Inst]\r
-AddReg = IrCOMM2k_DriverEventLog_AddReg\r
-\r
-[IrCOMM2k_DriverEventLog_AddReg]\r
-HKR,,EventMessageFile,REG_EXPAND_SZ,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\ircomm2k.sys"\r
-HKR,,TypesSupported,REG_DWORD,7\r
-\r
-\r
-[Strings]\r
-\r
-;\r
-; Non-Localizable Strings\r
-;\r
-\r
-REG_SZ = 0x00000000\r
-REG_MULTI_SZ = 0x00010000\r
-REG_EXPAND_SZ = 0x00020000\r
-REG_BINARY = 0x00000001\r
-REG_DWORD = 0x00010001\r
-SERVICEROOT = "System\CurrentControlSet\Services"\r
-UNINSTALL_KEY = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IrCOMM2k"\r
-\r
-;\r
-; Localizable Strings\r
-;\r
-\r
-JK = "Jan Kiszka"\r
-JK.DeviceDescIrCOMM = "Virtueller Infrarot-Kommunikationsanschluss"\r
-IrCOMM2k.DrvName = "Virtueller Infrarot-Kommunikationsanschluss"\r
-;IrCOMM2k.SvcName = "Virtueller Infrarot-Kommunikationsanschluß, Dienstprogramm"\r
-;IrCOMM2k.SvcDesc = "Bildet über Infarot einen Kommunikationsanschluß nach."\r
+++ /dev/null
-.SUFFIXES: .java .class
-
-CLASSPATH=classes:./*:/usr/share/java/*
-CLASSFILES=\
- Altos.class \
- AltosChannelMenu.class \
- AltosConfig.class \
- AltosConfigUI.class \
- AltosConvert.class \
- AltosCRCException.class \
- AltosCSV.class \
- AltosCSVUI.class \
- AltosDebug.class \
- AltosEepromDownload.class \
- AltosEepromMonitor.class \
- AltosEepromReader.class \
- AltosEepromRecord.class \
- AltosFile.class \
- AltosFlash.class \
- AltosFlashUI.class \
- AltosFlightInfoTableModel.class \
- AltosFlightStatusTableModel.class \
- AltosGPS.class \
- AltosGreatCircle.class \
- AltosHexfile.class \
- AltosLine.class \
- AltosInfoTable.class \
- AltosLog.class \
- AltosLogfileChooser.class \
- AltosParse.class \
- AltosPreferences.class \
- AltosReader.class \
- AltosRecord.class \
- AltosSerialMonitor.class \
- AltosSerial.class \
- AltosState.class \
- AltosStatusTable.class \
- AltosTelemetry.class \
- AltosTelemetryReader.class \
- AltosUI.class \
- AltosDevice.class \
- AltosDeviceDialog.class \
- AltosRomconfig.class \
- AltosRomconfigUI.class \
- AltosVoice.class
-
-JAVA_ICON=../../icon/altus-metrum-16x16.jpg
-WINDOWS_ICON=../../icon/altus-metrum.ico
-
-# where altosui.jar gets installed
-ALTOSLIB=/usr/share/java
-
-# where freetts.jar is to be found
-FREETTSLIB=/usr/share/java
-
-# all of the freetts files
-FREETTSJAR= \
- $(FREETTSLIB)/cmudict04.jar \
- $(FREETTSLIB)/cmulex.jar \
- $(FREETTSLIB)/cmu_time_awb.jar \
- $(FREETTSLIB)/cmutimelex.jar \
- $(FREETTSLIB)/cmu_us_kal.jar \
- $(FREETTSLIB)/en_us.jar \
- $(FREETTSLIB)/freetts.jar
-
-# The current hex files
-HEXLIB=../../src
-HEXFILES = \
- $(HEXLIB)/telemetrum-v1.0.ihx \
- $(HEXLIB)/teledongle-v0.2.ihx
-
-JAVAFLAGS=-Xlint:unchecked -Xlint:deprecation
-
-ALTOSUIJAR = altosui.jar
-FATJAR = fat/altosui.jar
-
-OS:=$(shell uname)
-
-LINUX_APP=altosui
-
-DARWIN_ZIP=Altos-Mac.zip
-
-WINDOWS_EXE=Altos-Windows.exe
-
-LINUX_TGZ=Altos-Linux.tgz
-
-all: altosui.jar $(LINUX_APP)
-fat: altosui.jar $(LINUX_APP) $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
-
-$(CLASSFILES):
-
-.java.class:
- javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
-
-altosui.jar: classes/images classes/altosui classes/libaltosJNI $(CLASSFILES) Manifest.txt
- cd ./classes && jar cfm ../$@ altosui/Manifest.txt images/* altosui/*.class libaltosJNI/*.class
-
-Manifest.txt: Makefile $(CLASSFILES)
- echo 'Main-Class: altosui.AltosUI' > $@
- echo "Class-Path: $(FREETTSLIB)/freetts.jar" >> $@
-
-classes/altosui:
- mkdir -p classes
- ln -sf .. classes/altosui
-
-classes/libaltosJNI:
- mkdir -p classes
- ln -sf ../../libaltos/libaltosJNI classes/libaltosJNI
-
-classes/images:
- mkdir -p classes/images
- ln -sf ../../$(JAVA_ICON) classes/images
-
-altosui:
- echo "#!/bin/sh" > $@
- echo "exec java -Djava.library.path=/usr/lib/altos -jar /usr/share/java/altosui.jar" >> $@
- chmod +x ./altosui
-
-fat/altosui:
- echo "#!/bin/sh" > $@
- echo 'ME=`which "$0"`' >> $@
- echo 'DIR=`dirname "$ME"`' >> $@
- echo 'exec java -Djava.library.path="$$DIR" -jar "$$DIR"/altosui.jar' >> $@
- chmod +x $@
-
-fat/altosui.jar: $(CLASSFILES) $(JAVA_ICON) fat/classes/Manifest.txt
- mkdir -p fat/classes
- test -L fat/classes/altosui || ln -sf ../.. fat/classes/altosui
- mkdir -p fat/classes/images
- cp $(JAVA_ICON) fat/classes/images
- test -L fat/classes/libaltosJNI || ln -sf ../../../libaltos/libaltosJNI fat/classes/libaltosJNI
- cd ./fat/classes && jar cfm ../../$@ Manifest.txt images/* altosui/*.class libaltosJNI/*.class
-
-fat/classes/Manifest.txt: $(CLASSFILES) Makefile
- mkdir -p fat/classes
- echo 'Main-Class: altosui.AltosUI' > $@
- echo "Class-Path: freetts.jar" >> $@
-
-install: altosui.jar altosui
- install -m 0644 altosui.jar $(DESTDIR)/usr/share/java/altosui.jar
- install -m 0644 altosui.1 $(DESTDIR)/usr/share/man/man1/altosui.1
- install altosui $(DESTDIR)/usr/bin/altosui
-
-clean:
- rm -f *.class altosui.jar
- rm -f AltosUI.app/Contents/Resources/Java/*
- rm -rf classes
- rm -rf windows linux
-
-distclean: clean
- rm -f $(DARWIN_ZIP) $(WINDOWS_EXE) $(LINUX_TGZ)
- rm -rf darwin fat
-
-FAT_FILES=$(FATJAR) $(FREETTSJAR) $(HEXFILES)
-
-LINUX_FILES=$(FAT_FILES) ../libaltos/libaltos.so fat/altosui
-$(LINUX_TGZ): $(LINUX_FILES)
- rm -f $@
- mkdir -p linux/AltOS
- rm -f linux/AltOS/*
- cp $(LINUX_FILES) linux/AltOS
- cd linux && tar czf ../$@ AltOS
-
-DARWIN_RESOURCES=$(FATJAR) $(FREETTSJAR) ../libaltos/libaltos.dylib
-DARWIN_EXTRA=$(HEXFILES)
-DARWIN_FILES=$(DARWIN_RESOURCES) $(DARWIN_EXTRA)
-
-$(DARWIN_ZIP): $(DARWIN_FILES)
- rm -f $@
- cp -a AltosUI.app darwin/
- mkdir -p darwin/AltosUI.app/Contents/Resources/Java
- cp $(DARWIN_RESOURCES) darwin/AltosUI.app/Contents/Resources/Java
- mkdir -p darwin/AltOS
- cp $(DARWIN_EXTRA) darwin/AltOS
- cd darwin && zip -r ../$@ AltosUI.app AltOS
-
-WINDOWS_FILES = $(FAT_FILES) ../libaltos/altos.dll ../../telemetrum.inf $(WINDOWS_ICON)
-
-$(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi
- rm -f $@
- mkdir -p windows/AltOS
- rm -f windows/AltOS/*
- cp $(WINDOWS_FILES) windows/AltOS
- makensis altos-windows.nsi
+++ /dev/null
-JAVAROOT=classes
-AM_JAVACFLAGS=-encoding UTF-8
-
-man_MANS=altosui.1
-
-altoslibdir=$(libdir)/altos
-
-CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../libaltos:$(FREETTS)/*:/usr/share/java/*"
-
-bin_SCRIPTS=altosui
-
-altosui_JAVA = \
- GrabNDrag.java \
- AltosAscent.java \
- AltosChannelMenu.java \
- AltosConfig.java \
- AltosConfigUI.java \
- AltosConfigureUI.java \
- AltosConvert.java \
- AltosCRCException.java \
- AltosCSV.java \
- AltosCSVUI.java \
- AltosDebug.java \
- AltosDescent.java \
- AltosDeviceDialog.java \
- AltosDevice.java \
- AltosDisplayThread.java \
- AltosEepromDownload.java \
- AltosEepromMonitor.java \
- AltosEepromIterable.java \
- AltosEepromRecord.java \
- AltosFile.java \
- AltosFlash.java \
- AltosFlashUI.java \
- AltosFlightDisplay.java \
- AltosFlightInfoTableModel.java \
- AltosFlightReader.java \
- AltosFlightStatus.java \
- AltosFlightUI.java \
- AltosGPS.java \
- AltosGreatCircle.java \
- AltosHexfile.java \
- Altos.java \
- AltosIgnite.java \
- AltosIgniteUI.java \
- AltosInfoTable.java \
- AltosKML.java \
- AltosLanded.java \
- AltosLed.java \
- AltosLights.java \
- AltosLine.java \
- AltosLog.java \
- AltosPad.java \
- AltosParse.java \
- AltosPreferences.java \
- AltosReader.java \
- AltosRecord.java \
- AltosRecordIterable.java \
- AltosTelemetryReader.java \
- AltosReplayReader.java \
- AltosRomconfig.java \
- AltosRomconfigUI.java \
- AltosSerial.java \
- AltosSerialInUseException.java \
- AltosSerialMonitor.java \
- AltosSiteMap.java \
- AltosSiteMapCache.java \
- AltosSiteMapTile.java \
- AltosState.java \
- AltosTelemetry.java \
- AltosTelemetryIterable.java \
- AltosUI.java \
- AltosWriter.java \
- AltosDataPointReader.java \
- AltosDataPoint.java \
- AltosGraph.java \
- AltosGraphTime.java \
- AltosGraphUI.java \
- AltosDataChooser.java \
- AltosVoice.java
-
-JFREECHART_CLASS= \
- jfreechart.jar
-
-JCOMMON_CLASS=\
- jcommon.jar
-
-FREETTS_CLASS= \
- cmudict04.jar \
- cmulex.jar \
- cmu_time_awb.jar \
- cmutimelex.jar \
- cmu_us_kal.jar \
- en_us.jar \
- freetts.jar
-
-LIBALTOS= \
- libaltos.so \
- libaltos.dylib \
- altos.dll
-
-JAR=altosui.jar
-
-FATJAR=altosui-fat.jar
-
-# Icons
-ICONDIR=$(top_srcdir)/icon
-
-JAVA_ICON=$(ICONDIR)/altus-metrum-16x16.jpg
-
-ICONS= $(ICONDIR)/redled.png $(ICONDIR)/redoff.png \
- $(ICONDIR)/greenled.png $(ICONDIR)/greenoff.png \
- $(ICONDIR)/grayled.png $(ICONDIR)/grayoff.png
-
-# icon base names for jar
-ICONJAR= -C $(ICONDIR) altus-metrum-16x16.jpg \
- -C $(ICONDIR) redled.png -C $(ICONDIR) redoff.png \
- -C $(ICONDIR) greenled.png -C $(ICONDIR) greenoff.png \
- -C $(ICONDIR) grayon.png -C $(ICONDIR) grayled.png
-
-WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico
-
-# Firmware
-FIRMWARE_TD=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx
-FIRMWARE_TM=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx
-FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TD)
-
-# Distribution targets
-LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2
-MACOSX_DIST=Altos-Mac-$(VERSION).zip
-WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe
-
-FAT_FILES=$(FATJAR) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
-
-LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE)
-LINUX_EXTRA=altosui-fat
-
-MACOSX_FILES=$(FAT_FILES) libaltos.dylib
-MACOSX_EXTRA=$(FIRMWARE)
-
-WINDOWS_FILES=$(FAT_FILES) altos.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
-
-all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb
-
-clean-local:
- -rm -rf classes $(JAR) $(FATJAR) \
- $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(FREETTS_CLASS) \
- $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \
- altosui altosui-test altosui-jdb macosx linux
-
-if FATINSTALL
-
-FATTARGET=$(FATDIR)/$(VERSION)
-
-LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
-MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
-WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
-
-fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
-
-$(LINUX_DIST_TARGET): $(LINUX_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
-
-$(MACOSX_DIST_TARGET): $(MACOSX_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
-
-$(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
- mkdir -p $(FATTARGET)
- cp -p $< $@
-
-else
-fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST)
-endif
-
-
-altosuidir=$(datadir)/java
-
-install-altosuiJAVA: altosui.jar
- @$(NORMAL_INSTALL)
- test -z "$(altosuidir)" || $(MKDIR_P) "$(DESTDIR)$(altosuidir)"
- echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(altosuidir)/altosui.jar'"; \
- $(INSTALL_DATA) "$<" "$(DESTDIR)$(altosuidir)"
-
-classes/altosui:
- mkdir -p classes/altosui
-
-$(JAR): classaltosui.stamp Manifest.txt $(JAVA_ICON)
- jar cfm $@ Manifest.txt \
- $(ICONJAR) \
- -C classes altosui \
- -C ../libaltos libaltosJNI
-
-$(FATJAR): classaltosui.stamp Manifest-fat.txt $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICON)
- jar cfm $@ Manifest-fat.txt \
- $(ICONJAR) \
- -C classes altosui \
- -C ../libaltos libaltosJNI
-
-Manifest.txt: Makefile
- echo 'Main-Class: altosui.AltosUI' > $@
- echo "Class-Path: $(FREETTS)/freetts.jar $(JFREECHART)/jfreechart.jar $(JCOMMON)/jcommon.jar" >> $@
-
-Manifest-fat.txt:
- echo 'Main-Class: altosui.AltosUI' > $@
- echo "Class-Path: freetts.jar jfreechart.jar jcommon.jar" >> $@
-
-altosui: Makefile
- echo "#!/bin/sh" > $@
- echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@
- chmod +x $@
-
-altosui-test: Makefile
- echo "#!/bin/sh" > $@
- echo 'exec java -cp "$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="../libaltos/.libs" -jar altosui.jar "$$@"' >> $@
- chmod +x $@
-
-altosui-jdb: Makefile
- echo "#!/bin/sh" > $@
- echo 'exec jdb -classpath "classes:../libaltos:$(FREETTS)/*:$(JFREECHART)/*:$(JCOMMON)/*" -Djava.library.path="../libaltos/.libs" altosui/AltosUI "$$@"' >> $@
- chmod +x $@
-
-libaltos.so:
- -rm -f "$@"
- $(LN_S) ../libaltos/.libs/"$@" .
-
-libaltos.dylib:
- -rm -f "$@"
- $(LN_S) ../libaltos/"$@" .
-
-altos.dll:
- -rm -f "$@"
- $(LN_S) ../libaltos/"$@" .
-
-$(FREETTS_CLASS):
- -rm -f "$@"
- $(LN_S) "$(FREETTS)"/"$@" .
-
-$(JFREECHART_CLASS):
- -rm -f "$@"
- $(LN_S) "$(JFREECHART)"/"$@" .
-
-$(JCOMMON_CLASS):
- -rm -f "$@"
- $(LN_S) "$(JCOMMON)"/"$@" .
-
-$(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
- -rm -f $@
- -rm -rf linux
- mkdir -p linux/AltOS
- cp -p $(LINUX_FILES) linux/AltOS
- cp -p altosui-fat linux/AltOS/altosui
- chmod +x linux/AltOS/altosui
- tar cjf $@ -C linux AltOS
-
-$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA)
- -rm -f $@
- -rm -rf macosx
- mkdir macosx
- cp -a AltosUI.app macosx/
- mkdir -p macosx/AltOS macosx/AltosUI.app/Contents/Resources/Java
- cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
- cp -p $(FREETTS_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
- cp -p $(JFREECHART_CLASS) libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
- cp -p $(MACOSX_EXTRA) macosx/AltOS
- cd macosx && zip -r ../$@ AltosUI.app AltOS
-
-$(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi
- -rm -f $@
- makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi
+++ /dev/null
-!addplugindir Instdrv/NSIS/Plugins
-
-Name "Altus Metrum Installer"
-
-; Default install directory
-InstallDir "$PROGRAMFILES\AltusMetrum"
-
-; Tell the installer where to re-install a new version
-InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir"
-
-LicenseText "GNU General Public License Version 2"
-LicenseData "../../COPYING"
-
-; Need admin privs for Vista or Win7
-RequestExecutionLevel admin
-
-ShowInstDetails Show
-
-ComponentText "Altus Metrum Software and Driver Installer"
-
-; Pages to present
-
-Page license
-Page components
-Page directory
-Page instfiles
-
-UninstPage uninstConfirm
-UninstPage instfiles
-
-; And the stuff to install
-
-Section "Install Driver" InstDriver
- InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum"
- Pop $0
- DetailPrint "InitDriverSetup: $0"
-
- InstDrv::DeleteOemInfFiles /NOUNLOAD
- InstDrv::CreateDevice /NOUNLOAD
- SetOutPath $TEMP
- File "../../telemetrum.inf"
- InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf"
-
- SetOutPath $INSTDIR
- File "../../telemetrum.inf"
-SectionEnd
-
-Section "AltosUI Application"
- SetOutPath $INSTDIR
-
- File "altosui-fat.jar"
- File "cmudict04.jar"
- File "cmulex.jar"
- File "cmu_time_awb.jar"
- File "cmutimelex.jar"
- File "cmu_us_kal.jar"
- File "en_us.jar"
- File "freetts.jar"
-
- File "*.dll"
-
- File "../../icon/*.ico"
-
- CreateShortCut "$SMPROGRAMS\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico"
-SectionEnd
-
-Section "AltosUI Desktop Shortcut"
- CreateShortCut "$DESKTOP\AltusMetrum.lnk" "$INSTDIR\altosui-fat.jar" "" "$INSTDIR\altus-metrum.ico"
-SectionEnd
-
-Section "TeleMetrum and TeleDongle Firmware"
-
- SetOutPath $INSTDIR
-
- File "../../src/telemetrum-v1.0/telemetrum-v1.0-${VERSION}.ihx"
- File "../../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
-
-SectionEnd
-
-Section "Uninstaller"
-
- ; Deal with the uninstaller
-
- SetOutPath $INSTDIR
-
- ; Write the install path to the registry
- WriteRegStr HKLM SOFTWARE\AltusMetrum "Install_Dir" "$INSTDIR"
-
- ; Write the uninstall keys for windows
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "DisplayName" "Altus Metrum"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "UninstallString" '"$INSTDIR\uninstall.exe"'
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoModify" "1"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoRepair" "1"
-
- WriteUninstaller "uninstall.exe"
-SectionEnd
-
-Section "Uninstall"
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum"
- DeleteRegKey HKLM "Software\AltusMetrum"
-
- Delete "$INSTDIR\*.*"
- RMDir "$INSTDIR"
-
- ; Remove devices
- InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} "Altus Metrum"
- InstDrv::DeleteOemInfFiles /NOUNLOAD
- InstDrv::RemoveAllDevices
-
- ; Remove shortcuts, if any
- Delete "$SMPROGRAMS\AltusMetrum.lnk"
- Delete "$DESKTOP\AltusMetrum.lnk"
-SectionEnd
+++ /dev/null
-#!/bin/sh
-me=`which "$0"`
-dir=`dirname "$me"`
-exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/altosui-fat.jar "$@"
+++ /dev/null
-.\"
-.\" Copyright © 2010 Bdale Garbee <bdale@gag.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; 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
-.\" 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.
-.\"
-.\"
-.TH ALTOSUI 1 "altosui" ""
-.SH NAME
-altosui \- Rocket flight monitor
-.SH SYNOPSIS
-.B "altosui"
-.SH DESCRIPTION
-.I altosui
-connects to a TeleDongle or TeleMetrum device through a USB serial device.
-It provides a menu-oriented
-user interface to monitor, record and review rocket flight data.
-.SH USAGE
-When connected to a TeleDongle device, altosui turns on the radio
-receiver and listens for telemetry packets. It displays the received
-telemetry data, and reports flight status via voice synthesis. All
-received telemetry information is recorded to a file.
-.P
-When connected to a TeleMetrum device, altosui can be used to configure the
-TeleMetrum, and to downloads the eeprom data and store it in a file.
-.P
-A number of other menu options exist, including the ability to export flight
-data in different formats.
-.SH FILES
-All data log files are recorded into a user-specified directory
-(default ~/TeleMetrum). Files are named using the current date, the serial
-number of the reporting device, the flight number recorded in the data
-and either '.telem' for telemetry data or '.eeprom' for eeprom data.
-.SH AUTHOR
-Keith Packard
+++ /dev/null
-*.so
-*.lo
-*.la
-*.java
-*.class
-.libs/
-classlibaltos.stamp
-libaltos_wrap.c
-libaltosJNI
-cjnitest
-libaltos.swig
-swig_bindings/
+++ /dev/null
-OS:=$(shell uname)
-
-#
-# Linux
-#
-ifeq ($(OS),Linux)
-
-JAVA_CFLAGS=-I/usr/lib/jvm/java-6-openjdk/include
-
-OS_LIB_CFLAGS=-DLINUX -DPOSIX_TTY $(JAVA_CFLAGS)
-
-OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
-
-OS_LDFLAGS=
-
-LIBNAME=libaltos.so
-EXEEXT=
-endif
-
-#
-# Darwin (Mac OS X)
-#
-ifeq ($(OS),Darwin)
-
-OS_LIB_CFLAGS=\
- -DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 \
- --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
-OS_APP_CFLAGS=$(OS_LIB_CFLAGS)
-
-OS_LDFLAGS =\
- -framework IOKit -framework CoreFoundation
-
-LIBNAME=libaltos.dylib
-EXEEXT=
-
-endif
-
-#
-# Windows
-#
-ifneq (,$(findstring MINGW,$(OS)))
-
-CC=gcc
-
-OS_LIB_CFLAGS = -DWINDOWS -mconsole -DBUILD_DLL
-OS_APP_CFLAGS = -DWINDOWS -mconsole
-
-OS_LDFLAGS = -lgdi32 -luser32 -lcfgmgr32 -lsetupapi -lole32 \
- -ladvapi32 -lcomctl32 -mconsole -Wl,--add-stdcall-alias
-
-LIBNAME=altos.dll
-
-EXEEXT=.exe
-
-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
-
-CJNITEST=cjnitest$(EXEEXT)
-
-all: $(LIBNAME) $(CJNITEST) $(CLASSFILES)
-
-.java.class:
- javac -encoding UTF8 -classpath "$(CLASSPATH)" $(JAVAFLAGS) $*.java
-
-CFLAGS=$(OS_LIB_CFLAGS) -O -I.
-
-LDFLAGS=$(OS_LDFLAGS)
-
-HEADERS=libaltos.h
-SRCS = libaltos.c $(SWIG_WRAP)
-OBJS = $(SRCS:%.c=%.o)
-LIBS = $(DARWIN_LIBS)
-
-$(CJNITEST): cjnitest.c $(LIBNAME)
- $(CC) -o $@ $(OS_APP_CFLAGS) cjnitest.c $(LIBNAME) $(LIBS) $(LDFLAGS)
-
-$(LIBNAME): $(OBJS)
- $(CC) -shared $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
-
-clean:
- rm -f $(CLASSFILES) $(OBJS) $(LIBNAME) $(CJNITEST) cjnitest.o
- rm -rf swig_bindings libaltosJNI
-
-distclean: clean
-
-$(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)
-
-ifeq ($(OS),Linux)
-install: $(LIBNAME)
- install -c $(LIBNAME) $(DESTDIR)/usr/lib/altos/$(LIBNAME)
-
-endif
-
-.NOTPARALLEL:
+++ /dev/null
-JAVAC=javac
-AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
-AM_JAVACFLAGS=-encoding UTF-8
-
-altoslibdir=$(libdir)/altos
-
-altoslib_LTLIBRARIES=libaltos.la
-
-libaltos_la_LDFLAGS = -version-info 1:0:1
-
-libaltos_la_SOURCES=\
- libaltos.c \
- libaltos_wrap.c
-
-noinst_PROGRAMS=cjnitest
-
-cjnitest_LDADD=libaltos.la
-
-LIBS=
-
-HFILES=libaltos.h
-
-SWIG_FILE=libaltos.swig
-
-CLASSDIR=libaltosJNI
-
-$(SWIG_FILE): libaltos.i0 $(HFILES)
- sed 's;//%;%;' libaltos.i0 $(HFILES) > $(SWIG_FILE)
-
-all-local: classlibaltos.stamp
-
-libaltos_wrap.c: classlibaltos.stamp
-
-classlibaltos.stamp: $(SWIG_FILE)
- swig -java -package libaltosJNI $(SWIG_FILE)
- mkdir -p libaltosJNI
- $(JAVAC) -d . $(AM_JAVACFLAGS) $(JAVACFLAGS) *.java && \
- touch classlibaltos.stamp
-
-clean-local:
- -rm -rf libaltosJNI *.class *.java classlibaltos.stamp $(SWIG_FILE) libaltos_wrap.c
+++ /dev/null
-#include <stdio.h>
-#include "libaltos.h"
-
-static void
-altos_puts(struct altos_file *file, char *string)
-{
- char c;
-
- while ((c = *string++))
- altos_putchar(file, c);
-}
-
-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;
-
- printf ("%04x:%04x %-20s %4d %s\n", device.vendor, device.product,
- device.name, device.serial, device.path);
-
- file = altos_open(&device);
- if (!file) {
- printf("altos_open failed\n");
- continue;
- }
- altos_puts(file,"v\nc s\n");
- altos_flush(file);
- while ((c = altos_getchar(file, 100)) >= 0) {
- putchar (c);
- }
- if (c != LIBALTOS_TIMEOUT)
- printf ("getchar returns %d\n", c);
- altos_close(file);
- }
- altos_list_finish(list);
- altos_fini();
-}
+++ /dev/null
-/*
- * 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>
-
-#define USE_POLL
-
-PUBLIC int
-altos_init(void)
-{
- return LIBALTOS_SUCCESS;
-}
-
-PUBLIC void
-altos_fini(void)
-{
-}
-
-#ifdef DARWIN
-
-#undef USE_POLL
-
-/* 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
-
-/*
- * Scan for Altus Metrum devices by looking through /sys
- */
-
-#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_name;
- 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_name = 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_name);
- /* 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;
-};
-
-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 (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) {
- 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->name, dev->product_name);
- device->vendor = dev->idVendor;
- device->product = dev->idProduct;
- 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;
-}
-
-static int
-get_number(io_object_t object, CFStringRef entry, int *result)
-{
- CFTypeRef entry_as_number;
- Boolean got_number;
-
- entry_as_number = IORegistryEntrySearchCFProperty (object,
- kIOServicePlane,
- entry,
- kCFAllocatorDefault,
- kIORegistryIterateRecursively);
- if (entry_as_number) {
- got_number = CFNumberGetValue(entry_as_number,
- kCFNumberIntType,
- result);
- if (got_number)
- return 1;
- }
- return 0;
-}
-
-struct altos_list *
-altos_list_start(void)
-{
- struct altos_list *list = calloc (sizeof (struct altos_list), 1);
- CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
- io_iterator_t tdIterator;
- io_object_t tdObject;
- kern_return_t ret;
- int i;
-
- ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
- if (ret != kIOReturnSuccess)
- return NULL;
- 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_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
- !get_number (object, CFSTR(kUSBProductID), &device->product))
- continue;
- if (device->vendor != 0xfffe)
- continue;
- if (device->product < 0x000a || 0x0013 < device->product)
- continue;
- if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
- get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
- 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;
-#ifdef USE_POLL
- int pipe[2];
-#else
- int out_fd;
-#endif
- unsigned char out_data[USB_BUF_SIZE];
- int out_used;
- unsigned char in_data[USB_BUF_SIZE];
- int in_used;
- int in_read;
-};
-
-PUBLIC 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;
- }
-#ifdef USE_POLL
- pipe(file->pipe);
-#else
- file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
- if (file->out_fd < 0) {
- perror(device->path);
- close(file->fd);
- free(file);
- return NULL;
- }
-#endif
- ret = tcgetattr(file->fd, &term);
- if (ret < 0) {
- perror("tcgetattr");
- close(file->fd);
-#ifndef USE_POLL
- close(file->out_fd);
-#endif
- free(file);
- return NULL;
- }
- cfmakeraw(&term);
-#ifdef USE_POLL
- term.c_cc[VMIN] = 1;
- term.c_cc[VTIME] = 0;
-#else
- term.c_cc[VMIN] = 0;
- term.c_cc[VTIME] = 1;
-#endif
- ret = tcsetattr(file->fd, TCSAFLUSH, &term);
- if (ret < 0) {
- perror("tcsetattr");
- close(file->fd);
-#ifndef USE_POLL
- close(file->out_fd);
-#endif
- free(file);
- return NULL;
- }
- return file;
-}
-
-PUBLIC void
-altos_close(struct altos_file *file)
-{
- if (file->fd != -1) {
- int fd = file->fd;
- file->fd = -1;
-#ifdef USE_POLL
- write(file->pipe[1], "\r", 1);
-#else
- close(file->out_fd);
- file->out_fd = -1;
-#endif
- close(fd);
- }
-}
-
-PUBLIC void
-altos_free(struct altos_file *file)
-{
- altos_close(file);
- free(file);
-}
-
-PUBLIC int
-altos_flush(struct altos_file *file)
-{
- if (file->out_used && 0) {
- printf ("flush \"");
- fwrite(file->out_data, 1, file->out_used, stdout);
- printf ("\"\n");
- }
- while (file->out_used) {
- int ret;
-
- if (file->fd < 0)
- return -EBADF;
-#ifdef USE_POLL
- ret = write (file->fd, file->out_data, file->out_used);
-#else
- ret = write (file->out_fd, file->out_data, file->out_used);
-#endif
- if (ret < 0)
- return -errno;
- if (ret) {
- memmove(file->out_data, file->out_data + ret,
- file->out_used - ret);
- file->out_used -= ret;
- }
- }
- return 0;
-}
-
-PUBLIC 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;
- ret = 0;
- if (file->out_used == USB_BUF_SIZE)
- ret = altos_flush(file);
- return 0;
-}
-
-#ifdef USE_POLL
-#include <poll.h>
-#endif
-
-static int
-altos_fill(struct altos_file *file, int timeout)
-{
- int ret;
-#ifdef USE_POLL
- struct pollfd fd[2];
-#endif
-
- if (timeout == 0)
- timeout = -1;
- while (file->in_read == file->in_used) {
- if (file->fd < 0)
- return LIBALTOS_ERROR;
-#ifdef USE_POLL
- fd[0].fd = file->fd;
- fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
- fd[1].fd = file->pipe[0];
- fd[1].events = POLLIN;
- ret = poll(fd, 2, timeout);
- if (ret < 0) {
- perror("altos_getchar");
- return LIBALTOS_ERROR;
- }
- if (ret == 0)
- return LIBALTOS_TIMEOUT;
-
- if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
- return LIBALTOS_ERROR;
- if (fd[0].revents & POLLIN)
-#endif
- {
- ret = read(file->fd, file->in_data, USB_BUF_SIZE);
- if (ret < 0) {
- perror("altos_getchar");
- return LIBALTOS_ERROR;
- }
- file->in_read = 0;
- file->in_used = ret;
-#ifndef USE_POLL
- if (ret == 0 && timeout > 0)
- return LIBALTOS_TIMEOUT;
-#endif
- }
- }
- if (file->in_used && 0) {
- printf ("fill \"");
- fwrite(file->in_data, 1, file->in_used, stdout);
- printf ("\"\n");
- }
- return 0;
-}
-
-PUBLIC int
-altos_getchar(struct altos_file *file, int timeout)
-{
- int ret;
- while (file->in_read == file->in_used) {
- if (file->fd < 0)
- return LIBALTOS_ERROR;
- ret = altos_fill(file, timeout);
- if (ret)
- return ret;
- }
- return file->in_data[file->in_read++];
-}
-
-#endif /* POSIX_TTY */
-
-#ifdef WINDOWS
-
-#include <stdlib.h>
-#include <windows.h>
-#include <setupapi.h>
-
-struct altos_list {
- HDEVINFO dev_info;
- int index;
-};
-
-#define USB_BUF_SIZE 64
-
-struct altos_file {
- HANDLE handle;
- unsigned char out_data[USB_BUF_SIZE];
- int out_used;
- unsigned char in_data[USB_BUF_SIZE];
- int in_used;
- int in_read;
- OVERLAPPED ov_read;
- BOOL pend_read;
- OVERLAPPED ov_write;
-};
-
-PUBLIC struct altos_list *
-altos_list_start(void)
-{
- struct altos_list *list = calloc(1, sizeof (struct altos_list));
-
- if (!list)
- return NULL;
- list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
- DIGCF_ALLCLASSES|DIGCF_PRESENT);
- if (list->dev_info == INVALID_HANDLE_VALUE) {
- printf("SetupDiGetClassDevs failed %d\n", GetLastError());
- free(list);
- return NULL;
- }
- list->index = 0;
- return list;
-}
-
-PUBLIC int
-altos_list_next(struct altos_list *list, struct altos_device *device)
-{
- SP_DEVINFO_DATA dev_info_data;
- char port[128];
- DWORD port_len;
- char friendlyname[256];
- char symbolic[256];
- DWORD symbolic_len;
- HKEY dev_key;
- int vid, pid;
- int serial;
- HRESULT result;
- DWORD friendlyname_type;
- DWORD friendlyname_len;
-
- dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
- while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
- &dev_info_data))
- {
- list->index++;
-
- dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
- DICS_FLAG_GLOBAL, 0, DIREG_DEV,
- KEY_READ);
- if (dev_key == INVALID_HANDLE_VALUE) {
- printf("cannot open device registry key\n");
- continue;
- }
-
- /* Fetch symbolic name for this device and parse out
- * the vid/pid/serial info */
- symbolic_len = sizeof(symbolic);
- result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
- symbolic, &symbolic_len);
- if (result != 0) {
- printf("cannot find SymbolicName value\n");
- RegCloseKey(dev_key);
- continue;
- }
- vid = pid = serial = 0;
- sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1,
- "%04X", &vid);
- sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
- "%04X", &pid);
- sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
- "%d", &serial);
- if (!USB_IS_ALTUSMETRUM(vid, pid)) {
- RegCloseKey(dev_key);
- continue;
- }
-
- /* Fetch the com port name */
- port_len = sizeof (port);
- result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
- port, &port_len);
- RegCloseKey(dev_key);
- if (result != 0) {
- printf("failed to get PortName\n");
- continue;
- }
-
- /* Fetch the device description which is the device name,
- * with firmware that has unique USB ids */
- friendlyname_len = sizeof (friendlyname);
- if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
- &dev_info_data,
- SPDRP_FRIENDLYNAME,
- &friendlyname_type,
- (BYTE *)friendlyname,
- sizeof(friendlyname),
- &friendlyname_len))
- {
- printf("Failed to get friendlyname\n");
- continue;
- }
- device->vendor = vid;
- device->product = pid;
- device->serial = serial;
- strcpy(device->name, friendlyname);
-
- strcpy(device->path, port);
- return 1;
- }
- result = GetLastError();
- if (result != ERROR_NO_MORE_ITEMS)
- printf ("SetupDiEnumDeviceInfo failed error %d\n", result);
- return 0;
-}
-
-PUBLIC void
-altos_list_finish(struct altos_list *list)
-{
- SetupDiDestroyDeviceInfoList(list->dev_info);
- free(list);
-}
-
-static int
-altos_queue_read(struct altos_file *file)
-{
- DWORD got;
- if (file->pend_read)
- return LIBALTOS_SUCCESS;
-
- if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
- if (GetLastError() != ERROR_IO_PENDING)
- return LIBALTOS_ERROR;
- file->pend_read = TRUE;
- } else {
- file->pend_read = FALSE;
- file->in_read = 0;
- file->in_used = got;
- }
- return LIBALTOS_SUCCESS;
-}
-
-static int
-altos_wait_read(struct altos_file *file, int timeout)
-{
- DWORD ret;
- DWORD got;
-
- if (!file->pend_read)
- return LIBALTOS_SUCCESS;
-
- if (!timeout)
- timeout = INFINITE;
-
- ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
- switch (ret) {
- case WAIT_OBJECT_0:
- if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE))
- return LIBALTOS_ERROR;
- file->pend_read = FALSE;
- file->in_read = 0;
- file->in_used = got;
- break;
- case WAIT_TIMEOUT:
- return LIBALTOS_TIMEOUT;
- break;
- default:
- return LIBALTOS_ERROR;
- }
- return LIBALTOS_SUCCESS;
-}
-
-static int
-altos_fill(struct altos_file *file, int timeout)
-{
- int ret;
-
- if (file->in_read < file->in_used)
- return LIBALTOS_SUCCESS;
-
- file->in_read = file->in_used = 0;
-
- ret = altos_queue_read(file);
- if (ret)
- return ret;
- ret = altos_wait_read(file, timeout);
- if (ret)
- return ret;
-
- return LIBALTOS_SUCCESS;
-}
-
-PUBLIC int
-altos_flush(struct altos_file *file)
-{
- DWORD put;
- char *data = file->out_data;
- char used = file->out_used;
- DWORD ret;
-
- while (used) {
- if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
- if (GetLastError() != ERROR_IO_PENDING)
- return LIBALTOS_ERROR;
- ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
- switch (ret) {
- case WAIT_OBJECT_0:
- if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE))
- return LIBALTOS_ERROR;
- break;
- default:
- return LIBALTOS_ERROR;
- }
- }
- data += put;
- used -= put;
- }
- file->out_used = 0;
- return LIBALTOS_SUCCESS;
-}
-
-PUBLIC struct altos_file *
-altos_open(struct altos_device *device)
-{
- struct altos_file *file = calloc (1, sizeof (struct altos_file));
- char full_name[64];
- DCB dcbSerialParams = {0};
- COMMTIMEOUTS timeouts;
-
- if (!file)
- return NULL;
-
- strcpy(full_name, "\\\\.\\");
- strcat(full_name, device->path);
- file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
- if (file->handle == INVALID_HANDLE_VALUE) {
- free(file);
- return NULL;
- }
- file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- timeouts.ReadIntervalTimeout = MAXDWORD;
- timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
- timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
- timeouts.WriteTotalTimeoutMultiplier = 0;
- timeouts.WriteTotalTimeoutConstant = 0;
- SetCommTimeouts(file->handle, &timeouts);
-
- dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
- if (!GetCommState(file->handle, &dcbSerialParams)) {
- CloseHandle(file->handle);
- free(file);
- return NULL;
- }
- dcbSerialParams.BaudRate = CBR_9600;
- dcbSerialParams.ByteSize = 8;
- dcbSerialParams.StopBits = ONESTOPBIT;
- dcbSerialParams.Parity = NOPARITY;
- if (!SetCommState(file->handle, &dcbSerialParams)) {
- CloseHandle(file->handle);
- free(file);
- return NULL;
- }
-
- return file;
-}
-
-PUBLIC void
-altos_close(struct altos_file *file)
-{
- if (file->handle != INVALID_HANDLE_VALUE) {
- CloseHandle(file->handle);
- file->handle = INVALID_HANDLE_VALUE;
- }
-}
-
-PUBLIC void
-altos_free(struct altos_file *file)
-{
- altos_close(file);
- 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 LIBALTOS_SUCCESS;
-}
-
-int
-altos_getchar(struct altos_file *file, int timeout)
-{
- int ret;
- while (file->in_read == file->in_used) {
- if (file->handle == INVALID_HANDLE_VALUE)
- return LIBALTOS_ERROR;
- ret = altos_fill(file, timeout);
- if (ret)
- return ret;
- }
- return file->in_data[file->in_read++];
-}
-
-#endif
+++ /dev/null
-/*
- * 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_
-
-#include <stdlib.h>
-
-#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
-# ifndef BUILD_STATIC
-# ifdef BUILD_DLL
-# define PUBLIC __declspec(dllexport)
-# else
-# define PUBLIC __declspec(dllimport)
-# endif
-# endif /* BUILD_STATIC */
-#endif
-
-#ifndef PUBLIC
-# define PUBLIC
-#endif
-
-#define USB_VENDOR_FSF 0xfffe
-#define USB_VENDOR_ALTUSMETRUM USB_VENDOR_FSF
-#define USB_PRODUCT_ALTUSMETRUM 0x000a
-#define USB_PRODUCT_TELEMETRUM 0x000b
-#define USB_PRODUCT_TELEDONGLE 0x000c
-#define USB_PRODUCT_TELETERRA 0x000d
-#define USB_PRODUCT_ALTUSMETRUM_MIN 0x000a
-#define USB_PRODUCT_ALTUSMETRUM_MAX 0x0013
-
-#define USB_IS_ALTUSMETRUM(v,p) ((v) == USB_VENDOR_ALTUSMETRUM && \
- (USB_PRODUCT_ALTUSMETRUM_MIN <= (p) && \
- (p) <= USB_PRODUCT_ALTUSMETRUM_MAX))
-
-struct altos_device {
- //%immutable;
- int vendor;
- int product;
- int serial;
- char name[256];
- char path[256];
- //%mutable;
-};
-
-#define LIBALTOS_SUCCESS 0
-#define LIBALTOS_ERROR -1
-#define LIBALTOS_TIMEOUT -2
-
-/* Returns 0 for success, < 0 on error */
-PUBLIC int
-altos_init(void);
-
-PUBLIC void
-altos_fini(void);
-
-PUBLIC struct altos_list *
-altos_list_start(void);
-
-/* Returns 1 for success, zero on end of list */
-PUBLIC int
-altos_list_next(struct altos_list *list, struct altos_device *device);
-
-PUBLIC void
-altos_list_finish(struct altos_list *list);
-
-PUBLIC struct altos_file *
-altos_open(struct altos_device *device);
-
-PUBLIC void
-altos_close(struct altos_file *file);
-
-PUBLIC void
-altos_free(struct altos_file *file);
-
-/* Returns < 0 for error */
-PUBLIC int
-altos_putchar(struct altos_file *file, char c);
-
-/* Returns < 0 for error */
-PUBLIC int
-altos_flush(struct altos_file *file);
-
-/* Returns < 0 for error or timeout. timeout of 0 == wait forever */
-PUBLIC int
-altos_getchar(struct altos_file *file, int timeout);
-
-#endif /* _LIBALTOS_H_ */
+++ /dev/null
-%module libaltos
-%{
-#include "libaltos.h"
-%}
-
AC_OUTPUT([
Makefile
+altosui/Makefile
+altosui/libaltos/Makefile
ao-tools/Makefile
ao-tools/lib/Makefile
ao-tools/ao-rawload/Makefile
ao-tools/ao-load/Makefile
ao-tools/ao-postflight/Makefile
ao-tools/ao-view/Makefile
-ao-tools/libaltos/Makefile
-ao-tools/altosui/Makefile
ao-utils/Makefile
src/Version
])